add todo app module
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import controllers
|
||||
from . import models
|
||||
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': "Odoo OWL App",
|
||||
|
||||
'summary': """
|
||||
A test app to learn owl framework""",
|
||||
|
||||
'description': """
|
||||
Implementation of an app using owl with odoo
|
||||
""",
|
||||
|
||||
'author': "odooers",
|
||||
'website': "https://www.odooers.ir",
|
||||
|
||||
# Categories can be used to filter modules in modules listing
|
||||
# Check https://github.com/odoo/odoo/blob/16.0/odoo/addons/base/data/ir_module_category_data.xml
|
||||
# for the full list
|
||||
'category': 'Tutorial',
|
||||
'version': '0.1',
|
||||
|
||||
# any module necessary for this one to work correctly
|
||||
'depends': ['base','theme_common'],
|
||||
|
||||
# always loaded
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'data/sequences.xml',
|
||||
'views/views.xml',
|
||||
'views/templates.xml',
|
||||
],
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
'web/static/src/xml/**/*',
|
||||
],
|
||||
'web.assets_common': [
|
||||
'web/static/lib/bootstrap/**/*',
|
||||
],
|
||||
'todo_app.assets': [
|
||||
# required for fa icons
|
||||
'web/static/src/libs/fontawesome/css/font-awesome.css',
|
||||
|
||||
# Bootstrap dependencies
|
||||
('include', 'web._assets_helpers'),
|
||||
'web/static/src/scss/pre_variables.scss',
|
||||
'web/static/lib/bootstrap/scss/_variables.scss',
|
||||
|
||||
# Your custom SCSS files
|
||||
'todo_app/static/src/scss/primary_variables.scss',
|
||||
'todo_app/static/src/scss/bootstrap_overridden.scss',
|
||||
|
||||
# Core assets
|
||||
('include', 'web._assets_bootstrap'),
|
||||
('include', 'web._assets_core'),
|
||||
'todo_app/static/src/todo_app/**/*',
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
from . import controllers
|
||||
@@ -0,0 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import http
|
||||
from odoo.http import request, route, Controller
|
||||
|
||||
class OwlApp(Controller):
|
||||
@http.route(['/owl-app'], type='http', auth='public')
|
||||
def root(self):
|
||||
return request.render('todo_app.root')
|
||||
@@ -0,0 +1,12 @@
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- Sequences for todo_app.todo -->
|
||||
<record id="sequence_todo" model="ir.sequence">
|
||||
<field name="name">Todo Sequence</field>
|
||||
<field name="code">todo_app.todo</field>
|
||||
<field name="prefix">TD</field>
|
||||
<field name="padding">5</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
@@ -0,0 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
|
||||
|
||||
class OwlApp(models.Model):
|
||||
_name = 'todo_app.todo'
|
||||
_description = 'Odoo OWL App Todo'
|
||||
name = fields.Char(string='Todo Reference', copy=False, readonly=True, index=True, default=lambda self: _('New'))
|
||||
text = fields.Char()
|
||||
is_completed = fields.Boolean()
|
||||
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code('todo_app.todo') # todo_app.todo is code value
|
||||
return super(OwlApp, self).create(vals)
|
||||
@@ -0,0 +1,2 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_todo_app,todo_app.todo,model_todo_app_todo,base.group_user,1,1,1,1
|
||||
|
@@ -0,0 +1,12 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { whenReady, } from "@odoo/owl";
|
||||
import { mountComponent } from "@web/env";
|
||||
import { templates } from "@web/core/assets";
|
||||
import { Root } from "./root";
|
||||
|
||||
whenReady(() => mountComponent(Root, document.querySelector('#root'), {
|
||||
templates,
|
||||
dev: true,
|
||||
name: "Owl Demo App",
|
||||
}));
|
||||
@@ -0,0 +1,16 @@
|
||||
<svg width="126" height="48" viewBox="0 0 126 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M49 17.1818V22.8636H34.625V17.1818H49ZM37.4091 11.9545H45.25V31.983C45.25 32.286 45.3021 32.5417 45.4062 32.75C45.5104 32.9489 45.6714 33.1004 45.8892 33.2045C46.107 33.2992 46.3864 33.3466 46.7273 33.3466C46.964 33.3466 47.2386 33.3182 47.5511 33.2614C47.8731 33.2045 48.1098 33.1572 48.2614 33.1193L49.3977 38.6307C49.0473 38.7348 48.5455 38.8627 47.892 39.0142C47.2481 39.1657 46.4811 39.2652 45.5909 39.3125C43.7917 39.4072 42.2813 39.2225 41.0597 38.7585C39.8381 38.285 38.9195 37.5417 38.304 36.5284C37.6884 35.5152 37.3902 34.2462 37.4091 32.7216V11.9545ZM62.4766 39.3977C60.1091 39.3977 58.0826 38.929 56.397 37.9915C54.7114 37.0445 53.4188 35.7282 52.5192 34.0426C51.6196 32.3475 51.1697 30.3826 51.1697 28.1477C51.1697 25.9129 51.6196 23.9527 52.5192 22.267C53.4188 20.572 54.7114 19.2557 56.397 18.3182C58.0826 17.3712 60.1091 16.8977 62.4766 16.8977C64.844 16.8977 66.8705 17.3712 68.5561 18.3182C70.2417 19.2557 71.5343 20.572 72.4339 22.267C73.3336 23.9527 73.7834 25.9129 73.7834 28.1477C73.7834 30.3826 73.3336 32.3475 72.4339 34.0426C71.5343 35.7282 70.2417 37.0445 68.5561 37.9915C66.8705 38.929 64.844 39.3977 62.4766 39.3977ZM62.5334 33.6023C63.1963 33.6023 63.7692 33.3797 64.2521 32.9347C64.7351 32.4896 65.1091 31.8551 65.3743 31.0312C65.6394 30.2074 65.772 29.2273 65.772 28.0909C65.772 26.9451 65.6394 25.965 65.3743 25.1506C65.1091 24.3267 64.7351 23.6922 64.2521 23.2472C63.7692 22.8021 63.1963 22.5795 62.5334 22.5795C61.8326 22.5795 61.2313 22.8021 60.7294 23.2472C60.2275 23.6922 59.844 24.3267 59.5788 25.1506C59.3137 25.965 59.1811 26.9451 59.1811 28.0909C59.1811 29.2273 59.3137 30.2074 59.5788 31.0312C59.844 31.8551 60.2275 32.4896 60.7294 32.9347C61.2313 33.3797 61.8326 33.6023 62.5334 33.6023Z" fill="#4EA8DE"/>
|
||||
<path d="M84.8629 39.2841C83.3099 39.2841 81.88 38.8769 80.5732 38.0625C79.2758 37.2481 78.2341 36.0123 77.4482 34.3551C76.6716 32.6979 76.2834 30.6098 76.2834 28.0909C76.2834 25.4583 76.6906 23.3182 77.505 21.6705C78.3288 20.0227 79.3894 18.8153 80.6868 18.0483C81.9936 17.2812 83.3667 16.8977 84.8061 16.8977C85.8857 16.8977 86.8326 17.0871 87.647 17.4659C88.4614 17.8352 89.1432 18.3324 89.6925 18.9574C90.2417 19.5729 90.6584 20.25 90.9425 20.9886H91.0561V9.90909H98.897V39H91.1129V35.4205H90.9425C90.6394 36.1591 90.2038 36.822 89.6357 37.4091C89.0769 37.9867 88.3951 38.446 87.5902 38.7869C86.7947 39.1184 85.8857 39.2841 84.8629 39.2841ZM87.7607 33.2614C88.4804 33.2614 89.0959 33.053 89.6072 32.6364C90.1281 32.2102 90.5258 31.6136 90.8004 30.8466C91.0845 30.0701 91.2266 29.1515 91.2266 28.0909C91.2266 27.0114 91.0845 26.0881 90.8004 25.321C90.5258 24.5445 90.1281 23.9527 89.6072 23.5455C89.0959 23.1288 88.4804 22.9205 87.7607 22.9205C87.041 22.9205 86.4254 23.1288 85.9141 23.5455C85.4122 23.9527 85.0239 24.5445 84.7493 25.321C84.4841 26.0881 84.3516 27.0114 84.3516 28.0909C84.3516 29.1705 84.4841 30.0985 84.7493 30.875C85.0239 31.642 85.4122 32.2339 85.9141 32.6506C86.4254 33.0578 87.041 33.2614 87.7607 33.2614ZM113.258 39.3977C110.89 39.3977 108.864 38.929 107.178 37.9915C105.493 37.0445 104.2 35.7282 103.3 34.0426C102.401 32.3475 101.951 30.3826 101.951 28.1477C101.951 25.9129 102.401 23.9527 103.3 22.267C104.2 20.572 105.493 19.2557 107.178 18.3182C108.864 17.3712 110.89 16.8977 113.258 16.8977C115.625 16.8977 117.652 17.3712 119.337 18.3182C121.023 19.2557 122.316 20.572 123.215 22.267C124.115 23.9527 124.565 25.9129 124.565 28.1477C124.565 30.3826 124.115 32.3475 123.215 34.0426C122.316 35.7282 121.023 37.0445 119.337 37.9915C117.652 38.929 115.625 39.3977 113.258 39.3977ZM113.315 33.6023C113.978 33.6023 114.55 33.3797 115.033 32.9347C115.516 32.4896 115.89 31.8551 116.156 31.0312C116.421 30.2074 116.553 29.2273 116.553 28.0909C116.553 26.9451 116.421 25.965 116.156 25.1506C115.89 24.3267 115.516 23.6922 115.033 23.2472C114.55 22.8021 113.978 22.5795 113.315 22.5795C112.614 22.5795 112.013 22.8021 111.511 23.2472C111.009 23.6922 110.625 24.3267 110.36 25.1506C110.095 25.965 109.962 26.9451 109.962 28.0909C109.962 29.2273 110.095 30.2074 110.36 31.0312C110.625 31.8551 111.009 32.4896 111.511 32.9347C112.013 33.3797 112.614 33.6023 113.315 33.6023Z" fill="#5E60CE"/>
|
||||
<g clip-path="url(#clip0_12_482)">
|
||||
<path d="M11.0214 12.933C14.1471 16.9011 15.8156 21.7944 15.7551 26.8155V28.0141L16.7864 28.6416C18.1188 29.4482 19.1126 30.6993 19.5865 32.1669C19.1704 31.8605 18.7351 31.5803 18.2831 31.3278L15.5331 29.7838L15.039 32.9001C14.9962 33.1755 14.9388 33.4485 14.8671 33.718H7.16138C7.0468 33.3655 6.9537 33.0129 6.86776 32.6463L6.24472 29.8261L3.70956 31.2362C3.28603 31.473 2.87711 31.7344 2.48495 32.0188C2.96812 30.5682 3.94111 29.3242 5.24211 28.4935L6.22323 27.866V26.7521C6.24093 21.7513 7.92955 16.8952 11.0286 12.933H11.0214ZM11.0286 10C10.8679 10.0004 10.7127 10.058 10.5917 10.1622L10.5273 10.2186C6.39766 14.7656 4.10454 20.6454 4.08196 26.745C2.32955 27.8643 1.03238 29.5543 0.417141 31.5197C-0.198101 33.485 -0.0922939 35.6007 0.716072 37.4971C1.56764 35.6455 2.99119 34.1058 4.78378 33.0975C4.96356 33.8642 5.20298 34.6161 5.49993 35.3467C5.53759 35.4871 5.62106 35.6114 5.73751 35.7006C5.85396 35.7898 5.99694 35.8388 6.14446 35.8402H16.0846C16.2851 35.8402 16.4856 35.6498 16.5859 35.3537C16.8757 34.6592 17.0777 33.9322 17.1874 33.1892C18.9834 34.1932 20.4082 35.7342 21.2551 37.5887C22.1123 35.7017 22.245 33.5727 21.6286 31.5967C21.0123 29.6206 19.6887 27.9319 17.9036 26.8437C17.9744 20.7082 15.6934 14.7718 11.5156 10.2186C11.4533 10.1501 11.3772 10.0952 11.2921 10.0576C11.2069 10.0199 11.1147 10.0003 11.0214 10H11.0286Z" fill="#4EA8DE"/>
|
||||
<path d="M11.0213 26.1598C10.4713 26.1598 9.93351 25.9995 9.47587 25.699C9.01822 25.3986 8.66116 24.9715 8.44969 24.4716C8.23822 23.9716 8.18181 23.4213 8.28758 22.8898C8.39334 22.3584 8.65653 21.8697 9.04399 21.4853C9.43144 21.1009 9.92582 20.838 10.4648 20.7298C11.0038 20.6216 11.5632 20.6729 12.0726 20.8773C12.582 21.0816 13.0186 21.4298 13.3272 21.8781C13.6359 22.3263 13.8029 22.8545 13.8071 23.396C13.8157 23.7469 13.7539 24.0961 13.6254 24.4235C13.4969 24.751 13.304 25.0503 13.058 25.3043C12.8119 25.5583 12.5174 25.7622 12.1913 25.9041C11.8652 26.0461 11.5139 26.1234 11.1574 26.1316C11.1123 26.1387 11.0664 26.1387 11.0213 26.1316V26.1598Z" fill="#4EA8DE"/>
|
||||
<path d="M14.8957 37.5958C14.7165 37.5901 14.538 37.6198 14.3706 37.683C14.2032 37.7462 14.0503 37.8416 13.9209 37.9638C13.7915 38.086 13.6881 38.2323 13.6169 38.3943C13.5458 38.5563 13.5082 38.7307 13.5063 38.9072V43.067C13.5063 43.4297 13.6527 43.7776 13.9133 44.0342C14.1738 44.2907 14.5272 44.4348 14.8957 44.4348C15.2641 44.4348 15.6175 44.2907 15.8781 44.0342C16.1386 43.7776 16.285 43.4297 16.285 43.067V38.9636C16.2907 38.7877 16.2608 38.6126 16.1971 38.4482C16.1333 38.2839 16.037 38.1337 15.9137 38.0064C15.7904 37.879 15.6425 37.7772 15.4788 37.7067C15.3151 37.6362 15.1388 37.5985 14.9601 37.5958H14.8957Z" fill="#5E60CE"/>
|
||||
<path d="M7.1613 37.5958C6.97906 37.5863 6.79675 37.613 6.62521 37.6743C6.45367 37.7356 6.29641 37.8302 6.16278 37.9526C6.02915 38.0749 5.92188 38.2225 5.84736 38.3865C5.77284 38.5505 5.73259 38.7275 5.729 38.9072V43.067C5.729 43.4297 5.87538 43.7777 6.13593 44.0342C6.39648 44.2907 6.74986 44.4348 7.11833 44.4348C7.4868 44.4348 7.84018 44.2907 8.10073 44.0342C8.36128 43.7777 8.50765 43.4297 8.50765 43.067V38.9636C8.51337 38.7877 8.48349 38.6126 8.41974 38.4482C8.35599 38.2839 8.25965 38.1337 8.13634 38.0064C8.01302 37.879 7.8652 37.7772 7.70149 37.7067C7.53777 37.6362 7.36144 37.5985 7.18278 37.5958H7.1613Z" fill="#5E60CE"/>
|
||||
<path d="M10.9211 37.5958C10.7424 37.592 10.5647 37.623 10.3981 37.6869C10.2316 37.7507 10.0795 37.8463 9.95044 37.9681C9.82142 38.0899 9.71804 38.2355 9.6462 38.3966C9.57435 38.5577 9.53546 38.7312 9.53174 38.9072V44.6392C9.53174 45.002 9.67811 45.3499 9.93866 45.6064C10.1992 45.8629 10.5526 46.007 10.9211 46.007C11.2895 46.007 11.6429 45.8629 11.9035 45.6064C12.164 45.3499 12.3104 45.002 12.3104 44.6392V38.9988C12.3161 38.823 12.2862 38.6478 12.2225 38.4835C12.1587 38.3191 12.0624 38.1689 11.9391 38.0416C11.8158 37.9143 11.6679 37.8124 11.5042 37.7419C11.3405 37.6714 11.1642 37.6337 10.9855 37.631L10.9211 37.5958Z" fill="#5E60CE"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_12_482">
|
||||
<rect width="22" height="36" fill="white" transform="translate(0 10)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.2 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.0 KiB |
@@ -0,0 +1,29 @@
|
||||
/** @odoo-module **/
|
||||
import { Component, useState, useRef, onMounted } from "@odoo/owl";
|
||||
export class TodoForm extends Component {
|
||||
static template = "todo_app.todo_form";
|
||||
static props = ['handleCreate']
|
||||
setup() {
|
||||
this.state = useState({
|
||||
todo: {
|
||||
id: new Date().getTime(),
|
||||
text: '',
|
||||
is_completed: false
|
||||
},
|
||||
})
|
||||
this.ref = useRef('input');
|
||||
|
||||
this.handleSubmit = (ev) => {
|
||||
ev.preventDefault();
|
||||
if (this.state.todo.text) {
|
||||
this.props.handleCreate(this.state.todo);
|
||||
this.state.todo.text = ""
|
||||
this.ref.el.focus();
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
this.ref.el.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="todo_app.todo_form" owl="1">
|
||||
<div id="todo-form">
|
||||
<form class="d-flex" t-on-submit="handleSubmit">
|
||||
<input class="form-control ms-2" type="text" placeholder="Add a new task" t-model="state.todo.text" t-ref="input"/>
|
||||
<button class="btn btn-primary d-flex justify-content-center align-items-center" type="submit">Add
|
||||
<span class="fa fa-plus-circle me-1"></span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,26 @@
|
||||
/** @odoo-module **/
|
||||
import { Component, useState, useRef } from "@odoo/owl";
|
||||
export class Todo extends Component {
|
||||
static template = "todo_app.todo";
|
||||
static components = {};
|
||||
static props = ['todo', 'handleChangeState', 'handleEdit', 'handleRemove'];
|
||||
|
||||
setup() {
|
||||
this.state = useState({
|
||||
isEdit: false
|
||||
});
|
||||
this.ref = useRef("editInput");
|
||||
this.enableEditMode = () => {
|
||||
this.state.isEdit = true;
|
||||
setTimeout(() => {
|
||||
this.ref.el.focus();
|
||||
}, 100);
|
||||
}
|
||||
this.editTodo = (ev, id) => {
|
||||
if (ev.keyCode === 13 && ev.target.value !== "") {
|
||||
this.props.handleEdit(id, ev.target.value);
|
||||
this.state.isEdit = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
.todo {
|
||||
&.completed {
|
||||
.todo__content {
|
||||
text-decoration: line-through !important;
|
||||
color: $o-color-4;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
padding: .7rem;
|
||||
background-color: $o-color-5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="todo_app.todo" owl="1">
|
||||
<div t-attf-class="todo d-flex justify-content-between align-items-center gap-3 bg-secondary p-4 rounded my-3 {{props.todo.is_completed ? 'completed' : ''}}">
|
||||
<div class="todo__check">
|
||||
<input type="checkbox" t-att-checked="props.todo.is_completed" t-att-value="props.todo.id" t-on-change="props.handleChangeState" class="cursor-pointer" t-attf-id="todo-state-#{props.todo.id}"/>
|
||||
</div>
|
||||
<div class="todo__content flex-grow-1">
|
||||
<t t-if="state.isEdit">
|
||||
<input type="text" t-att-value="props.todo.text" class="form-control ms-2" t-on-keyup="(ev)=>editTodo(ev,props.todo.id)" t-ref="editInput"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<label t-attf-for="todo-state-#{props.todo.id}">
|
||||
<t t-esc="props.todo.text"/>
|
||||
</label>
|
||||
</t>
|
||||
</div>
|
||||
<div class="todo__action d-flex justify-content-between align-items-center gap-3">
|
||||
<span class="fa fa-pencil-square-o fa-lg text-primary text-opacity-75 cursor-pointer" t-on-click="enableEditMode"/>
|
||||
<span class="fa fa-trash-o fa-lg text-danger text-opacity-75 cursor-pointer" t-on-click="()=>props.handleRemove(props.todo.id)"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,13 @@
|
||||
/** @odoo-module **/
|
||||
import { Component } from "@odoo/owl";
|
||||
import { Todo } from "./todo/todo";
|
||||
export class Todos extends Component {
|
||||
static template = "todo_app.todos";
|
||||
static components = { Todo };
|
||||
static props = ['todos', 'handleChangeState', 'handleEdit', 'handleRemove'];
|
||||
|
||||
setup() {
|
||||
this.getTodosNumber = () => { return this.props.todos.length }
|
||||
this.getCompletedTodosNumber = () => { return this.props.todos.filter(todo => todo.is_completed).length }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
.todos {
|
||||
p {
|
||||
color: $o-color-4 !important;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="todo_app.todos" owl="1">
|
||||
<div class="todos my-5">
|
||||
<div class="todos__meta d-flex justify-content-between">
|
||||
<span>
|
||||
<span class="text-primary fw-bold">Tasks created:</span>
|
||||
<span class="badge badge bg-secondary rounded-pill me-2 fs-6" t-esc="getTodosNumber()"/>
|
||||
</span>
|
||||
<span>
|
||||
<span class="text-primary fw-bold">Completed:</span>
|
||||
<span class="badge badge bg-secondary rounded-pill me-2 fs-6">
|
||||
<t t-esc="getCompletedTodosNumber()"/> of
|
||||
<t t-esc="getTodosNumber()"/>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="todos__list">
|
||||
<t t-if="getTodosNumber()">
|
||||
<t t-foreach="props.todos" t-as="todo" t-key="todo.id">
|
||||
<Todo todo="todo" handleChangeState="props.handleChangeState" handleEdit="props.handleEdit" handleRemove="props.handleRemove"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="message d-flex flex-column justify-content-between align-items-center p-5">
|
||||
<img src="/todo_app/static/src/todo_app/assets/images/notodos.svg" class="mb-3"/>
|
||||
<p class="fw-bold">You don't have tasks registered yet</p>
|
||||
<p>Create tasks and organize your to-do items</p>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,8 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component } from "@odoo/owl";
|
||||
|
||||
export class Navbar extends Component {
|
||||
static template = "todo_app.navbar";
|
||||
static props = ['todosNumber'];
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="todo_app.navbar" owl="1">
|
||||
<div class="row">
|
||||
<nav class="navbar bg-body-tertiary col-12 justify-content-center my-5">
|
||||
<a class="navbar-brand" href="#">
|
||||
<img src="/todo_app/static/src/todo_app/assets/images/Logo.svg" alt="Logo" class="d-inline-block align-text-top"/>
|
||||
</a>
|
||||
<span class="fs-6 badge text-bg-primary rounded-pill me-2" t-esc="this.props.todosNumber"/>
|
||||
</nav>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,9 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component } from "@odoo/owl";
|
||||
import { Navbar } from "./Navbar/navbar";
|
||||
export class WebsiteLayout extends Component {
|
||||
static template = "todo_app.website_layout";
|
||||
static components = { Navbar };
|
||||
static props = { todosNumber: Number, slots: Object, };
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="todo_app.website_layout" owl="1">
|
||||
<div class="o-action container">
|
||||
<div class="o-content row justify-content-md-center" t-att-class="props.contentClass">
|
||||
<div class="col-12 col-md-7">
|
||||
<Navbar todosNumber="this.props.todosNumber"/>
|
||||
<t t-slot="default"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,50 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { Component, useState, onWillStart } from "@odoo/owl";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
|
||||
|
||||
import { WebsiteLayout } from "./layouts/website/layout"
|
||||
import { TodoForm } from "./components/todo_form/todo_form";
|
||||
import { Todos } from "./components/todos/todos";
|
||||
|
||||
export class Root extends Component {
|
||||
static template = "todo_app.root";
|
||||
static components = { WebsiteLayout, TodoForm, Todos };
|
||||
static props = {};
|
||||
|
||||
setup() {
|
||||
this.state = useState({ todos: [] });
|
||||
this.orm = useService("orm");
|
||||
this.model = 'todo_app.todo';
|
||||
|
||||
this.handleChangeState = async (event) => {
|
||||
const id = Number(event.target.value);
|
||||
await this.orm.write(this.model, [id], { is_completed: event.target.checked });
|
||||
this.getAllTodos();
|
||||
}
|
||||
|
||||
this.handleEdit = async (id, text) => {
|
||||
await this.orm.write(this.model, [id], { text });
|
||||
this.getAllTodos();
|
||||
}
|
||||
|
||||
this.handleRemove = async (id) => {
|
||||
await this.orm.unlink(this.model, [id]);
|
||||
this.getAllTodos();
|
||||
}
|
||||
|
||||
this.handleCreate = async (todo) => {
|
||||
await this.orm.create(this.model, [todo]);
|
||||
this.getAllTodos();
|
||||
}
|
||||
|
||||
this.getAllTodos = async () => {
|
||||
this.state.todos = await this.orm.searchRead(this.model, []);
|
||||
}
|
||||
|
||||
onWillStart(() => {
|
||||
this.getAllTodos();
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
body {
|
||||
// background: #0D0D0D;
|
||||
// color: white;
|
||||
}
|
||||
|
||||
#root {
|
||||
height: 100vh;
|
||||
|
||||
.btn {
|
||||
background-color: $o-color-3 !important;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="todo_app.root">
|
||||
<WebsiteLayout todosNumber="state.todos.length">
|
||||
<main>
|
||||
<TodoForm handleCreate="handleCreate"/>
|
||||
<Todos todos="state.todos" handleChangeState="handleChangeState" handleEdit="handleEdit" handleRemove="handleRemove"/>
|
||||
</main>
|
||||
</WebsiteLayout>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,11 @@
|
||||
@import 'bootstrap/scss/functions';
|
||||
@import 'bootstrap/scss/variables';
|
||||
@import 'bootstrap/scss/maps';
|
||||
@import 'bootstrap/scss/mixins';
|
||||
@import 'bootstrap/scss/utilities';
|
||||
|
||||
// Then define your theme colors
|
||||
$theme-colors: (
|
||||
"primary": $o-color-1,
|
||||
"secondary": $o-color-6
|
||||
);
|
||||
@@ -0,0 +1,19 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Global
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Fonts
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Colors
|
||||
//------------------------------------------------------------------------------
|
||||
$o-color-1: #4EA8DE;
|
||||
$o-color-2: #F2F2F2;
|
||||
$o-color-3: #5E60CE;
|
||||
$o-color-4: #808080;
|
||||
$o-color-5: #0D0D0D;
|
||||
$o-color-6: #262626;
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<template id="todo_app.root" name="OWL App Root">
|
||||
<html>
|
||||
<head>
|
||||
<t t-call-assets="todo_app.assets"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
</template>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,37 @@
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="record_action" model="ir.actions.act_window">
|
||||
<field name="name">Odoo OWL Todo Application</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">todo_app.todo</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
<record id="odoo_owl_todo_form" model="ir.ui.view">
|
||||
<field name="name">todo_app.todo.form</field>
|
||||
<field name="model">todo_app.todo</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="text"/>
|
||||
<field name="is_completed"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="odoo_owl_todo_list" model="ir.ui.view">
|
||||
<field name="name">todo_app.todo.list</field>
|
||||
<field name="model">todo_app.todo</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="text"/>
|
||||
<field name="is_completed"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem id="parent_menu_root" name="Odoo OWl">
|
||||
<menuitem id="menu_id" name="Todo Application" action="record_action" sequence="10"/>
|
||||
</menuitem>
|
||||
</data>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user