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

+ Total amount of new orders this month

+ Average amount of t-shirt by order this month

+ Number of cancelled orders this month

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

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

Number of cancelled orders this month

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

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

- Total amount of new orders this month

- Average amount of t-shirt by order this month

- Number of cancelled orders this month

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

- + +

+ + +

+ + +

+ + +

+ + +

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

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

- - -

- - -

- - -

- - -

- - - - +
+ +

+ + +

+ + +

+ + +

+ + +

+ + + + +

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

- - -

- - -

- - -

- - -

- - - - + + + + + +

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

+

+
+ +
diff --git a/awesome_dashboard/static/src/pie-chart/pie-chart-card.js b/awesome_dashboard/static/src/pie-chart/pie-chart-card.js new file mode 100644 index 00000000000..4e2e767c05d --- /dev/null +++ b/awesome_dashboard/static/src/pie-chart/pie-chart-card.js @@ -0,0 +1,11 @@ +import { Component } from "@odoo/owl"; +import { PieChart } from "./pie-chart"; + +export class PieChartCard extends Component { + static template = "awesome_dashboard.pie-chart-card"; + static props = { + title: String, + value: { type: Object, values: Number }, + }; + static components = { PieChart }; +} diff --git a/awesome_dashboard/static/src/pie-chart/pie-chart-card.xml b/awesome_dashboard/static/src/pie-chart/pie-chart-card.xml new file mode 100644 index 00000000000..eff186e06bd --- /dev/null +++ b/awesome_dashboard/static/src/pie-chart/pie-chart-card.xml @@ -0,0 +1,12 @@ + + + + +
+
+
+ +
+
+ +
From e5ec513249e4def19634b4abb4f178c8a296c99b Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Tue, 23 Dec 2025 08:45:26 +0100 Subject: [PATCH 12/16] [IMP] awesome_dashboard: make dashboard extensible with a registry --- .../static/src/dashboard-registry.js | 64 +++++++++++++++++++ awesome_dashboard/static/src/dashboard.js | 58 +---------------- 2 files changed, 65 insertions(+), 57 deletions(-) create mode 100644 awesome_dashboard/static/src/dashboard-registry.js diff --git a/awesome_dashboard/static/src/dashboard-registry.js b/awesome_dashboard/static/src/dashboard-registry.js new file mode 100644 index 00000000000..0e16da86dc1 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard-registry.js @@ -0,0 +1,64 @@ +import { registry } from "@web/core/registry"; +import { NumberCard } from "./number-card/number-card"; +import { PieChartCard } from "./pie-chart/pie-chart-card"; + +registry.category("awesome_dashboard").add("nb_new_orders", { + 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, + }), +}); + +registry.category("awesome_dashboard").add("total_amount", { + 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, + }), +}); + +registry.category("awesome_dashboard").add("average_quantity", { + 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, + }), +}); + +registry.category("awesome_dashboard").add("nb_cancelled_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, + }), +}); + +registry.category("awesome_dashboard").add("average_time", { + 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, + }), +}); + +registry.category("awesome_dashboard").add("orders_by_size", { + id: "orders_by_size", + description: "Ordered T-shirts by size", + component: PieChartCard, + size: 2, + props: (data) => ({ + title: "Ordered T-shirts by size", + value: data.orders_by_size, + }), +}); diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 91a99d78eb8..e2b88faf1a3 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -15,63 +15,7 @@ class AwesomeDashboard extends Component { this.statistics = useState(useService("awesome_dashboard.statistics")); // Dashboard items - this.items = [ - { - id: "nb_new_orders", - description: "Number of new orders this month", - component: NumberCard, - props: (data) => ({ - title: "Number of new orders this month", - value: data.nb_new_orders, - }), - }, - { - id: "total_amount", - description: "Total amount of new orders this month", - component: NumberCard, - props: (data) => ({ - title: "Total amount of new orders this month", - value: data.total_amount, - }), - }, - { - id: "average_quantity", - description: "Average amount of t-shirt by order this month", - component: NumberCard, - props: (data) => ({ - title: "Average amount of t-shirt by order this month", - value: data.average_quantity, - }), - }, - { - id: "nb_cancelled_orders", - description: "Number of cancelled orders this month", - component: NumberCard, - props: (data) => ({ - title: "Number of cancelled orders this month", - value: data.nb_cancelled_orders, - }), - }, - { - id: "average_time", - description: "Average time for an order to go from 'new' to 'sent' or 'cancelled'", - component: NumberCard, - props: (data) => ({ - title: "Average time for an order to go from 'new' to 'sent' or 'cancelled'", - value: data.average_time, - }), - }, - { - id: "orders_by_size", - description: "Ordered T-shirts by size", - component: PieChartCard, - size: 2, - props: (data) => ({ - title: "Ordered T-shirts by size", - value: data.orders_by_size, - }), - }, - ]; + this.items = registry.category("awesome_dashboard").getAll(); } actionCustomers() { From ffa53f561c78c7d2a8efe6f8eaf24cf7881bc7b8 Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Tue, 23 Dec 2025 13:48:08 +0100 Subject: [PATCH 13/16] [IMP] awesome_dashboard: add dialog to enable or disable Dashboard items --- .../configuration-dialog.js | 32 +++++++++++++++++++ .../configuration-dialog.xml | 24 ++++++++++++++ awesome_dashboard/static/src/dashboard.js | 25 ++++++++++++--- awesome_dashboard/static/src/dashboard.xml | 5 ++- 4 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 awesome_dashboard/static/src/configuration-dialog/configuration-dialog.js create mode 100644 awesome_dashboard/static/src/configuration-dialog/configuration-dialog.xml diff --git a/awesome_dashboard/static/src/configuration-dialog/configuration-dialog.js b/awesome_dashboard/static/src/configuration-dialog/configuration-dialog.js new file mode 100644 index 00000000000..7ca7e1a1fe8 --- /dev/null +++ b/awesome_dashboard/static/src/configuration-dialog/configuration-dialog.js @@ -0,0 +1,32 @@ +import { Dialog } from "@web/core/dialog/dialog"; +import { Component } from "@odoo/owl"; + +export class DashboardDialog extends Component { + static template = "awesome_dashboard.configuration-dialog"; + static props = { + items: { type: Array, element: Object }, + disabledItems: { type: Array, element: String }, + updateConfiguration: Function, + close: { type: Function, optional: true }, + }; + static components = { Dialog }; + + setup() { + this.items = this.props.items.map((item) => ({ + ...item, + disabled: this.props.disabledItems.includes(item.id), + })); + } + + toggleMasked(item) { + item.disabled = !item.disabled; + } + + applyConfigurationChanges() { + const disabledItems = this.items.filter((item) => item.disabled).map((item) => item.id); + this.props.updateConfiguration(disabledItems); + if(this.props.close) { + this.props.close(); + } + } +} diff --git a/awesome_dashboard/static/src/configuration-dialog/configuration-dialog.xml b/awesome_dashboard/static/src/configuration-dialog/configuration-dialog.xml new file mode 100644 index 00000000000..f47809daa5f --- /dev/null +++ b/awesome_dashboard/static/src/configuration-dialog/configuration-dialog.xml @@ -0,0 +1,24 @@ + + + + + + +

Which cards do you wish to see ?

+ +
+ + +
+
+
+ + + + +
+
+ +
diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index e2b88faf1a3..16f5fcb7039 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -1,10 +1,12 @@ import { registry } from "@web/core/registry"; -import { useService } from "@web/core/utils/hooks"; +import { useService, useOwnedDialogs } from "@web/core/utils/hooks"; import { Layout } from "@web/search/layout"; import { Component, useState } from "@odoo/owl"; -import { DashboardItem } from "./dashboard-item/dashboard-item" -import { NumberCard } from "./number-card/number-card" -import { PieChartCard } from "./pie-chart/pie-chart-card" +import { DashboardItem } from "./dashboard-item/dashboard-item"; +import { NumberCard } from "./number-card/number-card"; +import { PieChartCard } from "./pie-chart/pie-chart-card"; +import { DashboardDialog } from "./configuration-dialog/configuration-dialog"; +import { browser } from "@web/core/browser/browser"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; @@ -13,9 +15,11 @@ class AwesomeDashboard extends Component { setup() { this.action = useService("action"); this.statistics = useState(useService("awesome_dashboard.statistics")); + this.configDialog = useOwnedDialogs(); // Dashboard items this.items = registry.category("awesome_dashboard").getAll(); + this.state = useState({ disabledItems: JSON.parse(browser.localStorage.getItem("awesome_dashboard.disabled") ?? "[]") }); } actionCustomers() { @@ -30,6 +34,19 @@ class AwesomeDashboard extends Component { views: [[false, "list"], [false, "form"]], }); } + + updateConfiguration(disabledItems) { + browser.localStorage.setItem("awesome_dashboard.disabled", JSON.stringify(disabledItems)); + this.state.disabledItems = disabledItems; + } + + openDashboardConfig() { + this.configDialog(DashboardDialog, { + items: this.items, + disabledItems: this.state.disabledItems, + updateConfiguration: this.updateConfiguration.bind(this), + }); + } } registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 8f60c06385a..5b6c1cd099c 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -7,10 +7,13 @@ + + +
- + From be53dc712af6910eec7d24614478eb955b5766e3 Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Tue, 23 Dec 2025 14:12:51 +0100 Subject: [PATCH 14/16] [IMP] awesome_dashboard: lazyload the dashboard --- awesome_dashboard/__manifest__.py | 4 ++++ .../configuration-dialog/configuration-dialog.js | 0 .../configuration-dialog/configuration-dialog.xml | 0 .../{ => dashboard}/dashboard-item/dashboard-item.js | 0 .../dashboard-item/dashboard-item.xml | 0 .../static/src/{ => dashboard}/dashboard-registry.js | 0 .../static/src/{ => dashboard}/dashboard.js | 2 +- .../static/src/{ => dashboard}/dashboard.scss | 0 .../static/src/{ => dashboard}/dashboard.xml | 0 .../src/{ => dashboard}/number-card/number-card.js | 0 .../src/{ => dashboard}/number-card/number-card.scss | 0 .../src/{ => dashboard}/number-card/number-card.xml | 0 .../src/{ => dashboard}/pie-chart/pie-chart-card.js | 0 .../src/{ => dashboard}/pie-chart/pie-chart-card.xml | 0 .../src/{ => dashboard}/pie-chart/pie-chart.js | 0 .../src/{ => dashboard}/pie-chart/pie-chart.xml | 0 .../static/src/{ => dashboard}/statistics-service.js | 0 awesome_dashboard/static/src/dashboard_action.js | 12 ++++++++++++ 18 files changed, 17 insertions(+), 1 deletion(-) rename awesome_dashboard/static/src/{ => dashboard}/configuration-dialog/configuration-dialog.js (100%) rename awesome_dashboard/static/src/{ => dashboard}/configuration-dialog/configuration-dialog.xml (100%) 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}/dashboard-registry.js (100%) rename awesome_dashboard/static/src/{ => dashboard}/dashboard.js (95%) rename awesome_dashboard/static/src/{ => dashboard}/dashboard.scss (100%) rename awesome_dashboard/static/src/{ => dashboard}/dashboard.xml (100%) rename awesome_dashboard/static/src/{ => dashboard}/number-card/number-card.js (100%) rename awesome_dashboard/static/src/{ => dashboard}/number-card/number-card.scss (100%) rename awesome_dashboard/static/src/{ => dashboard}/number-card/number-card.xml (100%) rename awesome_dashboard/static/src/{ => dashboard}/pie-chart/pie-chart-card.js (100%) rename awesome_dashboard/static/src/{ => dashboard}/pie-chart/pie-chart-card.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%) rename awesome_dashboard/static/src/{ => dashboard}/statistics-service.js (100%) create mode 100644 awesome_dashboard/static/src/dashboard_action.js diff --git a/awesome_dashboard/__manifest__.py b/awesome_dashboard/__manifest__.py index a1cd72893d7..bd10cc6fc0c 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/configuration-dialog/configuration-dialog.js b/awesome_dashboard/static/src/dashboard/configuration-dialog/configuration-dialog.js similarity index 100% rename from awesome_dashboard/static/src/configuration-dialog/configuration-dialog.js rename to awesome_dashboard/static/src/dashboard/configuration-dialog/configuration-dialog.js diff --git a/awesome_dashboard/static/src/configuration-dialog/configuration-dialog.xml b/awesome_dashboard/static/src/dashboard/configuration-dialog/configuration-dialog.xml similarity index 100% rename from awesome_dashboard/static/src/configuration-dialog/configuration-dialog.xml rename to awesome_dashboard/static/src/dashboard/configuration-dialog/configuration-dialog.xml 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/dashboard-registry.js b/awesome_dashboard/static/src/dashboard/dashboard-registry.js similarity index 100% rename from awesome_dashboard/static/src/dashboard-registry.js rename to awesome_dashboard/static/src/dashboard/dashboard-registry.js diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard/dashboard.js similarity index 95% rename from awesome_dashboard/static/src/dashboard.js rename to awesome_dashboard/static/src/dashboard/dashboard.js index 16f5fcb7039..765185149ee 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard/dashboard.js @@ -49,4 +49,4 @@ class AwesomeDashboard extends Component { } } -registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard); +registry.category("lazy_components").add("awesome_dashboard.dashboard", 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 100% rename from awesome_dashboard/static/src/dashboard.xml rename to awesome_dashboard/static/src/dashboard/dashboard.xml diff --git a/awesome_dashboard/static/src/number-card/number-card.js b/awesome_dashboard/static/src/dashboard/number-card/number-card.js similarity index 100% rename from awesome_dashboard/static/src/number-card/number-card.js rename to awesome_dashboard/static/src/dashboard/number-card/number-card.js diff --git a/awesome_dashboard/static/src/number-card/number-card.scss b/awesome_dashboard/static/src/dashboard/number-card/number-card.scss similarity index 100% rename from awesome_dashboard/static/src/number-card/number-card.scss rename to awesome_dashboard/static/src/dashboard/number-card/number-card.scss diff --git a/awesome_dashboard/static/src/number-card/number-card.xml b/awesome_dashboard/static/src/dashboard/number-card/number-card.xml similarity index 100% rename from awesome_dashboard/static/src/number-card/number-card.xml rename to awesome_dashboard/static/src/dashboard/number-card/number-card.xml diff --git a/awesome_dashboard/static/src/pie-chart/pie-chart-card.js b/awesome_dashboard/static/src/dashboard/pie-chart/pie-chart-card.js similarity index 100% rename from awesome_dashboard/static/src/pie-chart/pie-chart-card.js rename to awesome_dashboard/static/src/dashboard/pie-chart/pie-chart-card.js diff --git a/awesome_dashboard/static/src/pie-chart/pie-chart-card.xml b/awesome_dashboard/static/src/dashboard/pie-chart/pie-chart-card.xml similarity index 100% rename from awesome_dashboard/static/src/pie-chart/pie-chart-card.xml rename to awesome_dashboard/static/src/dashboard/pie-chart/pie-chart-card.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/statistics-service.js b/awesome_dashboard/static/src/dashboard/statistics-service.js similarity index 100% rename from awesome_dashboard/static/src/statistics-service.js rename to awesome_dashboard/static/src/dashboard/statistics-service.js diff --git a/awesome_dashboard/static/src/dashboard_action.js b/awesome_dashboard/static/src/dashboard_action.js new file mode 100644 index 00000000000..15855537dbb --- /dev/null +++ b/awesome_dashboard/static/src/dashboard_action.js @@ -0,0 +1,12 @@ +import { Component, xml } from "@odoo/owl"; +import { LazyComponent } from "@web/core/assets"; +import { registry } from "@web/core/registry"; + +export class LazyDashboard extends Component { + static components = { LazyComponent }; + static template = xml` + + `; +} + +registry.category("actions").add("awesome_dashboard.dashboard", LazyDashboard); From cc9b78fc3e751a197ea116eff4833bb576bd171e Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Tue, 23 Dec 2025 16:25:50 +0100 Subject: [PATCH 15/16] [LINT] awesome_dashboard: fix linter issues --- .../configuration-dialog/configuration-dialog.js | 2 +- awesome_dashboard/static/src/dashboard/dashboard.js | 11 +++++++++-- .../static/src/dashboard/pie-chart/pie-chart.js | 13 ++++++++++--- .../static/src/dashboard/statistics-service.js | 8 +++++--- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard/configuration-dialog/configuration-dialog.js b/awesome_dashboard/static/src/dashboard/configuration-dialog/configuration-dialog.js index 7ca7e1a1fe8..2333b87db24 100644 --- a/awesome_dashboard/static/src/dashboard/configuration-dialog/configuration-dialog.js +++ b/awesome_dashboard/static/src/dashboard/configuration-dialog/configuration-dialog.js @@ -25,7 +25,7 @@ export class DashboardDialog extends Component { applyConfigurationChanges() { const disabledItems = this.items.filter((item) => item.disabled).map((item) => item.id); this.props.updateConfiguration(disabledItems); - if(this.props.close) { + if (this.props.close) { this.props.close(); } } diff --git a/awesome_dashboard/static/src/dashboard/dashboard.js b/awesome_dashboard/static/src/dashboard/dashboard.js index 765185149ee..44b06e45cfb 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.js +++ b/awesome_dashboard/static/src/dashboard/dashboard.js @@ -19,7 +19,11 @@ class AwesomeDashboard extends Component { // Dashboard items this.items = registry.category("awesome_dashboard").getAll(); - this.state = useState({ disabledItems: JSON.parse(browser.localStorage.getItem("awesome_dashboard.disabled") ?? "[]") }); + this.state = useState({ + disabledItems: JSON.parse( + browser.localStorage.getItem("awesome_dashboard.disabled") ?? "[]" + ), + }); } actionCustomers() { @@ -31,7 +35,10 @@ class AwesomeDashboard extends Component { type: "ir.actions.act_window", name: "All leads", res_model: "crm.lead", - views: [[false, "list"], [false, "form"]], + views: [ + [false, "list"], + [false, "form"], + ], }); } 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 46bc6ba3dfd..b760cabb3f3 100644 --- a/awesome_dashboard/static/src/dashboard/pie-chart/pie-chart.js +++ b/awesome_dashboard/static/src/dashboard/pie-chart/pie-chart.js @@ -1,4 +1,11 @@ -import { Component, onWillStart, onWillUnmount, onMounted, useRef, onWillUpdateProps } from "@odoo/owl"; +import { + Component, + onWillStart, + onWillUnmount, + onMounted, + useRef, + onWillUpdateProps, +} from "@odoo/owl"; import { loadJS } from "@web/core/assets"; import { DashboardItem } from "../dashboard-item/dashboard-item"; @@ -7,7 +14,7 @@ export class PieChart extends Component { static components = { DashboardItem }; static props = { data: { type: Object, values: Number }, - } + }; setup() { this.canvasRef = useRef("canvas"); @@ -40,7 +47,7 @@ export class PieChart extends Component { this.chart.update(); } } - + destroyChart() { if (this.chart) { this.chart.destroy(); diff --git a/awesome_dashboard/static/src/dashboard/statistics-service.js b/awesome_dashboard/static/src/dashboard/statistics-service.js index 0c97dc57973..6bfffc593a5 100644 --- a/awesome_dashboard/static/src/dashboard/statistics-service.js +++ b/awesome_dashboard/static/src/dashboard/statistics-service.js @@ -4,16 +4,18 @@ import { reactive } from "@odoo/owl"; export const statisticsService = { start() { - let statistics = reactive({ isReady: false }); + const statistics = reactive({ isReady: false }); async function loadStatistics() { - Object.assign(statistics, await rpc("/awesome_dashboard/statistics"), { isReady: true }); + Object.assign(statistics, await rpc("/awesome_dashboard/statistics"), { + isReady: true, + }); } // Refresh every 10 seconds for testing //const interval = 10000; // Refresh every 10 minutes for real const interval = 600000; - + setInterval(loadStatistics, interval); loadStatistics(); return statistics; From 6eb658a0c509b3a91ce136d3bf4e2bc9dc4547fe Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Wed, 24 Dec 2025 11:46:05 +0100 Subject: [PATCH 16/16] [CLN] awesome_dashboard: improve the way dashboard items are added to the registry --- .../src/dashboard/dashboard-registry.js | 117 +++++++++--------- 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard/dashboard-registry.js b/awesome_dashboard/static/src/dashboard/dashboard-registry.js index 0e16da86dc1..ebd59593590 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard-registry.js +++ b/awesome_dashboard/static/src/dashboard/dashboard-registry.js @@ -2,63 +2,62 @@ import { registry } from "@web/core/registry"; import { NumberCard } from "./number-card/number-card"; import { PieChartCard } from "./pie-chart/pie-chart-card"; -registry.category("awesome_dashboard").add("nb_new_orders", { - 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, - }), -}); +const registryItems = [ + { + id: "nb_new_orders", + description: "Number of new orders this month", + component: NumberCard, + props: (data) => ({ + title: "Number of new orders this month", + value: data.nb_new_orders, + }), + }, + { + id: "total_amount", + description: "Total amount of new orders this month", + component: NumberCard, + props: (data) => ({ + title: "Total amount of new orders this month", + value: data.total_amount, + }), + }, + { + id: "average_quantity", + description: "Average amount of t-shirt by order this month", + component: NumberCard, + props: (data) => ({ + title: "Average amount of t-shirt by order this month", + value: data.average_quantity, + }), + }, + { + id: "nb_cancelled_orders", + description: "Number of cancelled orders this month", + component: NumberCard, + props: (data) => ({ + title: "Number of cancelled orders this month", + value: data.nb_cancelled_orders, + }), + }, + { + id: "average_time", + description: "Average time for an order to go from 'new' to 'sent' or 'cancelled'", + component: NumberCard, + props: (data) => ({ + title: "Average time for an order to go from 'new' to 'sent' or 'cancelled'", + value: data.average_time, + }), + }, + { + id: "orders_by_size", + description: "Ordered T-shirts by size", + component: PieChartCard, + size: 2, + props: (data) => ({ + title: "Ordered T-shirts by size", + value: data.orders_by_size, + }), + }, +]; -registry.category("awesome_dashboard").add("total_amount", { - 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, - }), -}); - -registry.category("awesome_dashboard").add("average_quantity", { - 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, - }), -}); - -registry.category("awesome_dashboard").add("nb_cancelled_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, - }), -}); - -registry.category("awesome_dashboard").add("average_time", { - 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, - }), -}); - -registry.category("awesome_dashboard").add("orders_by_size", { - id: "orders_by_size", - description: "Ordered T-shirts by size", - component: PieChartCard, - size: 2, - props: (data) => ({ - title: "Ordered T-shirts by size", - value: data.orders_by_size, - }), -}); +registryItems.forEach((item) => registry.category("awesome_dashboard").add(item.id, item));