Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
748a2b7
[ADD] estate:taskv
tskv Nov 18, 2025
07ee005
[ADD] estate: init
tskv Nov 18, 2025
0db978f
[IMP] new model: estate_property
tskv Nov 18, 2025
b78f9c1
[IMP] estate_property:new fields
tskv Nov 18, 2025
c66d2ad
[IMP] estate: access rights
tskv Nov 18, 2025
821328f
[IMP] estate: menu + view form
tskv Nov 18, 2025
afec0e3
[IMP] estate: chapter 6 (views)
tskv Nov 19, 2025
b87b0a4
[IMP] estate: chapter 7 (relational fields)
tskv Nov 19, 2025
ae44645
[IMP] estate: chapter 8 (compute and onchange)
tskv Nov 19, 2025
898c085
[IMP] estate: chapter 9 (actions)
tskv Nov 19, 2025
347453f
[IMP] estate: chapter 10 (constraints)
tskv Nov 19, 2025
d490741
[IMP] estate: chapter11 (sprinkles)
tskv Nov 20, 2025
220923d
[IMP] estate: chapter 12 (inheritance)
tskv Nov 20, 2025
b722b3e
[ADD] estate: invoicing (chapter 13)
tskv Nov 20, 2025
64e100c
[ADD] estate: kanban view (chapter 14)
tskv Nov 21, 2025
03cee0d
[IMP] estate: chapter 15
tskv Nov 21, 2025
61dd212
[ADD] awsome_owl: task 1 + 2
tskv Nov 24, 2025
527af1f
[ADD] awsome_owl: task 3 (card)
tskv Nov 24, 2025
fceec12
[IMP] awsome_owl: task 4 (markup)
tskv Nov 24, 2025
0135233
[IMP] estate: corretions after code review
tskv Nov 24, 2025
09aff26
[IMP] awesome_owl: task 7 (todo list v1)
tskv Nov 24, 2025
16065f8
[IMP] awesome_owl: tasks 8-12 (todo list)
tskv Nov 25, 2025
5f3af82
[IMP] awesome_owl: task 13-14 (slots and toggle in cards)
tskv Nov 25, 2025
647c006
[ADD] awesome_dashboard: tasks 1-3
tskv Nov 25, 2025
67e8dc2
[ADD] estate: master_data and demo_data
tskv Nov 25, 2025
ddd9e28
[ADD] awesome_dashboard: task 4 (statistics)
tskv Nov 26, 2025
f233d5c
[IMP] awesome_dashboard: task 5
tskv Nov 26, 2025
66c4d7b
[IMP] awesome_dashboard: task 6 (pie chart)
tskv Nov 27, 2025
cd24f13
[IMP] awesome_dashboard: task 7
tskv Nov 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion awesome_dashboard/controllers/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,3 @@ def get_statistics(self):
},
'total_amount': random.randint(100, 1000)
}

31 changes: 29 additions & 2 deletions awesome_dashboard/static/src/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,35 @@
import { Component } from "@odoo/owl";
import { registry } from "@web/core/registry";
import {Component, onWillStart, useState} from "@odoo/owl";
import {registry} from "@web/core/registry";
import {Layout} from "@web/search/layout";
import {useService} from "@web/core/utils/hooks"
import {_t} from "@web/core/l10n/translation";
import {DashboardItem} from "./dashboard_item/dashboard_item";
import {PieChart} from "./pie_chart/pie_chart";

class AwesomeDashboard extends Component {
static template = "awesome_dashboard.AwesomeDashboard";
static components = { Layout, DashboardItem, PieChart };

setup() {
this.action = useService("action");
this.statistics = useState(useService("awesome_dashboard.statistics"));
this.stat_data = this.statistics['orders_by_size'];
}

openCustomers() {
this.action.doAction("base.action_partner_form")
}

openLeads() {
this.action.doAction({
type: 'ir.actions.act_window',
name: _t('CRM Leads'),
target: 'current',
res_model: 'crm.lead',
views: [[false, 'list'],[false, 'form']],
})
}

}

registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard);
3 changes: 3 additions & 0 deletions awesome_dashboard/static/src/dashboard.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.o_dashboard {
background-color: slategrey;
}
46 changes: 45 additions & 1 deletion awesome_dashboard/static/src/dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,51 @@
<templates xml:space="preserve">

<t t-name="awesome_dashboard.AwesomeDashboard">
hello dashboard
<Layout display="{controlPanel: {} }" className="'o_dashboard h-100'">

<t t-set-slot="layout-buttons">
<button class="btn btn-primary" t-on-click="openCustomers">Customers</button>
<button class="btn btn-primary" t-on-click="openLeads">Leads</button>
</t>

<div class="d-flex flex-wrap">
<DashboardItem>
<t t-set-slot="title">
New orders
</t>
<t t-set-slot="number">
<t t-out="statistics.nb_new_orders"/>
</t>
</DashboardItem>

<DashboardItem>
<t t-set-slot="title">
Total amount
</t>
<t t-set-slot="number">
<t t-out="statistics.total_amount"/>
</t>
</DashboardItem>

<DashboardItem>
<t t-set-slot="title">
Average time
</t>
<t t-set-slot="number">
<t t-out="statistics.average_time"/>
</t>
</DashboardItem>

<DashboardItem size="1.5">
<t t-set-slot="title">
Orders by size
</t>
<PieChart pieChartData="statistics.orders_by_size"/>
</DashboardItem>

</div>

</Layout>
</t>

</templates>
18 changes: 18 additions & 0 deletions awesome_dashboard/static/src/dashboard_item/dashboard_item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Component } from "@odoo/owl";

export class DashboardItem extends Component {
static template = "awesome_dashboard.DashboardItem";
static props = {
slots : {
type: Object,
optional: true
},
size : {
type: Number,
optional: true,
},
};
static defaultProps = {
size: 1,
};
}
16 changes: 16 additions & 0 deletions awesome_dashboard/static/src/dashboard_item/dashboard_item.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_dashboard.DashboardItem">
<div class="card m-3 p-1" t-attf-style="width: {{18 * props.size }}rem;">
<div class="card-title fs-3 mt-3 text-center">
<t t-slot="title"/>
</div>
<div class="card-body fs-1 fw-bold text-success text-center">
<t t-slot="number"/>
</div>
<t t-slot="default"/>
</div>
</t>

</templates>
32 changes: 32 additions & 0 deletions awesome_dashboard/static/src/pie_chart/pie_chart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Component, onWillStart, useRef, onMounted } from "@odoo/owl";
import { loadJS } from "@web/core/assets";

export class PieChart extends Component {
static template = "awesome_dashboard.PieChart";
static props = {
pieChartData: Object,
}

setup() {
this.canva = useRef("canva");
onWillStart(() => loadJS(["/web/static/lib/Chart/Chart.js"]));
onMounted( () => this.renderChart() );
}

renderChart() {
const labels = Object.keys(this.props.pieChartData);
const values = Object.values(this.props.pieChartData);
this.myPieChart = new Chart(this.canva.el, {
type: 'pie',
data: {
labels,
datasets: [
{
data: values,
}
]
},
})
}

}
8 changes: 8 additions & 0 deletions awesome_dashboard/static/src/pie_chart/pie_chart.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_dashboard.PieChart">
<canvas t-ref="canva"/>
</t>

</templates>
22 changes: 22 additions & 0 deletions awesome_dashboard/static/src/statistics_service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { registry } from "@web/core/registry";
import { rpc } from "@web/core/network/rpc";
import { reactive } from "@odoo/owl";

const statisticsService = {

start() {
const statistics = reactive ( { changed: false } );

async function loadStatistics () {
const updates = await rpc("/awesome_dashboard/statistics", {});
Object.assign(statistics, updates, {changed: true} );
}

setInterval(loadStatistics, 1*60*1000);
loadStatistics();

return statistics;
}
}

registry.category("services").add("awesome_dashboard.statistics", statisticsService);
2 changes: 2 additions & 0 deletions awesome_owl/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@
'assets': {
'awesome_owl.assets_playground': [
('include', 'web._assets_helpers'),
('include', 'web._assets_backend_helpers'),
'web/static/src/scss/pre_variables.scss',
'web/static/lib/bootstrap/scss/_variables.scss',
'web/static/lib/bootstrap/scss/_maps.scss',
('include', 'web._assets_bootstrap'),
('include', 'web._assets_core'),
'web/static/src/libs/fontawesome/css/font-awesome.css',
Expand Down
19 changes: 19 additions & 0 deletions awesome_owl/static/src/card/card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useState, Component } from "@odoo/owl";

export class Card extends Component {
static template = "awesome_owl.Card";

static props = {
title : { type: String },
slots : { type: Object, optional: true }
}

setup() {
this.state = useState({ isOpen: true })
}

toggle() {
this.state.isOpen = !this.state.isOpen;
}

}
18 changes: 18 additions & 0 deletions awesome_owl/static/src/card/card.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_owl.Card">
<div class="card d-inline-block m-2" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">
<t t-out="props.title"/>
<button class="btn btn-primary" t-on-click="toggle">Toggle</button>
</h5>
<p class="card-text" t-if="state.isOpen">
<t t-slot="default"/>
</p>
</div>
</div>
</t>

</templates>
20 changes: 20 additions & 0 deletions awesome_owl/static/src/counter/counter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useState, Component } from "@odoo/owl";

export class Counter extends Component {
static template = "awesome_owl.Counter";
static props = {
onChange: { type: Function, optional: true }
}

setup() {
this.state = useState({ value: 0 });
}

increment() {
this.state.value++;
if (this.props.onChange) {
this.props.onChange();
}
}

}
9 changes: 9 additions & 0 deletions awesome_owl/static/src/counter/counter.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_owl.Counter">
<p>Counter: <t t-esc="state.value"/></p>
<button class="btn btn-primary" t-on-click="increment">Increment</button>
</t>

</templates>
19 changes: 17 additions & 2 deletions awesome_owl/static/src/playground.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import { Component } from "@odoo/owl";
import { Component, useState, markup } from "@odoo/owl";
import { Counter } from "./counter/counter"
import { Card } from "./card/card";
import { TodoList } from "./todo_list/todo_list";

export class Playground extends Component {
static template = "awesome_owl.playground";
static template = "awesome_owl.Playground";
static components = { Counter, Card, TodoList };

setup() {
this.value1 = "<div class='text-primary'>test</div>";
this.value2 = markup("<a href='http://odoo.com'>test2</a>");
this.state = useState({ sum : 0 });
}

implementSum() {
this.state.sum++;
}

}
26 changes: 25 additions & 1 deletion awesome_owl/static/src/playground.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_owl.playground">
<t t-name="awesome_owl.Playground">
<div class="p-3">
hello world
</div>
<div>
<Counter onChange.bind="implementSum"/>
<Counter onChange.bind="implementSum"/>
</div>
<div>
<Card title="'card 1'">
<t t-out="value1"/>
</Card>
<Card title="'card 2'">
<t t-out="value2"/>
</Card>
</div>
<div>
<Card title="'card 3'">
<Counter onChange.bind="implementSum"/>
</Card>
</div>
<div>
The sum is: <t t-esc="state.sum"/>
</div>
<p></p>
<div>
<TodoList/>
</div>
</t>

</templates>
21 changes: 21 additions & 0 deletions awesome_owl/static/src/todo_list/todo_item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Component, useState } from "@odoo/owl"

export class TodoItem extends Component {
static template = "awesome_owl.TodoItem";

static props = {
todo : {
id: Number,
description: String,
isCompleted: Boolean },
onClick : { Type: Function, optional : true }
};

toggleState() {
this.props.todo.isCompleted = !this.props.todo.isCompleted;
}

removeTodo() {
this.props.onClick(this.props.todo.id);
}
}
15 changes: 15 additions & 0 deletions awesome_owl/static/src/todo_list/todo_item.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_owl.TodoItem">
<div>
<p t-att-class="props.todo.isCompleted ? 'text-muted text-decoration-line-through' : ''">
<input type="checkbox" t-att-checked="props.todo.isCompleted" t-on-change="toggleState"/>
<t t-out="props.todo.id"/>.
<t t-out="props.todo.description"/>
<span class="fa fa-remove text-danger" t-on-click="removeTodo"/>
</p>
</div>
</t>

</templates>
Loading