Skip to content

Commit 8b2c95b

Browse files
committed
[IMP] awesome_dashboard: add core dashboard features, dynamic widget framework
- Implement main dashboard layout with widget container and registry - Add base widget class and example widget following tutorial pattern - Integrate RPC calls for dynamic data fetching in widgets - Setup dashboard service to manage widget lifecycle and events - Configure QWeb templates and assets for widget rendering - Enable mounting and updating of widgets via Owl framework - Implemented real-time updates with reactive state for auto-refreshing dashboard. - Added lazy loading for the dashboard to optimize asset loading and performance. - Refactored dashboard to be generic and dynamic using configurable items.
1 parent b2cbb43 commit 8b2c95b

File tree

21 files changed

+344
-24
lines changed

21 files changed

+344
-24
lines changed

awesome_dashboard/__manifest__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
'web.assets_backend': [
2626
'awesome_dashboard/static/src/**/*',
2727
],
28+
'awesome_dashboard.dashboard': [
29+
'awesome_dashboard/static/src/dashboard/**/*',
30+
]
2831
},
2932
'license': 'AGPL-3'
3033
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Component } from '@odoo/owl'
2+
3+
export class NumberCard extends Component {
4+
static template = "awesome_dashboard.numberCard"
5+
static components = {}
6+
static props = {
7+
title: {
8+
type: String
9+
},
10+
value: {
11+
type: Number | String
12+
}
13+
}
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<templates>
3+
<t t-name="awesome_dashboard.numberCard">
4+
<h2 class="text-lg-center">
5+
<t t-esc="props.title"/>
6+
</h2>
7+
<div class="text-success text-bold text-lg-center" style="font-size: 38px; font-weight: bold">
8+
<t t-esc="props.value"/>
9+
</div>
10+
</t>
11+
</templates>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"use strict";
2+
import { Component, onWillStart, useRef, useEffect } from '@odoo/owl'
3+
import { AssetsLoadingError, loadJS } from '@web/core/assets';
4+
5+
export class PieChartCard extends Component {
6+
7+
static template = "awesome_dashboard.pieChartCard";
8+
static components = {}
9+
static props = {
10+
title: {
11+
type: String
12+
},
13+
value: {
14+
type: Object
15+
}
16+
}
17+
18+
setup() {
19+
this.canvasRef = useRef("canvas");
20+
21+
onWillStart(async () => {
22+
try {
23+
await loadJS(["/web/static/lib/Chart/Chart.js"]);
24+
}
25+
catch (error) {
26+
if (!(error instanceof AssetsLoadingError)) {
27+
throw error;
28+
}
29+
}
30+
})
31+
32+
useEffect(() => this.renderPieChart())
33+
}
34+
35+
renderPieChart() {
36+
const ctx = this.canvasRef.el.getContext("2d");
37+
if (this.chart) {
38+
this.chart.destroy();
39+
}
40+
this.chart = new Chart(ctx, {
41+
type: "pie",
42+
data: {
43+
labels: Object.keys(this.props.value || []), //["S", "M", "L", "XL", "XXL"],
44+
datasets: [{
45+
data: Object.values(this.props.value || []), // [10, 20, 15, 5, 2]
46+
}],
47+
},
48+
options: {
49+
responsive: true,
50+
},
51+
});
52+
}
53+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<templates>
3+
<t t-name="awesome_dashboard.pieChartCard">
4+
<canvas t-ref="canvas" width="300" height="300"></canvas>
5+
</t>
6+
</templates>

awesome_dashboard/static/src/dashboard.js

Lines changed: 0 additions & 10 deletions
This file was deleted.

awesome_dashboard/static/src/dashboard.xml

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/** @odoo-module **/
2+
3+
import { _t } from "@web/core/l10n/translation";
4+
import { Component, useState } from "@odoo/owl";
5+
import { registry } from "@web/core/registry";
6+
import { Layout } from '@web/search/layout'
7+
import { useService } from "@web/core/utils/hooks";
8+
import { DashboardItem } from "../dashboarditem/dashboarditem";
9+
import { PieChartCard } from "../cards/piechartcard/piechart";
10+
import { NumberCard } from "../cards/numbercard/numbercard";
11+
import { ITEMS } from "../data/items";
12+
13+
14+
15+
export class AwesomeDashboard extends Component {
16+
static template = "awesome_dashboard.AwesomeDashboard";
17+
static components = { Layout, DashboardItem, PieChartCard, NumberCard }
18+
19+
setup() {
20+
const { status } = owl;
21+
this.action = useService("action");
22+
this.state = useState({ items: [], chart: {} });
23+
this.statisticsService = useService('statistics');
24+
this.statsResult = useState(this.statisticsService);
25+
}
26+
27+
// get items() {
28+
// return [
29+
// {
30+
// id: 1,
31+
// title: 'Number of new orders this month',
32+
// value: this.statisticsService.nb_new_orders,
33+
// },
34+
// {
35+
// id: 2,
36+
// title: 'Total amount of new orders this month',
37+
// value: this.statisticsService.total_amount,
38+
// },
39+
// {
40+
// id: 3,
41+
// title: 'Average amount of t-shirt by order this month',
42+
// value: this.statisticsService.average_quantity,
43+
// },
44+
// {
45+
// id: 4,
46+
// title: 'Number of cancelled orders this month',
47+
// value: this.statisticsService.nb_cancelled_orders,
48+
// },
49+
// {
50+
// id: 5,
51+
// title: "Average time for an order to go from ‘new’ to ‘sent’ or ‘cancelled`",
52+
// value: this.statisticsService.average_time,
53+
// }
54+
// ];
55+
// }
56+
57+
get items() {
58+
return ITEMS;
59+
}
60+
61+
get chart() {
62+
return this.statsResult.orders_by_size;
63+
}
64+
65+
openCustomers() {
66+
this.action.doAction("contacts.action_contacts");
67+
}
68+
69+
openLeads() {
70+
this.action.doAction({
71+
type: 'ir.actions.act_window',
72+
name: _t('Leads'),
73+
target: 'current',
74+
res_model: 'crm.lead',
75+
views: [[false, 'kanban'], [false, 'list'], [false, 'form']], // [view_id, view_type]
76+
});
77+
}
78+
}
79+
80+
registry.category("lazy_components").add("awesome_dashboard.dashboard", AwesomeDashboard);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.o_dashboard {
2+
display: flex;
3+
flex-wrap: wrap;
4+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<templates xml:space="preserve">
3+
<t t-name="awesome_dashboard.AwesomeDashboard">
4+
<Layout className="'o_dashboard'" display="{controlPanel: {}}">
5+
<t t-set-slot="layout-buttons">
6+
<button type="button" class="btn btn-primary" t-on-click="openCustomers">Customers</button>
7+
<button type="button" class="btn btn-primary" t-on-click="openLeads">Leads</button>
8+
</t>
9+
<t t-foreach="items" t-as="item" t-key="item_index">
10+
<!-- <DashboardItem size="2">
11+
<h2 class="text-lg-center">
12+
<t t-esc="item.title"/>
13+
</h2>
14+
<div class="text-success text-bold text-lg-center" style="font-size: 38px; font-weight: bold">
15+
<t t-esc="item.value"/>
16+
</div>
17+
</DashboardItem> -->
18+
<!-- <DashboardItem>
19+
<NumberCard item="item" />
20+
</DashboardItem> -->
21+
<DashboardItem size="item.size || 1">
22+
<t t-set="itemProp" t-value="item.props ? item.props(statsResult) : {'data': statistics}"/>
23+
<t t-component="item.Component" t-props="itemProp" />
24+
</DashboardItem>
25+
</t>
26+
<!-- <DashboardItem>
27+
<PieChartCard t-props='{
28+
key_value: chart ? chart : {}
29+
}' />
30+
</DashboardItem> -->
31+
</Layout>
32+
</t>
33+
</templates>

0 commit comments

Comments
 (0)