Skip to content

Commit f72a207

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
1 parent b2cbb43 commit f72a207

File tree

16 files changed

+201
-24
lines changed

16 files changed

+201
-24
lines changed

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: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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 { PieChart } from "../piechart/piechart";
10+
11+
class AwesomeDashboard extends Component {
12+
static template = "awesome_dashboard.AwesomeDashboard";
13+
static components = { Layout, DashboardItem, PieChart }
14+
15+
setup() {
16+
const { status } = owl;
17+
this.action = useService("action");
18+
this.state = useState({ items: [], chart: {} });
19+
this.statisticsService = useService('statistics');
20+
this.loadStatisticsData();
21+
}
22+
23+
24+
async loadStatisticsData() {
25+
let result = await this.statisticsService.loadStatistics();
26+
this.state.items = [
27+
{
28+
id: 1,
29+
title: 'Number of new orders this month',
30+
value: result.nb_new_orders
31+
},
32+
{
33+
id: 2,
34+
title: 'Total amount of new orders this month',
35+
value: result.nb_new_orders
36+
},
37+
{
38+
id: 3,
39+
title: 'Average amount of t-shirt by order this month',
40+
value: result.nb_new_orders
41+
},
42+
{
43+
id: 4,
44+
title: 'Number of cancelled orders this month',
45+
value: result.nb_cancelled_orders
46+
},
47+
{
48+
id: 5,
49+
title: "Average time for an order to go from ‘new’ to ‘sent’ or ‘cancelled`",
50+
value: result.average_time
51+
}
52+
];
53+
this.state.chart = result.orders_by_size;
54+
55+
}
56+
57+
openCustomers() {
58+
this.action.doAction("contacts.action_contacts");
59+
}
60+
61+
openLeads() {
62+
this.action.doAction({
63+
type: 'ir.actions.act_window',
64+
name: _t('Leads'),
65+
target: 'current',
66+
res_model: 'crm.lead',
67+
views: [[false, 'kanban'], [false, 'list'], [false, 'form']], // [view_id, view_type]
68+
});
69+
}
70+
}
71+
72+
registry.category("actions").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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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="state.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+
</t>
19+
<DashboardItem>
20+
<PieChart t-props='{
21+
key_value: state.chart
22+
}' />
23+
</DashboardItem>
24+
</Layout>
25+
</t>
26+
</templates>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Component } from '@odoo/owl';
2+
3+
export class DashboardItem extends Component {
4+
static template = "awesome_dashboard.dashboardItem"
5+
static components = {}
6+
static props = {
7+
size: {
8+
type: Number,
9+
optional: true,
10+
default: 2
11+
},
12+
slots: {
13+
type: Object
14+
}
15+
}
16+
17+
setup() {}
18+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<templates xml:space="preserve">
3+
<t t-name="awesome_dashboard.dashboardItem">
4+
<div t-att-style="`width: ${18 * props.size}rem; border: 1px solid black;`" t-att-class="'m-3 p-3 d-inline-block'">
5+
<t t-slot="default"/>
6+
</div>
7+
</t>
8+
</templates>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"use strict";
2+
import { Component, onWillStart, useRef, useEffect } from '@odoo/owl'
3+
import { AssetsLoadingError, loadJS } from '@web/core/assets';
4+
5+
export class PieChart extends Component {
6+
7+
static template = "awesome_dashboard.pieChart";
8+
static components = {}
9+
static props = {
10+
key_value: Object
11+
}
12+
13+
setup() {
14+
this.canvasRef = useRef("canvas");
15+
16+
onWillStart(async () => {
17+
try {
18+
await loadJS(["/web/static/lib/Chart/Chart.js"]);
19+
}
20+
catch (error) {
21+
if (!(error instanceof AssetsLoadingError)) {
22+
throw error;
23+
}
24+
}
25+
})
26+
27+
useEffect(() => this.renderPieChart())
28+
}
29+
30+
renderPieChart() {
31+
const ctx = this.canvasRef.el.getContext("2d");
32+
this.chart = new Chart(ctx, {
33+
type: "pie",
34+
data: {
35+
labels: Object.keys(this.props.key_value), //["S", "M", "L", "XL", "XXL"],
36+
datasets: [{
37+
data: Object.values(this.props.key_value), // [10, 20, 15, 5, 2]
38+
}],
39+
},
40+
options: {
41+
responsive: true,
42+
},
43+
});
44+
}
45+
}
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.pieChart">
4+
<canvas t-ref="canvas" width="300" height="300"></canvas>
5+
</t>
6+
</templates>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { registry } from '@web/core/registry';
2+
import { rpc } from "@web/core/network/rpc";
3+
import { memoize } from "@web/core/utils/functions";
4+
5+
const loadStatistics = memoize(async () => {
6+
return await rpc("/awesome_dashboard/statistics");
7+
});
8+
9+
export const statisticsService = {
10+
dependencies: [],
11+
start() {
12+
return { loadStatistics };
13+
},
14+
};
15+
16+
registry.category("services").add("statistics", statisticsService);

0 commit comments

Comments
 (0)