Skip to content

Commit c4079fd

Browse files
committed
[IMP] awesome_dashboard: added settings in dashboard
Created a settings button in the dashboard to add and remove items. also Clicking on a section of the pie chart should open a list view of all orders that have the corresponding size and also make a responsive design.
1 parent 13a2b85 commit c4079fd

File tree

17 files changed

+296
-41
lines changed

17 files changed

+296
-41
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/i18n/hi_IN.po

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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 12:17+0000\n"
10+
"PO-Revision-Date: 2025-06-24 12:17+0000\n"
11+
"Last-Translator: \n"
12+
"Language-Team: Hindi\n"
13+
"Language: hi\n"
14+
"MIME-Version: 1.0\n"
15+
"Content-Type: text/plain; charset=UTF-8\n"
16+
"Content-Transfer-Encoding: 8bit\n"
17+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
18+
19+
#. module: awesome_dashboard
20+
#. odoo-javascript
21+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboardSetting/dashboard_setting.xml:0
22+
msgid "Apply"
23+
msgstr "लागू करें"
24+
25+
#. module: awesome_dashboard
26+
#: model:ir.ui.menu,name:awesome_dashboard.menu_root
27+
msgid "Awesome Dashboard"
28+
msgstr "ऑसम डैशबोर्ड"
29+
30+
#. module: awesome_dashboard
31+
#. odoo-javascript
32+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboardSetting/dashboard_setting.xml:0
33+
msgid "Cancel"
34+
msgstr "रद्द करें"
35+
36+
#. module: awesome_dashboard
37+
#. odoo-javascript
38+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard.xml:0
39+
msgid "Customers"
40+
msgstr "ग्राहक"
41+
42+
#. module: awesome_dashboard
43+
#: model:ir.actions.client,name:awesome_dashboard.dashboard
44+
#: model:ir.ui.menu,name:awesome_dashboard.dashboard_menu
45+
msgid "Dashboard"
46+
msgstr "डैशबोर्ड"
47+
48+
#. module: awesome_dashboard
49+
#. odoo-javascript
50+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard.xml:0
51+
msgid "Dashboard Settings"
52+
msgstr "डैशबोर्ड सेटिंग्स"
53+
54+
#. module: awesome_dashboard
55+
#. odoo-javascript
56+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboard.xml:0
57+
msgid "Leads"
58+
msgstr "लीड्स"
59+
60+
#. module: awesome_dashboard
61+
#. odoo-javascript
62+
#: code:addons/awesome_dashboard/static/src/dashboard/piechartcard/piechartcard.xml:0
63+
msgid "Loading chart..."
64+
msgstr "चार्ट लोड हो रहा है..."
65+
66+
#. module: awesome_dashboard
67+
#. odoo-javascript
68+
#: code:addons/awesome_dashboard/static/src/dashboard/dashboardSetting/dashboard_setting.xml:0
69+
msgid "Select items to display on your dashboard:"
70+
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: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,50 @@
1-
/** @odoo-module **/
2-
3-
import { Component, useState } from "@odoo/owl";
1+
import { Component, useState, onWillStart } from "@odoo/owl";
42
import { registry } from "@web/core/registry";
53
import { Layout } from "@web/search/layout";
64
import { useService } from "@web/core/utils/hooks";
75
import { DashboardItem } from "./dashboardItem/dashboard_item";
86
import { Piechart } from "./pieChart/pieChart";
7+
import { DashboardSettings } from "./dashboardSetting/dashboard_setting";
8+
import { rpc } from "@web/core/network/rpc";
9+
910
class AwesomeDashboard extends Component {
1011
static template = "awesome_dashboard.AwesomeDashboard";
1112
static components = { Layout, DashboardItem, Piechart };
1213

1314
setup() {
14-
this.action = useService("action");
1515
const dashboardItemsRegistryData = registry.category("awesome_dashboard");
16+
this.action = useService("action");
1617
this.items = dashboardItemsRegistryData.getAll();
1718
this.statisticServices = useService("awesome_dashboard.statistics");
1819
this.state = useState({ statistic: this.statisticServices.statistic });
20+
this.dialogService = useService("dialog");
21+
this.displayData = useState({
22+
disabledItems: [],
23+
isLoading: true,
24+
});
25+
onWillStart(async () => {
26+
try {
27+
// this.displayData.isLoading = true;
28+
const fetchedDisabledItems = await rpc(
29+
"/web/dataset/call_kw/res.users/get_dashboard_settings",
30+
{
31+
model: "res.users",
32+
method: "get_dashboard_settings",
33+
args: [],
34+
kwargs: {},
35+
}
36+
);
37+
this.displayData.disabledItems = fetchedDisabledItems;
38+
} catch (error) {
39+
console.error(
40+
"Error loading initial dashboard settings from server:",
41+
error
42+
);
43+
this.displayData.disabledItems = [];
44+
} finally {
45+
this.displayData.isLoading = false;
46+
}
47+
});
1948
}
2049
openCustomers() {
2150
this.action.doAction("base.action_partner_form");
@@ -34,6 +63,19 @@ class AwesomeDashboard extends Component {
3463
],
3564
});
3665
}
66+
67+
updateConfiguration(newUncheckedItems) {
68+
this.displayData.disabledItems.length = 0;
69+
this.displayData.disabledItems.push(...newUncheckedItems);
70+
}
71+
72+
openSetting() {
73+
this.dialogService.add(DashboardSettings, {
74+
items: this.items,
75+
initialUncheckedItems: this.state.uncheckedItems,
76+
updateConfiguration: this.updateConfiguration.bind(this),
77+
});
78+
}
3779
}
3880

3981
registry.category("lazy_components").add("AwesomeDashboard", AwesomeDashboard);

awesome_dashboard/static/src/dashboard/dashboard.scss

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

awesome_dashboard/static/src/dashboard/dashboard.xml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@
77
<button t-on-click="openCustomers" type="button" class="btn btn-primary" title="Customers">Customers</button>
88
<button t-on-click="openLeads" type="button" class="btn btn-primary" title="Customers">Leads</button>
99
</t>
10-
<div class="d-flex">
10+
<t t-set-slot="control-panel-additional-actions">
11+
<button class="btn btn-light" title="Dashboard Settings" t-on-click="openSetting">
12+
<i class="fa fa-cog"></i>
13+
</button>
14+
</t>
15+
<div class="d-flex flex-wrap">
1116
<t t-foreach="items" t-as="item" t-key="item.id">
12-
<DashboardItem size="item.size || 1">
17+
<DashboardItem t-if="(displayData.disabledItems || []).includes(item.id) === false" size="item.size || 1">
1318
<t t-set="itemProp" t-value="item.props ? item.props(this.state.statistic) : {'data': this.state.statistic}"/>
1419
<t t-component="item.Component" t-props="itemProp" />
1520
</DashboardItem>
1621
</t>
1722
</div>
18-
1923
</Layout>
2024
</t>
21-
2225
</templates>

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<templates xml:space="preserve">
33
<t t-name="awesome_dashboard.DashboardItem">
4-
<div class="card m-2 border-dark" t-attf-style="width: {{18 * props.size}}rem;">
4+
<div t-attf-class="o_dashboard_item"
5+
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;">
56
<div class="card-body">
67
<t t-slot="default"/>
78
</div>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Component, useState } from "@odoo/owl";
2+
import { Dialog } from "@web/core/dialog/dialog";
3+
import { rpc } from "@web/core/network/rpc";
4+
5+
export class DashboardSettings extends Component {
6+
static template = "awesome_dashboard.DashboardSettings";
7+
static components = { Dialog };
8+
9+
static props = {
10+
close: { type: Function },
11+
};
12+
13+
setup() {
14+
const items = this.props.items || {};
15+
const initialUncheckedItems = this.props.initialUncheckedItems || [];
16+
17+
this.dialogDisplayItems = useState(
18+
Object.values(items).map((item) => ({
19+
...item,
20+
checked: !initialUncheckedItems.includes(item.id),
21+
}))
22+
);
23+
}
24+
25+
onChange(checked, itemInDialog) {
26+
const targetItem = this.dialogDisplayItems.find(
27+
(i) => i.id === itemInDialog.id
28+
);
29+
if (targetItem) {
30+
targetItem.checked = checked;
31+
}
32+
}
33+
34+
async confirmChanges() {
35+
const newUncheckedItems = this.dialogDisplayItems
36+
.filter((item) => !item.checked)
37+
.map((item) => item.id);
38+
39+
await rpc("/web/dataset/call_kw/res.users/set_dashboard_settings", {
40+
model: "res.users",
41+
method: "set_dashboard_settings",
42+
args: [newUncheckedItems],
43+
kwargs: {},
44+
});
45+
46+
if (this.props.updateConfiguration) {
47+
this.props.updateConfiguration(newUncheckedItems);
48+
}
49+
this.props.close();
50+
}
51+
}
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.DashboardSettings">
4+
<Dialog title="'Dashboard Items Configuration'">
5+
<div class="p-3">
6+
<p>Select items to display on your dashboard:</p>
7+
<div t-foreach="dialogDisplayItems" t-as="item" t-key="item.id" class="form-check mb-2">
8+
<input
9+
type="checkbox"
10+
class="form-check-input"
11+
t-att-id="'settings_item_' + item.id"
12+
t-att-checked="item.checked"
13+
t-on-change="(ev) => this.onChange(ev.target.checked, item)"
14+
/>
15+
<label class="form-check-label" t-att-for="'settings_item_' + item.id">
16+
<t t-out="item.description"/>
17+
</label>
18+
</div>
19+
</div>
20+
<t t-set-slot="footer">
21+
<button class="btn btn-primary" t-on-click="confirmChanges">Apply</button>
22+
<button class="btn btn-secondary ms-2" t-on-click="props.close">Cancel</button>
23+
</t>
24+
</Dialog>
25+
</t>
26+
</templates>

awesome_dashboard/static/src/dashboard/numbercard/numbercard.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,7 @@ import { Component } from "@odoo/owl";
22
export class Numbercard extends Component {
33
static template = "awesome_dashboard.Numbercard";
44
static props = {
5-
size: {
6-
type: Number,
7-
default: 1,
8-
optional: true,
9-
},
10-
slots: {
11-
type: Object,
12-
shape: { default: true },
13-
},
5+
title: { type: String },
6+
value: { type: [String,Number] },
147
};
158
}

awesome_dashboard/static/src/dashboard/pieChart/pieChart.js

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import {
33
onWillStart,
44
useRef,
55
onMounted,
6-
onWillUnmount,
76
useEffect,
87
} from "@odoo/owl";
98
import { loadJS } from "@web/core/assets";
9+
import { useService } from "@web/core/utils/hooks";
1010

1111
export class Piechart extends Component {
1212
static template = "awesome_dashboard.Piechart";
@@ -16,12 +16,13 @@ export class Piechart extends Component {
1616
setup() {
1717
this.chart = null;
1818
this.canvasRef = useRef("canvas");
19+
this.action = useService("action");
1920

2021
onWillStart(async () => {
2122
await loadJS("/web/static/lib/Chart/Chart.js");
2223
});
2324

24-
this.chartData = {
25+
const chartData = {
2526
labels: Object.keys(this.props.data),
2627
datasets: [
2728
{
@@ -33,7 +34,16 @@ export class Piechart extends Component {
3334
onMounted(() => {
3435
this.chart = new Chart(this.canvasRef.el, {
3536
type: "pie",
36-
data: this.chartData,
37+
data: chartData,
38+
options: {
39+
onClick: (event, elements) => {
40+
if (elements.length > 0) {
41+
const idx = elements[0].index;
42+
const size = chartData.labels[idx];
43+
this.getOrdersBySize(size);
44+
}
45+
},
46+
},
3747
});
3848
});
3949
useEffect(
@@ -47,4 +57,19 @@ export class Piechart extends Component {
4757
() => [this.props.data]
4858
);
4959
}
60+
getOrdersBySize(size) {
61+
this.action.doAction({
62+
type: "ir.actions.act_window",
63+
name: `Orders with Size ${size.toUpperCase()}`,
64+
res_model: "sale.order",
65+
views: [[false, "list"]],
66+
domain: [
67+
[
68+
"order_line.product_template_attribute_value_ids.display_name",
69+
"ilike",
70+
size,
71+
],
72+
],
73+
});
74+
}
5075
}

0 commit comments

Comments
 (0)