Skip to content

Commit dfc1981

Browse files
committed
[IMP] awesome_dashboard: enhance chart interactivity and dashboard preferences
- Made the pie chart interactive so that clicking on a section opens a list of related orders, giving users a more direct way to explore data. - Improved the dashboard experience by storing each user’s preferences on the server, ensuring their personalized setup is kept across logins and devices.
1 parent 2bf1fcd commit dfc1981

File tree

8 files changed

+159
-80
lines changed

8 files changed

+159
-80
lines changed

awesome_dashboard/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# -*- coding: utf-8 -*-
22

33
from . import controllers
4+
from . import models

awesome_dashboard/__manifest__.py

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,31 @@
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-
'data': [
21-
'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/res_user_views.xml",
19+
"views/views.xml",
2220
],
23-
'assets': {
24-
'web.assets_backend': [
25-
'awesome_dashboard/static/src/**/*',
26-
('remove', 'awesome_dashboard/static/src/dashboard/**/*'),
21+
"assets": {
22+
"web.assets_backend": [
23+
"awesome_dashboard/static/src/**/*",
24+
("remove", "awesome_dashboard/static/src/dashboard/**/*"),
2725
],
28-
'awesome_dashboard.dashboard': [
29-
'awesome_dashboard/static/src/dashboard/**/*',
26+
"awesome_dashboard.dashboard": [
27+
"awesome_dashboard/static/src/dashboard/**/*",
3028
],
3129
},
32-
'license': 'AGPL-3',
30+
"license": "AGPL-3",
3331
}

awesome_dashboard/controllers/controllers.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88

99
logger = logging.getLogger(__name__)
1010

11+
1112
class AwesomeDashboard(http.Controller):
12-
@http.route('/awesome_dashboard/statistics', type='json', auth='user')
13+
@http.route("/awesome_dashboard/statistics", type="json", auth="user")
1314
def get_statistics(self):
1415
"""
1516
Returns a dict of statistics about the orders:
@@ -22,15 +23,23 @@ def get_statistics(self):
2223
"""
2324

2425
return {
25-
'average_quantity': random.randint(4, 12),
26-
'average_time': random.randint(4, 123),
27-
'nb_cancelled_orders': random.randint(0, 50),
28-
'nb_new_orders': random.randint(10, 200),
29-
'orders_by_size': {
30-
'm': random.randint(0, 150),
31-
's': random.randint(0, 150),
32-
'xl': random.randint(0, 150),
26+
"average_quantity": random.randint(4, 12),
27+
"average_time": random.randint(4, 123),
28+
"nb_cancelled_orders": random.randint(0, 50),
29+
"nb_new_orders": random.randint(10, 200),
30+
"orders_by_size": {
31+
"m": random.randint(0, 150),
32+
"s": random.randint(0, 150),
33+
"xl": random.randint(0, 150),
3334
},
34-
'total_amount': random.randint(100, 1000)
35+
"total_amount": random.randint(100, 1000),
3536
}
3637

38+
@http.route("/awesome_dashboard/save_disabled_items", type="json", auth="user")
39+
def save_disabled_items(self, disabled_items):
40+
request.env.user.save_disabled_dashboard_items(disabled_items)
41+
return {"status": "ok"}
42+
43+
@http.route("/awesome_dashboard/get_disabled_items", type="json", auth="user")
44+
def get_disabled_items(self):
45+
return request.env.user.get_disabled_dashboard_items()

awesome_dashboard/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import res_user

awesome_dashboard/models/res_user.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from odoo import models, fields, api
2+
3+
4+
class ResUsers(models.Model):
5+
_inherit = "res.users"
6+
7+
disabled_dashboard_items = fields.Text(
8+
string="Disabled Dashboard Items",
9+
help="Stores list of dashboard item IDs hidden by this user",
10+
)
11+
12+
@api.model
13+
def save_disabled_dashboard_items(self, disabled_items_json):
14+
self.env.user.disabled_dashboard_items = disabled_items_json
15+
return True
16+
17+
@api.model
18+
def get_disabled_dashboard_items(self):
19+
return self.env.user.disabled_dashboard_items or "[]"

awesome_dashboard/static/src/dashboard/dashboard.js

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
/** @odoo-module **/
22

3-
import { Component, useState } from "@odoo/owl";
3+
import { Component, useState, onWillStart } from "@odoo/owl";
44
import { registry } from "@web/core/registry";
55
import { Layout } from "@web/search/layout";
66
import { useService } from "@web/core/utils/hooks";
77
import { DashboardItem } from "./dashboard_item/dashboard_item";
88
import { Dialog } from "@web/core/dialog/dialog";
99
import { CheckBox } from "@web/core/checkbox/checkbox";
10-
import { browser } from "@web/core/browser/browser";
1110
import { _t } from "@web/core/l10n/translation";
11+
import { rpc } from "@web/core/network/rpc";
12+
13+
async function saveDisabledItems(ids) {
14+
await rpc("/awesome_dashboard/save_disabled_items", {
15+
disabled_items: JSON.stringify(ids),
16+
});
17+
}
18+
19+
async function loadDisabledItems() {
20+
const res = await rpc("/awesome_dashboard/get_disabled_items");
21+
return JSON.parse(res);
22+
}
1223

1324
class AwesomeDashboard extends Component {
1425
static template = "awesome_dashboard.AwesomeDashboard";
@@ -21,8 +32,16 @@ class AwesomeDashboard extends Component {
2132
this.dialog = useService("dialog");
2233
this.display = { controlPanel: {} };
2334
this.items = registry.category("awesome_dashboard").getAll();
35+
// this.state = useState({
36+
// disabledItems: browser.localStorage.getItem("disabledDashboardItems")?.split(",") || []
37+
// });
38+
2439
this.state = useState({
25-
disabledItems: browser.localStorage.getItem("disabledDashboardItems")?.split(",") || []
40+
disabledItems: [],
41+
});
42+
43+
onWillStart(async () => {
44+
this.state.disabledItems = await loadDisabledItems();
2645
});
2746
}
2847

@@ -35,7 +54,8 @@ class AwesomeDashboard extends Component {
3554
}
3655

3756
updateConfiguration(newDisabledItems) {
38-
this.state.disabledItems = newDisabledItems;
57+
this.state.disabledItems = newDisabledItems; // updates UI
58+
saveDisabledItems(newDisabledItems);
3959
}
4060

4161

@@ -80,11 +100,6 @@ class ConfigurationDialog extends Component {
80100
(item) => !item.enabled
81101
).map((item) => item.id)
82102

83-
browser.localStorage.setItem(
84-
"disabledDashboardItems",
85-
newDisabledItems,
86-
);
87-
88103
this.props.onUpdateConfiguration(newDisabledItems);
89104
}
90105

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,64 @@
1-
import { loadJS } from "@web/core/assets";
2-
import { getColor } from "@web/core/colors/colors";
3-
import { Component, onWillStart , useRef , onMounted , onWillUnmount} from "@odoo/owl";
1+
import { loadJS } from "@web/core/assets";
2+
import { getColor } from "@web/core/colors/colors";
3+
import { Component, onWillStart , useRef , onMounted , onWillUnmount} from "@odoo/owl";
4+
import { useService } from "@web/core/utils/hooks";
45

5-
export class PieChart extends Component{
6-
static template = "awesome_dashboard.PieChart";
7-
static props = {
8-
label: String,
9-
data: Object,
10-
};
6+
export class PieChart extends Component{
7+
static template = "awesome_dashboard.PieChart";
8+
static props = {
9+
label: String,
10+
data: Object,
11+
};
1112

12-
setup(){
13-
this.canvasRef = useRef("canvas");
14-
onWillStart(()=>loadJS("/web/static/lib/Chart/Chart.js"));
15-
onMounted(() => {
16-
this.renderChart();
17-
});
18-
onWillUnmount(() => {
19-
if(this.chart){
20-
this.chart.destroy();
21-
}
22-
});
23-
}
13+
setup(){
14+
this.canvasRef = useRef("canvas");
15+
this.actionService = useService("action");
16+
onWillStart(()=>loadJS("/web/static/lib/Chart/Chart.js"));
17+
onMounted(() => {
18+
this.renderChart();
19+
});
20+
onWillUnmount(() => {
21+
if(this.chart){
22+
this.chart.destroy();
23+
}
24+
});
25+
}
2426

25-
renderChart(){
26-
const labels = Object.keys(this.props.data);
27-
const data = Object.values(this.props.data);
28-
const color = labels.map((_, index) => getColor(index));
29-
this.chart = new Chart(this.canvasRef.el, {
30-
type: "pie",
31-
data: {
32-
labels: labels,
33-
datasets: [
34-
{
35-
label: this.props.label,
36-
data: data,
37-
backgroundColor: color,
27+
renderChart(){
28+
const labels = Object.keys(this.props.data);
29+
const data = Object.values(this.props.data);
30+
const color = labels.map((_, index) => getColor(index));
31+
this.chart = new Chart(this.canvasRef.el, {
32+
type: "pie",
33+
data: {
34+
labels: labels,
35+
datasets: [
36+
{
37+
label: this.props.label,
38+
data: data,
39+
backgroundColor: color,
40+
},
41+
],
42+
},
43+
options: {
44+
onClick: (event, elements) => {
45+
if (elements.length > 0) {
46+
const index = elements[0].index;
47+
const size = labels[index];
48+
this.openOrdersBySize(size);
49+
}
3850
},
39-
],
40-
},
41-
});
42-
}
43-
}
51+
},
52+
});
53+
}
54+
55+
openOrdersBySize(size) {
56+
this.actionService.doAction({
57+
type: "ir.actions.act_window",
58+
name: `Orders - Size ${size}`,
59+
res_model: "sale.order", //just to demonstrate
60+
views: [[false, "list"]],
61+
domain: [["id", "=", -1]], // always empty (demo only)
62+
});
63+
}
64+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo>
3+
<record id="view_users_form_dashboard" model="ir.ui.view">
4+
<field name="name">res.users.form.dashboard</field>
5+
<field name="model">res.users</field>
6+
<field name="inherit_id" ref="base.view_users_form"/>
7+
<field name="arch" type="xml">
8+
<xpath expr="//sheet/notebook/page[@name='preferences']" position="inside">
9+
<group string="Dashboard Preferences">
10+
<field name="disabled_dashboard_items"/>
11+
</group>
12+
</xpath>
13+
</field>
14+
</record>
15+
</odoo>

0 commit comments

Comments
 (0)