Skip to content

Commit 30e73cb

Browse files
committed
[IMP] awesome_dashboard: use a config dialog
Chapter 2: Build a dashboard (11) - Use a dict for the dashboard data instead of a list - Use a custom dialog to list the configurations and allow the user to disable/enable them
1 parent 104180f commit 30e73cb

File tree

5 files changed

+114
-20
lines changed

5 files changed

+114
-20
lines changed

awesome_dashboard/static/src/dashboard/dashboard.js

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11
/** @odoo-module **/
22

3-
import { Component, useState } from "@odoo/owl";
3+
import { Component, useState, useEffect } from "@odoo/owl";
44
import { Layout } from "@web/search/layout";
55
import { useService } from "@web/core/utils/hooks";
66
import { AwesomeDashboardItem } from "@awesome_dashboard/dashboard/dashboard_item";
77
import { registry } from "@web/core/registry";
8+
import { CogMenu } from "@web/search/cog_menu/cog_menu";
9+
import { AwesomeDashboardConfigDialog } from "@awesome_dashboard/dashboard/dialogs/dashboard_config_dailog";
810

911
class AwesomeDashboard extends Component {
1012
static template = "awesome_dashboard.AwesomeDashboard";
11-
static components = { Layout, AwesomeDashboardItem };
13+
static components = { Layout, AwesomeDashboardItem, CogMenu };
1214

1315
setup() {
1416
this.action = useService("action");
1517
this.stats = useState(useService("awesome_dashboard_statistics"));
16-
this.items = registry.category("awesome_dashboard").get("data");
18+
const config = JSON.parse(localStorage.getItem("awesome_dashboard_config"));
19+
const data = registry.category("awesome_dashboard").get("data");
20+
this.setActives(config, data);
21+
this.items = useState({ data });
22+
this.dialog = useService("dialog");
1723
}
1824

1925
onClickCustomers() {
@@ -35,6 +41,24 @@ class AwesomeDashboard extends Component {
3541
views: [[false, "list"]],
3642
});
3743
}
44+
45+
setActives(ref, toUpdate) {
46+
for (const key in ref) {
47+
const entry = ref[key];
48+
const dataItem = toUpdate[key];
49+
if (dataItem) {
50+
dataItem.active = entry.active;
51+
}
52+
}
53+
}
54+
55+
openConfiguration() {
56+
this.dialog.add(AwesomeDashboardConfigDialog, {
57+
onConfirm: (configItems) => {
58+
this.setActives(configItems, this.items.data);
59+
},
60+
});
61+
}
3862
}
3963

4064
registry.category("lazy_components").add("awesome_dashboard.AwesomeDashboard", AwesomeDashboard);

awesome_dashboard/static/src/dashboard/dashboard.xml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<templates xml:space="preserve">
33

44
<t t-name="awesome_dashboard.AwesomeDashboard">
5-
<Layout display="{ controlPanel: {} }" className="'o_dashboard h-100'">
5+
<Layout display="{ controlPanel: {} }" className="'o_dashboard o_awesome_dashboard h-100'">
66
<t t-set-slot="layout-buttons">
77
<div class="o_list_buttons d-flex gap-1 d-empty-none align-items-baseline" role="toolbar" aria-label="Main actions">
88
<button type="button" class="btn btn-primary" t-on-click="onClickCustomers">
@@ -13,9 +13,16 @@
1313
</button>
1414
</div>
1515
</t>
16+
<t t-set-slot="control-panel-additional-actions">
17+
<button t-on-click="openConfiguration" class="btn p-0 ms-1 border-0">
18+
<i class="fa fa-cog"></i>
19+
</button>
20+
</t>
1621
<div class="o_dashboard_items">
17-
<t t-foreach="items" t-as="item" t-key="item.id">
18-
<AwesomeDashboardItem size="item.size">
22+
<t t-foreach="Object.entries(items.data)" t-as="entry" t-key="entry[0]">
23+
<t t-set="key" t-value="entry[0]"/>
24+
<t t-set="item" t-value="entry[1]"/>
25+
<AwesomeDashboardItem t-if="item.active" size="item.size">
1926
<t t-component="item.Component" t-props="item.props(stats)" />
2027
</AwesomeDashboardItem>
2128
</t>

awesome_dashboard/static/src/dashboard/data/dashboard_data.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,51 @@ import { registry } from "@web/core/registry";
44
import { PieChartCard } from "@awesome_dashboard/dashboard/cards/pie_chart_card";
55
import { NumberCard } from "@awesome_dashboard/dashboard/cards/number_card";
66

7-
registry.category("awesome_dashboard").add("data", [
8-
{
9-
id: "average_quantity",
7+
registry.category("awesome_dashboard").add("data", {
8+
average_quantity: {
109
Component: NumberCard,
1110
props: (stats) => ({
1211
title: "Average amount of t-shirt by order this month",
1312
value: stats.data.average_quantity,
1413
}),
14+
active: true,
1515
},
16-
{
17-
id: "average_time",
16+
average_time: {
1817
Component: NumberCard,
1918
props: (stats) => ({
2019
title: "Average time to deliver an order this month",
2120
value: stats.data.average_time,
2221
}),
22+
active: true,
2323
},
24-
{
25-
id: "nb_cancelled_orders",
24+
nb_cancelled_orders: {
2625
Component: NumberCard,
2726
size: 2.5,
2827
props: (stats) => ({
2928
title: "Number of cancelled orders this month",
3029
value: stats.data.nb_cancelled_orders,
3130
}),
31+
active: true,
3232
},
33-
{
34-
id: "nb_new_orders",
33+
nb_new_orders: {
3534
Component: NumberCard,
3635
size: 2.5,
3736
props: (stats) => ({
3837
title: "Number of new orders this month",
3938
value: stats.data.nb_new_orders,
4039
}),
40+
active: true,
4141
},
42-
{
43-
id: "total_amount",
42+
total_amount: {
4443
Component: NumberCard,
4544
size: 2.5,
4645
props: (stats) => ({
4746
title: "Total amount of orders this month",
4847
value: stats.data.total_amount,
4948
}),
49+
active: true,
5050
},
51-
{
52-
id: "orders_by_size",
51+
orders_by_size: {
5352
Component: PieChartCard,
5453
props: (stats) => ({
5554
title: "Orders by size",
@@ -68,5 +67,6 @@ registry.category("awesome_dashboard").add("data", [
6867
},
6968
},
7069
}),
70+
active: true,
7171
},
72-
]);
72+
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/** @odoo-module **/
2+
3+
import { Component } from "@odoo/owl";
4+
import { Dialog } from "@web/core/dialog/dialog";
5+
6+
export class AwesomeDashboardConfigDialog extends Component {
7+
static template = "awesome_dashboard.AwesomeDashboardConfigDialog";
8+
static components = { Dialog };
9+
static props = { close: { type: Function, optional: true }, onConfirm: { type: Function, optional: true } };
10+
static defaultProps = {
11+
close: () => {},
12+
onConfirm: () => {},
13+
};
14+
15+
setup() {
16+
if (localStorage.getItem("awesome_dashboard_config") === null) {
17+
localStorage.setItem(
18+
"awesome_dashboard_config",
19+
JSON.stringify({
20+
average_quantity: { title: "Average Quantity", active: true },
21+
average_time: { title: "Average Time", active: true },
22+
nb_cancelled_orders: { title: "Cancelled Orders", active: true },
23+
nb_new_orders: { title: "New Orders", active: true },
24+
total_amount: { title: "Total Amount", active: true },
25+
orders_by_size: { title: "Orders by Size", active: true },
26+
})
27+
);
28+
}
29+
this.configItems = JSON.parse(localStorage.getItem("awesome_dashboard_config"));
30+
}
31+
32+
onSave() {
33+
localStorage.setItem("awesome_dashboard_config", JSON.stringify(this.configItems));
34+
this.props.onConfirm(this.configItems);
35+
this.props.close();
36+
}
37+
38+
discard() {
39+
this.props.close();
40+
}
41+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
3+
<templates xml:space="preserve">
4+
5+
<t t-name="awesome_dashboard.AwesomeDashboardConfigDialog">
6+
<Dialog size="'md'" title.translate="Dashboard Items Configuration">
7+
<div class="d-flex flex-column gap-2">
8+
<div class="form-check" t-foreach="Object.entries(configItems)" t-as="entry" t-key="entry[0]">
9+
<t t-set="key" t-value="entry[0]"/>
10+
<t t-set="item" t-value="entry[1]"/>
11+
<input class="form-check-input" type="checkbox" t-att-checked="item.active" t-attf-id="awesome_dashboard_config_{{key}}" t-on-change="() => this.configItems[key].active = !this.configItems[key].active"/>
12+
<label class="form-check-label" t-attf-for="awesome_dashboard_config_{{key}}" t-esc="item.title"/>
13+
</div>
14+
<t t-set-slot="footer">
15+
<button class="btn btn-primary" t-on-click="onSave">Save</button>
16+
<button class="btn btn-secondary" t-on-click="props.close">Discard</button>
17+
</t>
18+
</div>
19+
</Dialog>
20+
</t>
21+
22+
</templates>

0 commit comments

Comments
 (0)