Skip to content

[IMP] awesome_owl: add counter component as sub component to playground #747

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: 18.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 25 additions & 3 deletions awesome_dashboard/static/src/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
/** @odoo-module **/

import { Component } from "@odoo/owl";
import { Component, useState } from "@odoo/owl";
import { registry } from "@web/core/registry";
import { Layout } from "@web/search/layout";
import { useService } from "@web/core/utils/hooks";
import { DashboardItem } from "./dashboarditem";
import { PieChart } from "./piechart";

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"));
}

openCustomersView() {
this.action.doAction("base.action_partner_form");
}

async openLeadsView() {
this.action.doAction({
type: "ir.actions.act_window",
name: ("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: rgb(234, 243, 246);
}
50 changes: 49 additions & 1 deletion awesome_dashboard/static/src/dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,55 @@
<templates xml:space="preserve">

<t t-name="awesome_dashboard.AwesomeDashboard">
hello dashboard
<button t-on-click="openCustomersView">Customers</button>
<button t-on-click="openLeadsView">Leads</button>
<Layout display="{controlPanel: {} }" className="'o_dashboard h-100'">
<DashboardItem size="2">
<div style="text-align: center;">
<h4>Number of new orders this month</h4>
<h3 style="color: green;">
<t t-esc="this.statistics.nb_new_orders"/>
</h3>
</div>
</DashboardItem>
<DashboardItem size="1">
<div style="text-align: center;">
<h4>Number of cancelled orders this month</h4>
<h3 style="color: green;">
<t t-esc="this.statistics.nb_cancelled_orders"/>
</h3>
</div>
</DashboardItem>
<DashboardItem size="1">
<div style="text-align: center;">
<h4>Average amount of t-shirt by order this month</h4>
<h3 style="color: green;">
<t t-esc="this.statistics.average_quantity"/>
</h3>
</div>
</DashboardItem>
<DashboardItem size="2">
<div style="text-align: center;">
<h4>Average time for an order to go from ‘new’ to ‘sent’ or ‘cancelled’</h4>
<h3 style="color: green;">
<t t-esc="this.statistics.average_time"/>
</h3>
</div>
</DashboardItem>
<DashboardItem size="3">
<div style="text-align: center;">
<h4>Total amount of new orders this month</h4>
<h3 style="color: green;">
<t t-esc="this.statistics.total_amount"/>
</h3>
</div>
</DashboardItem>
<DashboardItem size="2">
<div style="text-align: center;">
<PieChart data="this.statistics"/>
</div>
</DashboardItem>
</Layout>
</t>

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

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

<t t-name="awesome_dashboard.dashboarditem">
<div class="card d-inline-block m-2" t-attf-style="width: {{18*props.size}}rem;">
<div class="card-body">
<t t-slot="default"/>
</div>
</div>
</t>
</templates>
34 changes: 34 additions & 0 deletions awesome_dashboard/static/src/piechart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Component, onWillStart, onMounted, onWillUnmount, useRef } from "@odoo/owl"
import { loadJS } from "@web/core/assets"
import { getColor } from "@web/core/colors/colors"

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

setup() {
this.canvasRef = useRef("canvas");
onWillStart(() => loadJS("/web/static/lib/Chart/Chart.js"));
onMounted(() => this.renderChart());
onWillUnmount(() => this.chart.destroy());
}

renderChart() {
const chartLabels = Object.keys(this.props.data.orders_by_size)
this.chart = new Chart(this.canvasRef.el, {
type: 'pie',
data: {
labels: chartLabels,
datasets: [
{
label: "Sizes Chart",
data: Object.values(this.props.data.orders_by_size),
backgroundColor: chartLabels.map((_, index) => getColor(index)),
}
]
}
});
}
}
7 changes: 7 additions & 0 deletions awesome_dashboard/static/src/piechart.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_dashboard.piechart">
<canvas t-ref="canvas"/>
</t>
</templates>
17 changes: 17 additions & 0 deletions awesome_dashboard/static/src/statistics_service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { registry } from "@web/core/registry";
import { rpc } from "@web/core/network/rpc";
import { memoize } from "@web/core/utils/functions";

async function loadStatistics() {
const memoizedRpc = memoize(rpc);
const statistics = await memoizedRpc("/awesome_dashboard/statistics");
return statistics;
}

export const statisticsService = {
async start() {
return await loadStatistics();
},
}

registry.category("services").add("awesome_dashboard.statistics", statisticsService);
17 changes: 17 additions & 0 deletions awesome_owl/static/src/card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Component, useState } from "@odoo/owl"

export class Card extends Component {
static template = "awesome_owl.card";
static props = {
title: String,
slots: Object,
};

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

toggleState() {
this.state.isOpen = !this.state.isOpen;
}
}
17 changes: 17 additions & 0 deletions awesome_owl/static/src/card.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?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="border:1px solid black; width: 18rem;">
<div class="card-body">
<h5 class="card-title">
<t t-esc="props.title"/>
<button style="border:0.5px solid purple;" class="btn btn-primary" t-on-click="toggleState">Hide/Show</button>
</h5>
<p class="card-text" t-if="state.isOpen">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better practice to have t-if first

Suggested change
<p class="card-text" t-if="state.isOpen">
<p t-if="state.isOpen" class="card-text">

<t t-slot="default"/>
</p>
</div>
</div>
</t>
</templates>
17 changes: 17 additions & 0 deletions awesome_owl/static/src/counter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Component, useState } 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++;
this.props.onChange();
}
}
12 changes: 12 additions & 0 deletions awesome_owl/static/src/counter.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed as this xml is parsed by either Owl or Qweb which already use UTF-8

Suggested change
<?xml version="1.0" encoding="UTF-8" ?>
<?xml version="1.0" ?>

<templates xml:space="preserve">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed

Suggested change
<templates xml:space="preserve">
<templates>


<t t-name="awesome_owl.counter">
<div style="border:1px solid black; width: 10rem;">Hello World

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline styles are not encouraged. You may either use Bootstrap classes directly or create your custom classes and use them.

<p>Counter: <t t-esc="state.value"/>
</p>
<button style="border:0.5px solid black;" class="btn btn-primary" t-on-click="increment">Increment</button>
</div>
</t>

</templates>
19 changes: 16 additions & 3 deletions awesome_owl/static/src/playground.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
/** @odoo-module **/

import { Component } from "@odoo/owl";
import { Component, useState, markup } from "@odoo/owl";
import { Counter } from "./counter";
import { Card } from "./card";
import { TodoList } from "./todolist";

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

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

card1Content = markup("<div>Some Text in div Tag</div>");
card2Content = "<div>Some Text in div Tag</div>";

incrementSum() {
this.state.sum++;
}
}
12 changes: 9 additions & 3 deletions awesome_owl/static/src/playground.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
<templates xml:space="preserve">

<t t-name="awesome_owl.playground">
<div class="p-3">
hello world
</div>
<p>Counters Sum: <t t-esc="state.sum"/>
</p>
<Card title="'Card 1'">
<Counter onChange.bind="incrementSum"></Counter>
</Card>
<Card title="'Card 2'">
<Counter onChange.bind="incrementSum"></Counter>
</Card>
<TodoList/>
</t>

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

export class TodoItem extends Component {
static template = "awesome_owl.todoitem";
static props = {
todo: Object,
onToggleState: Function,
onRemoveTodo: Function,
}
}
12 changes: 12 additions & 0 deletions awesome_owl/static/src/todoitem.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_owl.todoitem">
<input type="checkbox" t-on-change="() => props.onToggleState(props.todo.id)"/>
<div t-att-class="{'text-muted': props.todo.isCompleted, 'text-decoration-line-through': props.todo.isCompleted}">
<t t-out="props.todo.id + '. ' + props.todo.description"/>
</div>
<span t-on-click="() => props.onRemoveTodo(props.todo.id)" class="fa fa-remove"></span>
</t>

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

export class TodoList extends Component {
static template = "awesome_owl.todolist";
static components = { TodoItem };

setup() {
this.state = useState({
todos: [],
idCounter: 0,
});
useAutofocus("input_todo");
};

addTodo(ev) {
if (ev.keyCode === 13) {
this.state.idCounter++
this.state.todos.push({
"id": this.state.idCounter, "description": ev.target.value, "isCompleted": false
});
ev.target.value = "";
}
};

toggleState(todoId) {
const todo = this.state.todos.find(todo => todo.id === todoId);
todo.isCompleted = !todo.isCompleted;
}

removeTodo(todoId) {
const index = this.state.todos.findIndex(todo => todo.id === todoId);
if (index >= 0) {
this.state.todos.splice(index, 1);
}
}
}
14 changes: 14 additions & 0 deletions awesome_owl/static/src/todolist.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_owl.todolist">
<br/>
<input t-ref="input_todo" t-on-keyup="ev => this.addTodo(ev)" type="text" placeholder="Enter a new task"/>
<t t-foreach="state.todos" t-as="todo" t-key="todo.id">
<div style="border: 1px solid black">
<TodoItem todo="todo" onToggleState.bind="toggleState" onRemoveTodo.bind="removeTodo"/>
</div>
</t>
</t>

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

export function useAutofocus(refName) {
let ref = useRef(refName);
useEffect(
(el) => el && el.focus(),
() => [ref.el]
);
}