Skip to content

Commit 8a9fc09

Browse files
committed
[IMP] awesome_dashboard: add dashboard for owl training
Implemented a lazy-loaded dashboard for the JS awesome_dashboard tutorial. Dashboard retrieves data from the awesome_dashboard.statistics service. Displays various numerical data using graphs and cards.
1 parent 33f4f9c commit 8a9fc09

19 files changed

+396
-34
lines changed

awesome_dashboard/__manifest__.py

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,29 @@
11
# -*- coding: utf-8 -*-
22
{
3-
'name': "Awesome Dashboard",
4-
5-
'summary': """
3+
"name": "Awesome Dashboard",
4+
"summary": """
65
Starting module for "Discover the JS framework, chapter 2: Build a dashboard"
76
""",
8-
9-
'description': """
7+
"description": """
108
Starting module for "Discover the JS framework, chapter 2: Build a dashboard"
119
""",
12-
13-
'author': "Odoo",
14-
'website': "https://www.odoo.com/",
15-
'category': 'Tutorials/AwesomeDashboard',
16-
'version': '0.1',
17-
'application': True,
18-
'installable': True,
19-
'depends': ['base', 'web', 'mail', 'crm'],
20-
21-
'data': [
22-
'views/views.xml',
10+
"author": "Odoo",
11+
"website": "https://www.odoo.com/",
12+
"category": "Tutorials/AwesomeDashboard",
13+
"version": "0.1",
14+
"application": True,
15+
"installable": True,
16+
"depends": ["base", "web", "mail", "crm"],
17+
"data": [
18+
"views/views.xml",
2319
],
24-
'assets': {
25-
'web.assets_backend': [
26-
'awesome_dashboard/static/src/**/*',
20+
"assets": {
21+
"web.assets_backend": [
22+
"awesome_dashboard/static/src/**/*",
23+
],
24+
"awesome_dashboard.dashboard": [
25+
"awesome_dashboard/static/src/dashboard/**/*",
2726
],
2827
},
29-
'license': 'AGPL-3'
28+
"license": "AGPL-3",
3029
}

awesome_dashboard/static/src/dashboard.js

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Component, useRef, onWillStart, useEffect } from "@odoo/owl";
2+
import { loadJS } from "@web/core/assets";
3+
4+
export class PieChart extends Component {
5+
static template = "awesome_dashboard.pie_chart";
6+
static props = {
7+
data: { type: Object },
8+
};
9+
10+
setup() {
11+
this.canvasRef = useRef('canvasRef');
12+
this.chart = null;
13+
14+
onWillStart(async () => {
15+
await loadJS(["/web/static/lib/Chart/Chart.js"]);
16+
});
17+
18+
useEffect(()=> this.renderChart())
19+
20+
}
21+
22+
renderChart() {
23+
if (this.chart) {
24+
this.chart.destroy();}
25+
this.chart = new Chart(this.canvasRef.el, this.getChartConfig());
26+
}
27+
28+
getChartConfig() {
29+
return {
30+
type: 'pie',
31+
data: {
32+
labels: this.props.labels,
33+
datasets: [{
34+
data: Object.values(this.props.data)
35+
}],
36+
},
37+
}
38+
}
39+
40+
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<?xml version="1.0" encoding="UTF-8" ?>
22
<templates xml:space="preserve">
33

4-
<t t-name="awesome_dashboard.AwesomeDashboard">
5-
hello dashboard
4+
<t t-name="awesome_dashboard.pie_chart">
5+
<canvas t-ref="canvasRef"></canvas>
6+
67
</t>
78

89
</templates>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/** @odoo-module **/
2+
3+
import { Component , useState } from "@odoo/owl";
4+
import { registry } from "@web/core/registry";
5+
import { Layout } from "@web/search/layout";
6+
import { useService } from "@web/core/utils/hooks";
7+
import { DashboardItem } from "./dashboarditem/dashboarditem";
8+
import { PieChart } from "./chart/pie";
9+
import { dashboardRegistry } from "./dashboarditem/dashboard_items";
10+
import { SettingsDialog } from "./dialog/dialog";
11+
12+
class AwesomeDashboard extends Component {
13+
static template = "awesome_dashboard.AwesomeDashboard";
14+
static components = { Layout , DashboardItem , PieChart};
15+
setup() {
16+
this.action = useService("action");
17+
this.dialogService = useService("dialog");
18+
19+
this.statisticsService = useService("awesome_dashboard.statistics");
20+
this.state = useState(this.statisticsService.state.dashboardItems);
21+
22+
const savedHiddenItems = JSON.parse(localStorage.getItem("hidden_dashboard_items"));
23+
this.state.hiddenItems = new Set(savedHiddenItems);
24+
25+
26+
}
27+
get display() {
28+
return {controlPanel: {} }
29+
}
30+
async openCustomers() {
31+
32+
this.action.doAction("base.action_partner_form");
33+
}
34+
35+
async opendialog() {
36+
this.dialogService.add(SettingsDialog, {
37+
onApply: (hiddenItems) => {
38+
this.state.hiddenItems = new Set(hiddenItems);
39+
},
40+
});
41+
}
42+
async openCrmlead() {
43+
this.action.doAction({
44+
type: 'ir.actions.act_window',
45+
name:'crm leads',
46+
target: 'current',
47+
res_model: 'crm.lead',
48+
views: [[false, 'list'],[false, 'form']],
49+
});
50+
}
51+
get visibleItems() {
52+
return Object.values(dashboardRegistry.getAll()).filter(item => !this.state.hiddenItems.has(item.id));
53+
}
54+
}
55+
56+
registry.category("lazy_components").add("awesome_dashboard.dashboard", AwesomeDashboard);

awesome_dashboard/static/src/dashboard/dashboard.scss

Whitespace-only changes.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<templates xml:space="preserve">
3+
4+
<t t-name="awesome_dashboard.AwesomeDashboard">
5+
6+
7+
<Layout className="'o_dashboard h-100 '" display="display">
8+
9+
<t t-set-slot="layout-buttons">
10+
<button type="object" t-on-click="openCustomers" class="btn btn-primary">Customers</button>
11+
<button type="object" t-on-click="openCrmlead" class="btn btn-primary">leads</button>
12+
13+
14+
</t>
15+
<t t-set-slot="control-panel-additional-actions">
16+
<button class="btn" t-on-click="opendialog">
17+
<i class="fa fa-cog" />
18+
</button>
19+
</t>
20+
21+
<div class="d-flex flex-wrap justify-content-center">
22+
<t t-foreach="visibleItems" t-as="item" t-key="item.id">
23+
<div class="p-2 gap-2">
24+
<DashboardItem size="item.size || 1">
25+
<t >
26+
<t t-component="item.Component" t-props="item.props(this.state[item.id])" />
27+
</t>
28+
</DashboardItem>
29+
</div>
30+
</t>
31+
</div>
32+
</Layout>
33+
34+
</t>
35+
36+
</templates>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/** @odoo-module **/
2+
import { NumberCard } from "./number_card";
3+
import { PieChartCard } from "./pie_chart_card";
4+
import { registry } from "@web/core/registry";
5+
6+
export const dashboardRegistry = registry.category("awesome_dashboard.items");
7+
8+
dashboardRegistry.add(
9+
"average_quantity", {
10+
id: "average_quantity",
11+
description: "Average amount of t-shirt by order",
12+
Component: NumberCard,
13+
size: 1,
14+
props: (data) => ({
15+
title: "T-shirt Ordered",
16+
value: data,
17+
}),
18+
})
19+
20+
dashboardRegistry.add(
21+
"average_time", {
22+
id: "average_time",
23+
description: "Average Time",
24+
Component: NumberCard,
25+
size: 2,
26+
props: (data) => ({
27+
title: "Average time for an order to go from 'new' to 'sent' or 'cancelled'",
28+
value: data,
29+
}),
30+
})
31+
32+
dashboardRegistry.add(
33+
"nb_new_orders", {
34+
id: "nb_new_orders",
35+
description: "New orders this month",
36+
Component: NumberCard,
37+
size: 1,
38+
props: (data) => ({
39+
title: "Numbers of new orders this month",
40+
value: data,
41+
}),
42+
})
43+
44+
dashboardRegistry.add(
45+
"nb_cancelled_orders", {
46+
id: "nb_cancelled_orders",
47+
description: "Cancelled orders this month",
48+
Component: NumberCard,
49+
size: 1,
50+
props: (data) => ({
51+
title: "Numbers of cancelled orders this month",
52+
value: data,
53+
})
54+
})
55+
56+
dashboardRegistry.add(
57+
"total_amount", {
58+
id: "total_amount",
59+
description: "Total Orders",
60+
Component: NumberCard,
61+
size: 1,
62+
props: (data) => ({
63+
title: "Total Numbers of new orders this month",
64+
value: data,
65+
}),
66+
})
67+
68+
dashboardRegistry.add(
69+
"orders_by_size", {
70+
id: "orders_by_size",
71+
description: "Orders by size",
72+
Component: PieChartCard,
73+
size: 1.5,
74+
props: (data) => ({
75+
label: "Orders by size",
76+
data: data,
77+
}),
78+
})
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Component } from "@odoo/owl";
2+
3+
export class DashboardItem extends Component {
4+
static template = "awesome_dashboard.dashboarditem";
5+
static props ={
6+
size: { type: Number, optional: true, default: 1},
7+
}
8+
9+
}
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 class="card shadow-sm rounded-3 p-3 text-center d-flex flex-column align-items-center justify-content-center" t-att-style="'width: ' + (18 * (props.size || 1)) + 'rem'">
5+
<t t-slot="default" />
6+
</div>
7+
</t>
8+
</templates>

0 commit comments

Comments
 (0)