Skip to content

Commit 21e61c6

Browse files
committed
[IMP] awesome_dashboard: add/remove items, translation, pie chart drilldown,
Created the check and uncheck dashboard items on both localStorage and the server side inside the res.users model. Moreover, added the Hindi translation of the dashboard. Further, opening the list view of sale.order on click of the pie chart slice. Moreover, made the dashboard card mobile responsive.
1 parent 5710343 commit 21e61c6

File tree

18 files changed

+451
-75
lines changed

18 files changed

+451
-75
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

3+
from . import models
34
from . import controllers

awesome_dashboard/__manifest__.py

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
11
# -*- coding: utf-8 -*-
22
{
3-
"name": "Awesome Dashboard",
4-
"summary": """
3+
'name': "Awesome Dashboard",
4+
5+
'summary': """
56
Starting module for "Discover the JS framework, chapter 2: Build a dashboard"
67
""",
7-
"description": """
8+
9+
'description': """
810
Starting module for "Discover the JS framework, chapter 2: Build a dashboard"
911
""",
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",
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',
1923
],
20-
"assets": {
21-
"web.assets_backend": [
22-
"awesome_dashboard/static/src/**/*",
24+
'assets': {
25+
'web.assets_backend': [
26+
'awesome_dashboard/static/src/**/*',
2327
],
24-
"awesome_dashboard.dashboard": [
25-
"awesome_dashboard/static/src/dashboard/**/*",
28+
'awesome_dashboard.dashboard': [
29+
'awesome_dashboard/static/src/dashboard/**/*',
2630
],
2731
},
28-
"license": "AGPL-3",
32+
'license': 'AGPL-3'
2933
}

awesome_dashboard/i18n/hi_IN.po

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# Translation of Odoo Server.
2+
# This file contains the translation of the following modules:
3+
# * awesome_dashboard
4+
#
5+
msgid ""
6+
msgstr ""
7+
"Project-Id-Version: Odoo Server 18.0+e\n"
8+
"Report-Msgid-Bugs-To: \n"
9+
"POT-Creation-Date: 2025-06-24 11:57+0000\n"
10+
"PO-Revision-Date: 2025-06-24 11:57+0000\n"
11+
"Last-Translator: \n"
12+
"Language-Team: \n"
13+
"MIME-Version: 1.0\n"
14+
"Content-Type: text/plain; charset=UTF-8\n"
15+
"Content-Transfer-Encoding: \n"
16+
"Plural-Forms: \n"
17+
18+
#. module: awesome_dashboard
19+
#. odoo-javascript
20+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard_items.js:0
21+
msgid "Avg. T-Shirts per Order:"
22+
msgstr "प्रति ऑर्डर औसत टी-शर्ट:"
23+
24+
#. module: awesome_dashboard
25+
#. odoo-javascript
26+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard_items.js:0
27+
msgid "Avg. Time New → Sent/Cancelled:"
28+
msgstr "औसत समय नया → भेजा/रद्द:"
29+
30+
#. module: awesome_dashboard
31+
#: model:ir.ui.menu,name:awesome_dashboard.menu_root
32+
msgid "Awesome Dashboard"
33+
msgstr "शानदार डैशबोर्ड"
34+
35+
#. module: awesome_dashboard
36+
#. odoo-javascript
37+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboardSetting/dashboard_setting.xml:0
38+
msgid "Cancel"
39+
msgstr "रद्द करें"
40+
41+
#. module: awesome_dashboard
42+
#. odoo-javascript
43+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard_items.js:0
44+
msgid "Cancelled Orders:"
45+
msgstr "रद्द किए गए ऑर्डर:"
46+
47+
#. module: awesome_dashboard
48+
#. odoo-javascript
49+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard.xml:0
50+
msgid "Customer"
51+
msgstr "ग्राहक"
52+
53+
#. module: awesome_dashboard
54+
#: model:ir.actions.client,name:awesome_dashboard.dashboard
55+
#: model:ir.ui.menu,name:awesome_dashboard.dashboard_menu
56+
msgid "Dashboard"
57+
msgstr "डैशबोर्ड"
58+
59+
#. module: awesome_dashboard
60+
#: model:ir.model.fields,field_description:awesome_dashboard.field_res_users__dashboard_disabled_items
61+
msgid "Dashboard Disabled Items"
62+
msgstr "डैशबोर्ड में अक्षम आइटम"
63+
64+
#. module: awesome_dashboard
65+
#. odoo-javascript
66+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboardSetting/dashboard_setting.xml:0
67+
msgid "Done"
68+
msgstr "हो गया"
69+
70+
#. module: awesome_dashboard
71+
#. odoo-javascript
72+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard.xml:0
73+
msgid "Leads"
74+
msgstr "लीड"
75+
76+
#. module: awesome_dashboard
77+
#. odoo-javascript
78+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard_items.js:0
79+
msgid "New Orders This Month:"
80+
msgstr "इस महीने नए ऑर्डर:"
81+
82+
#. module: awesome_dashboard
83+
#. odoo-javascript
84+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard_items.js:0
85+
msgid "Total Amount This Month:"
86+
msgstr "इस महीने की कुल राशि:"
87+
88+
#. module: awesome_dashboard
89+
#. odoo-javascript
90+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard_items.js:0
91+
msgid "Number of shirts ordered based on size"
92+
msgstr "आकार के आधार पर ऑर्डर की गई शर्ट की संख्या"
93+
94+
#. module: awesome_dashboard
95+
#. odoo-javascript
96+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboardSetting/dashboard_setting.xml:0
97+
msgid "Select items to display on your dashboard:"
98+
msgstr "अपने डैशबोर्ड पर प्रदर्शित करने के लिए आइटम चुनें:"
99+
100+
#. module: awesome_dashboard
101+
#. odoo-javascript
102+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard_items.js:0
103+
msgid "Shirt orders by size:"
104+
msgstr "आकार के अनुसार शर्ट के ऑर्डर:"
105+
106+
#. module: awesome_dashboard
107+
#. odoo-javascript
108+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard_items.js:0
109+
msgid "The average number of t-shirts by order"
110+
msgstr "प्रति ऑर्डर टी-शर्ट की औसत संख्या"
111+
112+
#. module: awesome_dashboard
113+
#. odoo-javascript
114+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard_items.js:0
115+
msgid ""
116+
"The average time (in hours) elapsed between the moment an order is created, "
117+
"and the moment is it sent"
118+
msgstr "ऑर्डर बनने और भेजे जाने के बीच का औसत समय (घंटों में)"
119+
120+
#. module: awesome_dashboard
121+
#. odoo-javascript
122+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard_items.js:0
123+
msgid "The number of cancelled orders, this month"
124+
msgstr "इस महीने रद्द किए गए ऑर्डर की संख्या"
125+
126+
#. module: awesome_dashboard
127+
#. odoo-javascript
128+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard_items.js:0
129+
msgid "The number of new orders, this month"
130+
msgstr "इस महीने नए ऑर्डर की संख्या"
131+
132+
#. module: awesome_dashboard
133+
#. odoo-javascript
134+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard_items.js:0
135+
msgid "The total amount of orders, this month"
136+
msgstr "इस महीने ऑर्डर की कुल राशि"
137+
138+
#. module: awesome_dashboard
139+
#: model:ir.model,name:awesome_dashboard.model_res_users
140+
msgid "User"
141+
msgstr "उपयोगकर्ता"

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_users

awesome_dashboard/models/res_users.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from odoo import fields, models, api
2+
3+
4+
class ResUsers(models.Model):
5+
_inherit = "res.users"
6+
7+
dashboard_disabled_items = fields.Char(default="")
8+
9+
@api.model
10+
def set_dashboard_settings(self, disable_item_ids):
11+
if self.env.user:
12+
items = ",".join(map(str, disable_item_ids))
13+
self.env.user.sudo().write({"dashboard_disabled_items": items})
14+
return True
15+
return False
16+
17+
@api.model
18+
def get_dashboard_settings(self):
19+
if self.env.user and self.env.user.dashboard_disabled_items:
20+
return self.env.user.dashboard_disabled_items.split(",")
21+
return []

awesome_dashboard/static/src/dashboard/dashboard.js

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
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 "./dashboardItem/dashboarditem";
88
import { PieChart } from "./pieChart/piechart";
9-
9+
import { DashboardSetting } from "./dashboardSetting/dashboard_setting";
10+
import { rpc } from "@web/core/network/rpc";
1011

1112
class AwesomeDashboard extends Component {
1213
static template = "awesome_dashboard.AwesomeDashboard";
@@ -16,10 +17,47 @@ class AwesomeDashboard extends Component {
1617
setup() {
1718
const dashboardItemsRegistry = registry.category("awesome_dashboard");
1819
this.items = dashboardItemsRegistry.getAll();
20+
this.dialogService = useService("dialog");
21+
1922

2023
this.action = useService("action");
2124
this.statisticsService = useService("awesome_dashboard.statistics");
2225
this.state = useState({ statistics: this.statisticsService.statistics });
26+
27+
28+
this.displayState = useState({
29+
disabledItems: [],
30+
isLoading: true,
31+
});
32+
onWillStart(async () => {
33+
try {
34+
const fetchedDisabledItems = await rpc("/web/dataset/call_kw/res.users/get_dashboard_settings", {
35+
model: 'res.users',
36+
method: 'get_dashboard_settings',
37+
args: [],
38+
kwargs: {},
39+
});
40+
this.displayState.disabledItems = fetchedDisabledItems;
41+
} catch (error) {
42+
console.error("Error loading initial dashboard settings from server:", error);
43+
this.displayState.disabledItems = [];
44+
} finally {
45+
this.displayState.isLoading = false;
46+
}
47+
});
48+
}
49+
50+
updateSettings(newUncheckedItems) {
51+
this.displayState.disabledItems.length = 0;
52+
this.displayState.disabledItems.push(...newUncheckedItems);
53+
}
54+
55+
openSettings() {
56+
this.dialogService.add(DashboardSetting, {
57+
items: this.items,
58+
initialDisabledItems: this.displayState.disabledItems,
59+
updateSettings: this.updateSettings.bind(this),
60+
});
2361
}
2462

2563
openCustomerView() {

awesome_dashboard/static/src/dashboard/dashboard.scss

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,24 @@
1717
color: #228B22;
1818
font-weight: bold;
1919
}
20+
.o_dashboard_item {
21+
background: #fff;
22+
border-radius: 0.75rem;
23+
box-shadow: 0 2px 8px rgba(0,0,0,0.07);
24+
padding: 1rem;
25+
margin: 1rem;
26+
display: inline-flex;
27+
justify-content: center;
28+
vertical-align: top;
29+
min-height: 3rem;
30+
}
31+
32+
@media (max-width: 426px) {
33+
.o_dashboard_item {
34+
width: 100% !important;
35+
display: flex;
36+
margin-left: 0.5rem;
37+
margin-right: 0.5rem;
38+
box-sizing: border-box;
39+
}
40+
}

awesome_dashboard/static/src/dashboard/dashboard.xml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,16 @@
77
<button type="button" class="btn btn-primary o-kanban-button-new" t-on-click="openCustomerView">Customer</button>
88
<button type="button" class="btn btn-primary o-kanban-button-new" t-on-click="openLeadsView">Leads</button>
99
</t>
10+
<t t-set-slot="control-panel-additional-actions">
11+
<button type="button" icon="fa-cog" class="btn btn-light"
12+
t-on-click="openSettings">
13+
<i class="fa fa-cog" />
14+
</button>
15+
</t>
1016
<div class="dashboard-items">
1117
<t t-foreach="this.items" t-as="item" t-key="item.id">
12-
<DashboardItem size="item.size || 1">
18+
<DashboardItem size="item.size || 1"
19+
t-if="!this.displayState.disabledItems.includes(item.id)">
1320
<t t-set="itemProp" t-value="item.props ? item.props(this.state.statistics) : {'data': this.state.statistics}"/>
1421
<t t-component="item.Component" t-props="itemProp" />
1522
</DashboardItem>

awesome_dashboard/static/src/dashboard/dashboardItem/dashboarditem.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
<templates xml:space="preserve">
33
<t t-name="awesome_dashboard.DashboardItem">
44
<t t-set="itemSize" t-value="props.size or 1"/>
5-
<div t-attf-style="width: #{18 * itemSize}rem; background: #fff; border-radius: 0.75rem; box-shadow: 0 2px 8px rgba(0,0,0,0.07); padding: 1rem; margin: 1rem; display: inline-flex; justify-content: center; vertical-align: top; min-height: 3rem;">
5+
<div t-attf-class="o_dashboard_item"
6+
t-attf-style="width: #{18 * itemSize}rem; background: #fff; border-radius: 0.75rem; box-shadow: 0 2px 8px rgba(0,0,0,0.07); padding: 1rem; margin: 1rem; display: inline-flex; justify-content: center; vertical-align: top; min-height: 3rem;">
67
<t t-slot="default"/>
78
</div>
89
</t>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Component } from "@odoo/owl";
2+
import { Dialog } from "@web/core/dialog/dialog";
3+
import { rpc } from "@web/core/network/rpc";
4+
import { _t } from "@web/core/l10n/translation";
5+
6+
export class DashboardSetting extends Component {
7+
static template = "awesome_dashboard.setting";
8+
9+
static components = { Dialog };
10+
11+
static props = {
12+
close: { type: Function }
13+
};
14+
15+
setup() {
16+
const items = this.props.items || {};
17+
18+
const initialDisabledItems = this.props.initialDisabledItems || [];
19+
20+
this.settingDisplayItems = Object.values(items).map((item) => ({
21+
...item,
22+
checked: !initialDisabledItems.includes(item.id),
23+
}))
24+
}
25+
26+
_t(...args) {
27+
return _t(...args);
28+
}
29+
30+
onChange(checked, itemInDialog) {
31+
const targetItem = this.settingDisplayItems.find(i => i.id === itemInDialog.id);
32+
if (targetItem) {
33+
targetItem.checked = checked;
34+
}
35+
}
36+
37+
async confirmDone() {
38+
const newDisableItems = this.settingDisplayItems.filter((item) => !item.checked).map((item) => item.id);
39+
40+
await rpc("/web/dataset/call_kw/res.users/set_dashboard_settings", {
41+
model: 'res.users',
42+
method: 'set_dashboard_settings',
43+
args: [newDisableItems],
44+
kwargs: {},
45+
});
46+
47+
if (this.props.updateSettings) {
48+
this.props.updateSettings(newDisableItems);
49+
}
50+
this.props.close();
51+
}
52+
}

0 commit comments

Comments
 (0)