From 18b94f47ac1e81e424bd1d483e5449e94b8e6250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Sun, 9 Oct 2022 20:21:18 +0200 Subject: [PATCH 01/69] [ADD] Discover the JavaScript framework --- awesome_clicker/__init__.py | 1 + awesome_clicker/__manifest__.py | 29 ++++++++++ awesome_dashboard/__init__.py | 3 ++ awesome_dashboard/__manifest__.py | 30 +++++++++++ awesome_dashboard/controllers/__init__.py | 3 ++ awesome_dashboard/controllers/controllers.py | 36 +++++++++++++ awesome_dashboard/static/src/dashboard.js | 10 ++++ awesome_dashboard/static/src/dashboard.xml | 8 +++ awesome_dashboard/views/views.xml | 11 ++++ awesome_gallery/__init__.py | 2 + awesome_gallery/__manifest__.py | 26 +++++++++ awesome_gallery/models/__init__.py | 4 ++ awesome_gallery/models/ir_action.py | 10 ++++ awesome_gallery/models/ir_ui_view.py | 8 +++ awesome_gallery/static/src/gallery_view.js | 3 ++ awesome_gallery/views/views.xml | 19 +++++++ awesome_kanban/__init__.py | 1 + awesome_kanban/__manifest__.py | 26 +++++++++ .../static/src/awesome_kanban_view.js | 3 ++ awesome_kanban/views/views.xml | 15 ++++++ awesome_owl/__init__.py | 3 ++ awesome_owl/__manifest__.py | 54 +++++++++++++++++++ awesome_owl/controllers/__init__.py | 3 ++ awesome_owl/controllers/controllers.py | 10 ++++ awesome_owl/static/src/main.js | 41 ++++++++++++++ awesome_owl/static/src/playground.js | 7 +++ awesome_owl/static/src/playground.xml | 10 ++++ awesome_owl/views/templates.xml | 15 ++++++ 28 files changed, 391 insertions(+) create mode 100644 awesome_clicker/__init__.py create mode 100644 awesome_clicker/__manifest__.py create mode 100644 awesome_dashboard/__init__.py create mode 100644 awesome_dashboard/__manifest__.py create mode 100644 awesome_dashboard/controllers/__init__.py create mode 100644 awesome_dashboard/controllers/controllers.py create mode 100644 awesome_dashboard/static/src/dashboard.js create mode 100644 awesome_dashboard/static/src/dashboard.xml create mode 100644 awesome_dashboard/views/views.xml create mode 100644 awesome_gallery/__init__.py create mode 100644 awesome_gallery/__manifest__.py create mode 100644 awesome_gallery/models/__init__.py create mode 100644 awesome_gallery/models/ir_action.py create mode 100644 awesome_gallery/models/ir_ui_view.py create mode 100644 awesome_gallery/static/src/gallery_view.js create mode 100644 awesome_gallery/views/views.xml create mode 100644 awesome_kanban/__init__.py create mode 100644 awesome_kanban/__manifest__.py create mode 100644 awesome_kanban/static/src/awesome_kanban_view.js create mode 100644 awesome_kanban/views/views.xml create mode 100644 awesome_owl/__init__.py create mode 100644 awesome_owl/__manifest__.py create mode 100644 awesome_owl/controllers/__init__.py create mode 100644 awesome_owl/controllers/controllers.py create mode 100644 awesome_owl/static/src/main.js create mode 100644 awesome_owl/static/src/playground.js create mode 100644 awesome_owl/static/src/playground.xml create mode 100644 awesome_owl/views/templates.xml diff --git a/awesome_clicker/__init__.py b/awesome_clicker/__init__.py new file mode 100644 index 00000000000..40a96afc6ff --- /dev/null +++ b/awesome_clicker/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/awesome_clicker/__manifest__.py b/awesome_clicker/__manifest__.py new file mode 100644 index 00000000000..e57ef4d5bb0 --- /dev/null +++ b/awesome_clicker/__manifest__.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Awesome Clicker", + + 'summary': """ + Starting module for "Master the Odoo web framework, chapter 1: Build a Clicker game" + """, + + 'description': """ + Starting module for "Master the Odoo web framework, chapter 1: Build a Clicker game" + """, + + 'author': "Odoo", + 'website': "https://www.odoo.com/", + 'category': 'Tutorials/AwesomeClicker', + 'version': '0.1', + 'application': True, + 'installable': True, + 'depends': ['base', 'web'], + + 'data': [], + 'assets': { + 'web.assets_backend': [ + 'awesome_clicker/static/src/**/*', + ], + + }, + 'license': 'AGPL-3' +} diff --git a/awesome_dashboard/__init__.py b/awesome_dashboard/__init__.py new file mode 100644 index 00000000000..b0f26a9a602 --- /dev/null +++ b/awesome_dashboard/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers diff --git a/awesome_dashboard/__manifest__.py b/awesome_dashboard/__manifest__.py new file mode 100644 index 00000000000..31406e8addb --- /dev/null +++ b/awesome_dashboard/__manifest__.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Awesome Dashboard", + + 'summary': """ + Starting module for "Discover the JS framework, chapter 2: Build a dashboard" + """, + + 'description': """ + Starting module for "Discover the JS framework, chapter 2: Build a dashboard" + """, + + 'author': "Odoo", + 'website': "https://www.odoo.com/", + 'category': 'Tutorials/AwesomeDashboard', + 'version': '0.1', + 'application': True, + 'installable': True, + 'depends': ['base', 'web', 'mail', 'crm'], + + 'data': [ + 'views/views.xml', + ], + 'assets': { + 'web.assets_backend': [ + 'awesome_dashboard/static/src/**/*', + ], + }, + 'license': 'AGPL-3' +} diff --git a/awesome_dashboard/controllers/__init__.py b/awesome_dashboard/controllers/__init__.py new file mode 100644 index 00000000000..457bae27e11 --- /dev/null +++ b/awesome_dashboard/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers \ No newline at end of file diff --git a/awesome_dashboard/controllers/controllers.py b/awesome_dashboard/controllers/controllers.py new file mode 100644 index 00000000000..56d4a051287 --- /dev/null +++ b/awesome_dashboard/controllers/controllers.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- + +import logging +import random + +from odoo import http +from odoo.http import request + +logger = logging.getLogger(__name__) + +class AwesomeDashboard(http.Controller): + @http.route('/awesome_dashboard/statistics', type='json', auth='user') + def get_statistics(self): + """ + Returns a dict of statistics about the orders: + 'average_quantity': the average number of t-shirts by order + 'average_time': the average time (in hours) elapsed between the + moment an order is created, and the moment is it sent + 'nb_cancelled_orders': the number of cancelled orders, this month + 'nb_new_orders': the number of new orders, this month + 'total_amount': the total amount of orders, this month + """ + + return { + 'average_quantity': random.randint(4, 12), + 'average_time': random.randint(4, 123), + 'nb_cancelled_orders': random.randint(0, 50), + 'nb_new_orders': random.randint(10, 200), + 'orders_by_size': { + 'm': random.randint(0, 150), + 's': random.randint(0, 150), + 'xl': random.randint(0, 150), + }, + 'total_amount': random.randint(100, 1000) + } + diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js new file mode 100644 index 00000000000..637fa4bb972 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard.js @@ -0,0 +1,10 @@ +/** @odoo-module **/ + +import { Component } from "@odoo/owl"; +import { registry } from "@web/core/registry"; + +class AwesomeDashboard extends Component { + static template = "awesome_dashboard.AwesomeDashboard"; +} + +registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml new file mode 100644 index 00000000000..1a2ac9a2fed --- /dev/null +++ b/awesome_dashboard/static/src/dashboard.xml @@ -0,0 +1,8 @@ + + + + + hello dashboard + + + diff --git a/awesome_dashboard/views/views.xml b/awesome_dashboard/views/views.xml new file mode 100644 index 00000000000..47fb2b6f258 --- /dev/null +++ b/awesome_dashboard/views/views.xml @@ -0,0 +1,11 @@ + + + + Dashboard + awesome_dashboard.dashboard + + + + + + diff --git a/awesome_gallery/__init__.py b/awesome_gallery/__init__.py new file mode 100644 index 00000000000..a0fdc10fe11 --- /dev/null +++ b/awesome_gallery/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import models diff --git a/awesome_gallery/__manifest__.py b/awesome_gallery/__manifest__.py new file mode 100644 index 00000000000..a51f4e5d1c1 --- /dev/null +++ b/awesome_gallery/__manifest__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Gallery View", + 'summary': """ + Starting module for "Master the Odoo web framework, chapter 3: Create a Gallery View" + """, + + 'description': """ + Starting module for "Master the Odoo web framework, chapter 3: Create a Gallery View" + """, + + 'version': '0.1', + 'application': True, + 'category': 'Tutorials/AwesomeGallery', + 'installable': True, + 'depends': ['web', 'contacts'], + 'demo': [ + 'views/views.xml', + ], + 'assets': { + 'web.assets_backend': [ + 'awesome_gallery/static/src/**/*', + ], + }, + 'license': 'AGPL-3' +} diff --git a/awesome_gallery/models/__init__.py b/awesome_gallery/models/__init__.py new file mode 100644 index 00000000000..7f0930ee744 --- /dev/null +++ b/awesome_gallery/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# import filename_python_file_within_folder_or_subfolder +from . import ir_action +from . import ir_ui_view diff --git a/awesome_gallery/models/ir_action.py b/awesome_gallery/models/ir_action.py new file mode 100644 index 00000000000..eae20acbf5c --- /dev/null +++ b/awesome_gallery/models/ir_action.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +from odoo import fields, models + + +class ActWindowView(models.Model): + _inherit = 'ir.actions.act_window.view' + + view_mode = fields.Selection(selection_add=[ + ('gallery', "Awesome Gallery") + ], ondelete={'gallery': 'cascade'}) diff --git a/awesome_gallery/models/ir_ui_view.py b/awesome_gallery/models/ir_ui_view.py new file mode 100644 index 00000000000..0c11b8298ac --- /dev/null +++ b/awesome_gallery/models/ir_ui_view.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from odoo import fields, models + + +class View(models.Model): + _inherit = 'ir.ui.view' + + type = fields.Selection(selection_add=[('gallery', "Awesome Gallery")]) diff --git a/awesome_gallery/static/src/gallery_view.js b/awesome_gallery/static/src/gallery_view.js new file mode 100644 index 00000000000..db904d1f478 --- /dev/null +++ b/awesome_gallery/static/src/gallery_view.js @@ -0,0 +1,3 @@ +/** @odoo-module */ + +// TODO: Begin here! diff --git a/awesome_gallery/views/views.xml b/awesome_gallery/views/views.xml new file mode 100644 index 00000000000..56327365875 --- /dev/null +++ b/awesome_gallery/views/views.xml @@ -0,0 +1,19 @@ + + + + + Contacts + res.partner + kanban,tree,form,activity + + {'default_is_company': True} + +

+ Create a Contact in your address book +

+ Odoo helps you track all activities related to your contacts. +

+
+
+
+
diff --git a/awesome_kanban/__init__.py b/awesome_kanban/__init__.py new file mode 100644 index 00000000000..40a96afc6ff --- /dev/null +++ b/awesome_kanban/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/awesome_kanban/__manifest__.py b/awesome_kanban/__manifest__.py new file mode 100644 index 00000000000..752fc12f784 --- /dev/null +++ b/awesome_kanban/__manifest__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Awesome Kanban", + 'summary': """ + Starting module for "Master the Odoo web framework, chapter 4: Customize a kanban view" + """, + + 'description': """ + Starting module for "Master the Odoo web framework, chapter 4: Customize a kanban view. + """, + + 'version': '0.1', + 'application': True, + 'category': 'Tutorials/AwesomeKanban', + 'installable': True, + 'depends': ['web', 'crm'], + 'demo': [ + 'views/views.xml', + ], + 'assets': { + 'web.assets_backend': [ + 'awesome_kanban/static/src/**/*', + ], + }, + 'license': 'AGPL-3' +} diff --git a/awesome_kanban/static/src/awesome_kanban_view.js b/awesome_kanban/static/src/awesome_kanban_view.js new file mode 100644 index 00000000000..9f33fc1300b --- /dev/null +++ b/awesome_kanban/static/src/awesome_kanban_view.js @@ -0,0 +1,3 @@ +/** @odoo-module */ + +// TODO: Define here your AwesomeKanban view diff --git a/awesome_kanban/views/views.xml b/awesome_kanban/views/views.xml new file mode 100644 index 00000000000..548b2907b6e --- /dev/null +++ b/awesome_kanban/views/views.xml @@ -0,0 +1,15 @@ + + + + + crm.lead.kanban.lead.awesome_gallery + crm.lead + + + + awesome_kanban + + + + + diff --git a/awesome_owl/__init__.py b/awesome_owl/__init__.py new file mode 100644 index 00000000000..457bae27e11 --- /dev/null +++ b/awesome_owl/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers \ No newline at end of file diff --git a/awesome_owl/__manifest__.py b/awesome_owl/__manifest__.py new file mode 100644 index 00000000000..1be0b12eb72 --- /dev/null +++ b/awesome_owl/__manifest__.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Awesome Owl", + + 'summary': """ + Starting module for "Discover the JS framework, chapter 1: Owl components" + """, + + 'description': """ + Starting module for "Discover the JS framework, chapter 1: Owl components" + """, + + 'author': "Odoo", + 'website': "https://www.odoo.com", + + # Categories can be used to filter modules in modules listing + # Check https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/data/ir_module_category_data.xml + # for the full list + 'category': 'Tutorials/AwesomeOwl', + 'version': '0.1', + + # any module necessary for this one to work correctly + 'depends': ['base', 'web'], + 'application': True, + 'installable': True, + 'data': [ + 'views/templates.xml', + ], + 'assets': { + 'awesome_owl.assets_playground': [ + # bootstrap + ('include', 'web._assets_helpers'), + 'web/static/src/scss/pre_variables.scss', + 'web/static/lib/bootstrap/scss/_variables.scss', + ('include', 'web._assets_bootstrap_backend'), + + # required for fa icons + 'web/static/src/libs/fontawesome/css/font-awesome.css', + + # include base files from framework + ('include', 'web._assets_core'), + + # remove some files that we do not use to create a minimal bundle + ('remove', 'web/static/src/core/**/*'), + ('remove', 'web/static/lib/luxon/luxon.js'), + 'web/static/src/core/utils/functions.js', + 'web/static/src/core/browser/browser.js', + 'web/static/src/core/registry.js', + 'web/static/src/core/assets.js', + 'awesome_owl/static/src/**/*', + ], + }, + 'license': 'AGPL-3' +} diff --git a/awesome_owl/controllers/__init__.py b/awesome_owl/controllers/__init__.py new file mode 100644 index 00000000000..457bae27e11 --- /dev/null +++ b/awesome_owl/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers \ No newline at end of file diff --git a/awesome_owl/controllers/controllers.py b/awesome_owl/controllers/controllers.py new file mode 100644 index 00000000000..bccfd6fe283 --- /dev/null +++ b/awesome_owl/controllers/controllers.py @@ -0,0 +1,10 @@ +from odoo import http +from odoo.http import request, route + +class OwlPlayground(http.Controller): + @http.route(['/awesome_owl'], type='http', auth='public') + def show_playground(self): + """ + Renders the owl playground page + """ + return request.render('awesome_owl.playground') diff --git a/awesome_owl/static/src/main.js b/awesome_owl/static/src/main.js new file mode 100644 index 00000000000..58596c256ef --- /dev/null +++ b/awesome_owl/static/src/main.js @@ -0,0 +1,41 @@ +/** @odoo-module **/ + +import { browser } from "@web/core/browser/browser"; +import { mount, whenReady } from "@odoo/owl"; +import { Playground } from "./playground"; +import { templates } from "@web/core/assets"; + +// Mount the Playground component when the document.body is ready +whenReady( () => { + mount(Playground, document.body, { templates, dev: true, name: "Owl Tutorial" }); +}); + + + +/** + * This code is iterating over the cause property of an error object to console.error a string + * containing the stack trace of the error and any errors that caused it. + * @param {Event} ev + */ +function logError(ev) { + ev.preventDefault(); + let error = ev ?.error || ev.reason; + + if (error.seen) { + // If an error causes the mount to crash, Owl will reject the mount promise and throw the + // error. Therefore, this if statement prevents the same error from appearing twice. + return; + } + error.seen = true; + + let errorMessage = error.stack; + while (error.cause) { + errorMessage += "\nCaused by: " + errorMessage += error.cause.stack; + error = error.cause; + } + console.error(errorMessage); +} + +browser.addEventListener("error", (ev) => {logError(ev)}); +browser.addEventListener("unhandledrejection", (ev) => {logError(ev)}); diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js new file mode 100644 index 00000000000..657fb8b07bb --- /dev/null +++ b/awesome_owl/static/src/playground.js @@ -0,0 +1,7 @@ +/** @odoo-module **/ + +import { Component } from "@odoo/owl"; + +export class Playground extends Component { + static template = "awesome_owl.playground"; +} diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml new file mode 100644 index 00000000000..4fb905d59f9 --- /dev/null +++ b/awesome_owl/static/src/playground.xml @@ -0,0 +1,10 @@ + + + + +
+ hello world +
+
+ +
diff --git a/awesome_owl/views/templates.xml b/awesome_owl/views/templates.xml new file mode 100644 index 00000000000..aa54c1a7241 --- /dev/null +++ b/awesome_owl/views/templates.xml @@ -0,0 +1,15 @@ + + + + + From 5b999b068e53061888903d1688f339d147e2af0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 15:04:25 +0200 Subject: [PATCH 02/69] [SOLUTION] 1.1 Displaying a counter --- awesome_owl/static/src/playground.js | 10 +++++++++- awesome_owl/static/src/playground.xml | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 657fb8b07bb..2919582d576 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,7 +1,15 @@ /** @odoo-module **/ -import { Component } from "@odoo/owl"; +import { Component, useState } from "@odoo/owl"; export class Playground extends Component { static template = "awesome_owl.playground"; + + setup() { + this.state = useState({ value: 1 }); + } + + increment() { + this.state.value = this.state.value + 1; + } } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 4fb905d59f9..7d6dc1cc68b 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -4,6 +4,10 @@
hello world +
+ Counter: + +
From 483b01bb91d17a976044cb40e8a0b158f9fb4b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 15:10:35 +0200 Subject: [PATCH 03/69] [SOLUTION] 1.2 Extract counter in a sub component --- awesome_owl/static/src/counter/counter.js | 15 +++++++++++++++ awesome_owl/static/src/counter/counter.xml | 9 +++++++++ awesome_owl/static/src/playground.js | 12 +++--------- awesome_owl/static/src/playground.xml | 6 ++---- 4 files changed, 29 insertions(+), 13 deletions(-) create mode 100644 awesome_owl/static/src/counter/counter.js create mode 100644 awesome_owl/static/src/counter/counter.xml diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js new file mode 100644 index 00000000000..e7c592a2f47 --- /dev/null +++ b/awesome_owl/static/src/counter/counter.js @@ -0,0 +1,15 @@ +/** @odoo-module */ + +import { Component, useState } from "@odoo/owl"; + +export class Counter extends Component { + static template = "awesome_owl.Counter"; + + setup() { + this.state = useState({ value: 1 }); + } + + increment() { + this.state.value = this.state.value + 1; + } +} diff --git a/awesome_owl/static/src/counter/counter.xml b/awesome_owl/static/src/counter/counter.xml new file mode 100644 index 00000000000..4791fb6cd42 --- /dev/null +++ b/awesome_owl/static/src/counter/counter.xml @@ -0,0 +1,9 @@ + + + +
+ Counter: + +
+
+
diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 2919582d576..9f85177447d 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,15 +1,9 @@ /** @odoo-module **/ -import { Component, useState } from "@odoo/owl"; +import { Component } from "@odoo/owl"; +import { Counter } from "./counter/counter"; export class Playground extends Component { static template = "awesome_owl.playground"; - - setup() { - this.state = useState({ value: 1 }); - } - - increment() { - this.state.value = this.state.value + 1; - } + static components = { Counter }; } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 7d6dc1cc68b..cbf5b682b4c 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -4,10 +4,8 @@
hello world -
- Counter: - -
+ +
From d55533a32e91f21e1c6b3eb0d206a8ed96e95794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 15:15:59 +0200 Subject: [PATCH 04/69] [Solution] 1.3 A simple Card component --- awesome_owl/static/src/card/card.js | 7 +++++++ awesome_owl/static/src/card/card.xml | 11 +++++++++++ awesome_owl/static/src/playground.js | 3 ++- awesome_owl/static/src/playground.xml | 4 ++++ 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 awesome_owl/static/src/card/card.js create mode 100644 awesome_owl/static/src/card/card.xml diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js new file mode 100644 index 00000000000..d9dd9e88c91 --- /dev/null +++ b/awesome_owl/static/src/card/card.js @@ -0,0 +1,7 @@ +/** @odoo-module */ + +import { Component } from "@odoo/owl"; + +export class Card extends Component { + static template = "awesome_owl.Card"; +} diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml new file mode 100644 index 00000000000..4d6797962aa --- /dev/null +++ b/awesome_owl/static/src/card/card.xml @@ -0,0 +1,11 @@ + + + +
+
+
+

+
+
+
+
diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 9f85177447d..a9035a74009 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -2,8 +2,9 @@ import { Component } from "@odoo/owl"; import { Counter } from "./counter/counter"; +import { Card } from "./card/card"; export class Playground extends Component { static template = "awesome_owl.playground"; - static components = { Counter }; + static components = { Counter, Card }; } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index cbf5b682b4c..fa155075144 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -7,6 +7,10 @@ +
+ + +
From 4481e464b7baaa06365967cccc83718293191982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 15:27:57 +0200 Subject: [PATCH 05/69] [Solution] 1.4 Using markup to display html --- awesome_owl/static/src/card/card.xml | 4 ++-- awesome_owl/static/src/playground.js | 7 ++++++- awesome_owl/static/src/playground.xml | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index 4d6797962aa..23878b0723a 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -3,8 +3,8 @@
-
-

+
+

diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index a9035a74009..b3b59de62c5 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,10 +1,15 @@ /** @odoo-module **/ -import { Component } from "@odoo/owl"; +import { Component, markup } from "@odoo/owl"; import { Counter } from "./counter/counter"; import { Card } from "./card/card"; export class Playground extends Component { static template = "awesome_owl.playground"; static components = { Counter, Card }; + + setup() { + this.str1 = "
some content
"; + this.str2 = markup("
some content
"); + } } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index fa155075144..767481db527 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -8,8 +8,8 @@
- - + +
From b03addb322fb7cdb45863032f7e16345f0b5bd95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 15:35:45 +0200 Subject: [PATCH 06/69] [Solution] 1.5 Props validation --- awesome_owl/static/src/card/card.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index d9dd9e88c91..bfcc7313dca 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -4,4 +4,8 @@ import { Component } from "@odoo/owl"; export class Card extends Component { static template = "awesome_owl.Card"; + static props = { + title: String, + content: String, + }; } From 180bbc2fdcd8cae0859522a93c45f1b4aaad22c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 15:41:32 +0200 Subject: [PATCH 07/69] [Solution] 1.6 The sum of two Counter --- awesome_owl/static/src/counter/counter.js | 6 ++++++ awesome_owl/static/src/playground.js | 7 ++++++- awesome_owl/static/src/playground.xml | 5 +++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js index e7c592a2f47..e7484e880d9 100644 --- a/awesome_owl/static/src/counter/counter.js +++ b/awesome_owl/static/src/counter/counter.js @@ -4,6 +4,9 @@ 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: 1 }); @@ -11,5 +14,8 @@ export class Counter extends Component { increment() { this.state.value = this.state.value + 1; + if (this.props.onChange) { + this.props.onChange(); + } } } diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index b3b59de62c5..2765cedc720 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { Component, markup } from "@odoo/owl"; +import { Component, markup, useState } from "@odoo/owl"; import { Counter } from "./counter/counter"; import { Card } from "./card/card"; @@ -11,5 +11,10 @@ export class Playground extends Component { setup() { this.str1 = "
some content
"; this.str2 = markup("
some content
"); + this.sum = useState({ value: 2 }); + } + + incrementSum() { + this.sum.value++; } } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 767481db527..391ac038fca 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -4,8 +4,9 @@
hello world - - + + +
The sum is:
From 57726569474bfbc204c10ee23826aa3649908a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 15:50:22 +0200 Subject: [PATCH 08/69] [Solution] 1.7 A todo list --- awesome_owl/static/src/playground.js | 3 ++- awesome_owl/static/src/playground.xml | 1 + awesome_owl/static/src/todo_list/todo_item.js | 13 +++++++++++++ awesome_owl/static/src/todo_list/todo_item.xml | 9 +++++++++ awesome_owl/static/src/todo_list/todo_list.js | 16 ++++++++++++++++ awesome_owl/static/src/todo_list/todo_list.xml | 10 ++++++++++ 6 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 awesome_owl/static/src/todo_list/todo_item.js create mode 100644 awesome_owl/static/src/todo_list/todo_item.xml create mode 100644 awesome_owl/static/src/todo_list/todo_list.js create mode 100644 awesome_owl/static/src/todo_list/todo_list.xml diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 2765cedc720..98dc66d3743 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -3,10 +3,11 @@ import { Component, markup, useState } 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 components = { Counter, Card }; + static components = { Counter, Card, TodoList }; setup() { this.str1 = "
some content
"; diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 391ac038fca..7389cc78973 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -12,6 +12,7 @@
+
diff --git a/awesome_owl/static/src/todo_list/todo_item.js b/awesome_owl/static/src/todo_list/todo_item.js new file mode 100644 index 00000000000..164ced55c07 --- /dev/null +++ b/awesome_owl/static/src/todo_list/todo_item.js @@ -0,0 +1,13 @@ +/** @odoo-module */ + +import { Component } from "@odoo/owl"; + +export class TodoItem extends Component { + static template = "awesome_owl.TodoItem"; + static props = { + todo: { + type: Object, + shape: { id: Number, description: String, isCompleted: Boolean } + } + }; +} diff --git a/awesome_owl/static/src/todo_list/todo_item.xml b/awesome_owl/static/src/todo_list/todo_item.xml new file mode 100644 index 00000000000..d6c34aedd62 --- /dev/null +++ b/awesome_owl/static/src/todo_list/todo_item.xml @@ -0,0 +1,9 @@ + + + +
+ . + +
+
+
diff --git a/awesome_owl/static/src/todo_list/todo_list.js b/awesome_owl/static/src/todo_list/todo_list.js new file mode 100644 index 00000000000..02c545e2928 --- /dev/null +++ b/awesome_owl/static/src/todo_list/todo_list.js @@ -0,0 +1,16 @@ +/** @odoo-module */ + +import { Component, useState } from "@odoo/owl"; +import { TodoItem } from "./todo_item"; + +export class TodoList extends Component { + static template = "awesome_owl.TodoList"; + static components = { TodoItem }; + + setup() { + this.todos = useState([ + { id: 2, description: "write tutorial", isCompleted: true }, + { id: 3, description: "buy milk", isCompleted: false }, + ]); + } +} diff --git a/awesome_owl/static/src/todo_list/todo_list.xml b/awesome_owl/static/src/todo_list/todo_list.xml new file mode 100644 index 00000000000..61ec27bbcd4 --- /dev/null +++ b/awesome_owl/static/src/todo_list/todo_list.xml @@ -0,0 +1,10 @@ + + + +
+ + + +
+
+
From 2e9c9d78022f3ec4815e9fb5ba180221765ec4c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 15:55:40 +0200 Subject: [PATCH 09/69] [Solution] 1.8 Use dynamic attribute --- awesome_owl/static/src/todo_list/todo_item.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awesome_owl/static/src/todo_list/todo_item.xml b/awesome_owl/static/src/todo_list/todo_item.xml index d6c34aedd62..1007e0922ff 100644 --- a/awesome_owl/static/src/todo_list/todo_item.xml +++ b/awesome_owl/static/src/todo_list/todo_item.xml @@ -1,7 +1,7 @@ -
+
.
From 558c4f1409ffde91fbbf5f7b4d4e18b356f9c984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 16:00:12 +0200 Subject: [PATCH 10/69] [Solution] 1.9 Adding a todo --- awesome_owl/static/src/todo_list/todo_list.js | 17 +++++++++++++---- awesome_owl/static/src/todo_list/todo_list.xml | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/awesome_owl/static/src/todo_list/todo_list.js b/awesome_owl/static/src/todo_list/todo_list.js index 02c545e2928..0bc9d75981a 100644 --- a/awesome_owl/static/src/todo_list/todo_list.js +++ b/awesome_owl/static/src/todo_list/todo_list.js @@ -8,9 +8,18 @@ export class TodoList extends Component { static components = { TodoItem }; setup() { - this.todos = useState([ - { id: 2, description: "write tutorial", isCompleted: true }, - { id: 3, description: "buy milk", isCompleted: false }, - ]); + this.nextId = 0; + this.todos = useState([]); + } + + addTodo(ev) { + if (ev.keyCode === 13 && ev.target.value != "") { + this.todos.push({ + id: this.nextId++, + description: ev.target.value, + isCompleted: false + }); + ev.target.value = ""; + } } } diff --git a/awesome_owl/static/src/todo_list/todo_list.xml b/awesome_owl/static/src/todo_list/todo_list.xml index 61ec27bbcd4..bd33a40c811 100644 --- a/awesome_owl/static/src/todo_list/todo_list.xml +++ b/awesome_owl/static/src/todo_list/todo_list.xml @@ -2,6 +2,7 @@
+ From 313518da0dfda39f36862804a5ad8bd8ff6e765f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 16:03:32 +0200 Subject: [PATCH 11/69] [Solution] 1.10 Focusing the input --- awesome_owl/static/src/todo_list/todo_list.js | 2 ++ awesome_owl/static/src/todo_list/todo_list.xml | 2 +- awesome_owl/static/src/utils.js | 10 ++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 awesome_owl/static/src/utils.js diff --git a/awesome_owl/static/src/todo_list/todo_list.js b/awesome_owl/static/src/todo_list/todo_list.js index 0bc9d75981a..52671510029 100644 --- a/awesome_owl/static/src/todo_list/todo_list.js +++ b/awesome_owl/static/src/todo_list/todo_list.js @@ -2,6 +2,7 @@ import { Component, useState } from "@odoo/owl"; import { TodoItem } from "./todo_item"; +import { useAutofocus } from "../utils"; export class TodoList extends Component { static template = "awesome_owl.TodoList"; @@ -10,6 +11,7 @@ export class TodoList extends Component { setup() { this.nextId = 0; this.todos = useState([]); + useAutofocus("input") } addTodo(ev) { diff --git a/awesome_owl/static/src/todo_list/todo_list.xml b/awesome_owl/static/src/todo_list/todo_list.xml index bd33a40c811..8430d3e5fac 100644 --- a/awesome_owl/static/src/todo_list/todo_list.xml +++ b/awesome_owl/static/src/todo_list/todo_list.xml @@ -2,7 +2,7 @@
- + diff --git a/awesome_owl/static/src/utils.js b/awesome_owl/static/src/utils.js new file mode 100644 index 00000000000..36497fe6448 --- /dev/null +++ b/awesome_owl/static/src/utils.js @@ -0,0 +1,10 @@ +/** @odoo-module */ + +import { useRef, onMounted } from "@odoo/owl"; + +export function useAutofocus(refName) { + const ref = useRef(refName); + onMounted(() => { + ref.el.focus(); + }); +} From 129791627e79074375a9ea7b50d8a5fd4334ec87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 16:07:59 +0200 Subject: [PATCH 12/69] [Solution] 1.11 Toggling todos --- awesome_owl/static/src/todo_list/todo_item.js | 7 ++++++- awesome_owl/static/src/todo_list/todo_item.xml | 9 ++++++--- awesome_owl/static/src/todo_list/todo_list.js | 7 +++++++ awesome_owl/static/src/todo_list/todo_list.xml | 2 +- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/awesome_owl/static/src/todo_list/todo_item.js b/awesome_owl/static/src/todo_list/todo_item.js index 164ced55c07..30f34684c6a 100644 --- a/awesome_owl/static/src/todo_list/todo_item.js +++ b/awesome_owl/static/src/todo_list/todo_item.js @@ -8,6 +8,11 @@ export class TodoItem extends Component { todo: { type: Object, shape: { id: Number, description: String, isCompleted: Boolean } - } + }, + toggleState: Function, }; + + onChange() { + this.props.toggleState(this.props.todo.id); + } } diff --git a/awesome_owl/static/src/todo_list/todo_item.xml b/awesome_owl/static/src/todo_list/todo_item.xml index 1007e0922ff..9a240566372 100644 --- a/awesome_owl/static/src/todo_list/todo_item.xml +++ b/awesome_owl/static/src/todo_list/todo_item.xml @@ -1,9 +1,12 @@ -
- . - +
+ +
diff --git a/awesome_owl/static/src/todo_list/todo_list.js b/awesome_owl/static/src/todo_list/todo_list.js index 52671510029..102d51963e6 100644 --- a/awesome_owl/static/src/todo_list/todo_list.js +++ b/awesome_owl/static/src/todo_list/todo_list.js @@ -24,4 +24,11 @@ export class TodoList extends Component { ev.target.value = ""; } } + + toggleTodo(todoId) { + const todo = this.todos.find((todo) => todo.id === todoId); + if (todo) { + todo.isCompleted = !todo.isCompleted; + } + } } diff --git a/awesome_owl/static/src/todo_list/todo_list.xml b/awesome_owl/static/src/todo_list/todo_list.xml index 8430d3e5fac..19ce2ab584b 100644 --- a/awesome_owl/static/src/todo_list/todo_list.xml +++ b/awesome_owl/static/src/todo_list/todo_list.xml @@ -4,7 +4,7 @@
- +
From 69f8d86355949acae912e7dafee0dd790f151114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 16:27:04 +0200 Subject: [PATCH 13/69] [Solution] 1.12 Deleting todos --- awesome_owl/static/src/todo_list/todo_item.js | 5 +++++ awesome_owl/static/src/todo_list/todo_item.xml | 1 + awesome_owl/static/src/todo_list/todo_list.js | 7 +++++++ awesome_owl/static/src/todo_list/todo_list.xml | 2 +- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/awesome_owl/static/src/todo_list/todo_item.js b/awesome_owl/static/src/todo_list/todo_item.js index 30f34684c6a..ec21ab01d56 100644 --- a/awesome_owl/static/src/todo_list/todo_item.js +++ b/awesome_owl/static/src/todo_list/todo_item.js @@ -10,9 +10,14 @@ export class TodoItem extends Component { shape: { id: Number, description: String, isCompleted: Boolean } }, toggleState: Function, + removeTodo: Function, }; onChange() { this.props.toggleState(this.props.todo.id); } + + onRemove() { + this.props.removeTodo(this.props.todo.id); + } } diff --git a/awesome_owl/static/src/todo_list/todo_item.xml b/awesome_owl/static/src/todo_list/todo_item.xml index 9a240566372..159ae2cf6eb 100644 --- a/awesome_owl/static/src/todo_list/todo_item.xml +++ b/awesome_owl/static/src/todo_list/todo_item.xml @@ -7,6 +7,7 @@ . +
diff --git a/awesome_owl/static/src/todo_list/todo_list.js b/awesome_owl/static/src/todo_list/todo_list.js index 102d51963e6..01269b8f7a9 100644 --- a/awesome_owl/static/src/todo_list/todo_list.js +++ b/awesome_owl/static/src/todo_list/todo_list.js @@ -31,4 +31,11 @@ export class TodoList extends Component { todo.isCompleted = !todo.isCompleted; } } + + removeTodo(todoId) { + const todoIndex = this.todos.findIndex((todo) => todo.id === todoId); + if (todoIndex >= 0) { + this.todos.splice(todoIndex, 1); + } + } } diff --git a/awesome_owl/static/src/todo_list/todo_list.xml b/awesome_owl/static/src/todo_list/todo_list.xml index 19ce2ab584b..3248c389e9c 100644 --- a/awesome_owl/static/src/todo_list/todo_list.xml +++ b/awesome_owl/static/src/todo_list/todo_list.xml @@ -4,7 +4,7 @@
- +
From 2017aff47c593113bc514efd12c634da4a09aa8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 16:30:19 +0200 Subject: [PATCH 14/69] [Solution] 1.13 Generic card with slots --- awesome_owl/static/src/card/card.js | 7 ++++++- awesome_owl/static/src/card/card.xml | 4 +++- awesome_owl/static/src/playground.xml | 8 ++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index bfcc7313dca..c88e93b2bbe 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -6,6 +6,11 @@ export class Card extends Component { static template = "awesome_owl.Card"; static props = { title: String, - content: String, + slots: { + type: Object, + shape: { + default: true + }, + } }; } diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index 23878b0723a..5c284e81757 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -4,7 +4,9 @@
-

+

+ +

diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 7389cc78973..c552a90e934 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -9,8 +9,12 @@
The sum is:
- - + + content of card 1 + + + +
From 3d3e7c8f402bf960faaa05d9082e497deed1d696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 16:32:46 +0200 Subject: [PATCH 15/69] [Solution] 1.14 Minimizing card content --- awesome_owl/static/src/card/card.js | 10 +++++++++- awesome_owl/static/src/card/card.xml | 7 +++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index c88e93b2bbe..8be9475960e 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -1,6 +1,6 @@ /** @odoo-module */ -import { Component } from "@odoo/owl"; +import { Component, useState } from "@odoo/owl"; export class Card extends Component { static template = "awesome_owl.Card"; @@ -13,4 +13,12 @@ export class Card extends Component { }, } }; + + setup() { + this.state = useState({ isOpen: true }); + } + + toggleContent() { + this.state.isOpen = !this.state.isOpen; + } } diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index 5c284e81757..3cf5c65b704 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -3,8 +3,11 @@
-
-

+

+ + +
+

From ae5b825954e59209a4948a3c19233b6a115daba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 16:56:53 +0200 Subject: [PATCH 16/69] [Solution] 2.1 A new Layout --- awesome_dashboard/static/src/dashboard.js | 8 ++++++++ awesome_dashboard/static/src/dashboard.scss | 3 +++ awesome_dashboard/static/src/dashboard.xml | 7 ++++++- 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 awesome_dashboard/static/src/dashboard.scss diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 637fa4bb972..15d810af683 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -2,9 +2,17 @@ import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; +import { Layout } from "@web/search/layout"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; + static components = { Layout }; + + setup() { + this.display = { + controlPanel: {}, + }; + } } registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard.scss b/awesome_dashboard/static/src/dashboard.scss new file mode 100644 index 00000000000..32862ec0d82 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard.scss @@ -0,0 +1,3 @@ +.o_dashboard { + background-color: gray; +} diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 1a2ac9a2fed..2e053f5aa85 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -2,7 +2,12 @@ - hello dashboard + + + Hello dashboard + + some content + From 92bd22449351233316975b204dcf2fddb8e9df3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 17:11:55 +0200 Subject: [PATCH 17/69] [Solution] 2.2 Add some buttons for quick navigation --- awesome_dashboard/static/src/dashboard.js | 18 ++++++++++++++++++ awesome_dashboard/static/src/dashboard.xml | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 15d810af683..fa6cddd6c27 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -3,16 +3,34 @@ import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; +import { useService } from "@web/core/utils/hooks"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; static components = { Layout }; setup() { + this.action = useService("action"); this.display = { controlPanel: {}, }; } + + openCustomerView() { + this.action.doAction("base.action_partner_form"); + } + + openLeads() { + this.action.doAction({ + type: "ir.actions.act_window", + name: "All leads", + res_model: "crm.lead", + views: [ + [false, "list"], + [false, "form"], + ], + }); + } } registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 2e053f5aa85..6470035cce3 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -4,7 +4,8 @@ - Hello dashboard + + some content From 68212f61e57954d4bf9c972cadf0bd06db782288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 17:27:36 +0200 Subject: [PATCH 18/69] [Solution] 2.3 Add a DashboardItem --- awesome_dashboard/static/src/dashboard.js | 3 ++- awesome_dashboard/static/src/dashboard.xml | 12 ++++++++++- .../src/dashboard_item/dashboard_item.js | 20 +++++++++++++++++++ .../src/dashboard_item/dashboard_item.xml | 10 ++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 awesome_dashboard/static/src/dashboard_item/dashboard_item.js create mode 100644 awesome_dashboard/static/src/dashboard_item/dashboard_item.xml diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index fa6cddd6c27..740b3ad7dd1 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -4,10 +4,11 @@ import { Component } 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 "./dashboard_item/dashboard_item"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; - static components = { Layout }; + static components = { Layout, DashboardItem }; setup() { this.action = useService("action"); diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 6470035cce3..b49a55ec438 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -7,7 +7,17 @@ - some content +
+ + some content + + + I love milk + + + some content + +
diff --git a/awesome_dashboard/static/src/dashboard_item/dashboard_item.js b/awesome_dashboard/static/src/dashboard_item/dashboard_item.js new file mode 100644 index 00000000000..39188a95aee --- /dev/null +++ b/awesome_dashboard/static/src/dashboard_item/dashboard_item.js @@ -0,0 +1,20 @@ +/** @odoo-module */ + +import { Component } from "@odoo/owl"; + +export class DashboardItem extends Component { + static template = "awesome_dashboard.DashboardItem" + static props = { + slots: { + type: Object, + shape: { + default: Object + }, + }, + size: { + type: Number, + default: 1, + optional: true, + }, + }; +} diff --git a/awesome_dashboard/static/src/dashboard_item/dashboard_item.xml b/awesome_dashboard/static/src/dashboard_item/dashboard_item.xml new file mode 100644 index 00000000000..33e1fd98752 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard_item/dashboard_item.xml @@ -0,0 +1,10 @@ + + + +
+
+ +
+
+
+
From de2ca57c43b106ae78bb6362fa5fc58b2bf046bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 18:20:56 +0200 Subject: [PATCH 19/69] [Solution] 2.4 Call the server, add some statistics --- awesome_dashboard/static/src/dashboard.js | 6 ++++- awesome_dashboard/static/src/dashboard.xml | 29 +++++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 740b3ad7dd1..c99ab11277f 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { Component } from "@odoo/owl"; +import { Component, onWillStart } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; @@ -12,9 +12,13 @@ class AwesomeDashboard extends Component { setup() { this.action = useService("action"); + this.rpc = useService("rpc"); this.display = { controlPanel: {}, }; + onWillStart(async () => { + this.statistics = await this.rpc("/awesome_dashboard/statistics"); + }); } openCustomerView() { diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index b49a55ec438..be8fe7ba3c7 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -9,13 +9,34 @@
- some content + Average amount of t-shirt by order this month +
+ +
- - I love milk + + Average time for an order to go from 'new' to 'sent' or 'cancelled' +
+ +
+
+ + Number of new orders this month +
+ +
+
+ + Number of cancelled orders this month +
+ +
- some content + Total amount of new orders this month +
+ +
From f4ffaacb1e9a49f47d0ef06abc1c2b4c2fb09e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 21:13:55 +0200 Subject: [PATCH 20/69] [Solution] 2.5 Cache network calls, create a service --- awesome_dashboard/static/src/dashboard.js | 4 ++-- .../static/src/statistics_service.js | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 awesome_dashboard/static/src/statistics_service.js diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index c99ab11277f..c2d532abace 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -12,12 +12,12 @@ class AwesomeDashboard extends Component { setup() { this.action = useService("action"); - this.rpc = useService("rpc"); + this.statistics = useService("awesome_dashboard.statistics"); this.display = { controlPanel: {}, }; onWillStart(async () => { - this.statistics = await this.rpc("/awesome_dashboard/statistics"); + this.statistics = await this.statistics.loadStatistics(); }); } diff --git a/awesome_dashboard/static/src/statistics_service.js b/awesome_dashboard/static/src/statistics_service.js new file mode 100644 index 00000000000..6b26cf54bb1 --- /dev/null +++ b/awesome_dashboard/static/src/statistics_service.js @@ -0,0 +1,16 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { memoize } from "@web/core/utils/functions"; + +const statisticsService = { + dependencies: ["rpc"], + async: ["loadStatistics"], + start(env, { rpc }) { + return { + loadStatistics: memoize(() => rpc("/awesome_dashboard/statistics")), + }; + }, +}; + +registry.category("services").add("awesome_dashboard.statistics", statisticsService); From 7dc93c69e986040b04e4da10e0791988e09fb89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 21:33:15 +0200 Subject: [PATCH 21/69] [Solution] 2.6 Display a pie chart --- awesome_dashboard/static/src/dashboard.js | 3 +- awesome_dashboard/static/src/dashboard.xml | 4 ++ .../static/src/pie_chart/pie_chart.js | 43 +++++++++++++++++++ .../static/src/pie_chart/pie_chart.xml | 10 +++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 awesome_dashboard/static/src/pie_chart/pie_chart.js create mode 100644 awesome_dashboard/static/src/pie_chart/pie_chart.xml diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index c2d532abace..28985e2809b 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -5,10 +5,11 @@ import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; 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 }; + static components = { Layout, DashboardItem, PieChart }; setup() { this.action = useService("action"); diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index be8fe7ba3c7..ade2f967823 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -38,6 +38,10 @@
+ + Shirt orders by size + +
diff --git a/awesome_dashboard/static/src/pie_chart/pie_chart.js b/awesome_dashboard/static/src/pie_chart/pie_chart.js new file mode 100644 index 00000000000..e38b1b0ff32 --- /dev/null +++ b/awesome_dashboard/static/src/pie_chart/pie_chart.js @@ -0,0 +1,43 @@ +/** @odoo-module */ + +import { loadJS } from "@web/core/assets"; +import { getColor } from "@web/core/colors/colors"; +import { Component, onWillStart, useRef, onMounted, onWillUnmount } from "@odoo/owl"; + +export class PieChart extends Component { + static template = "awesome_dashboard.PieChart"; + static props = { + label: String, + data: Object, + }; + + setup() { + this.canvasRef = useRef("canvas"); + onWillStart(() => loadJS(["/web/static/lib/Chart/Chart.js"])); + onMounted(() => { + this.renderChart(); + }); + onWillUnmount(() => { + this.chart.destroy(); + }); + } + + renderChart() { + const labels = Object.keys(this.props.data); + const data = Object.values(this.props.data); + const color = labels.map((_, index) => getColor(index)); + this.chart = new Chart(this.canvasRef.el, { + type: "pie", + data: { + labels: labels, + datasets: [ + { + label: this.props.label, + data: data, + backgroundColor: color, + }, + ], + }, + }); + } +} diff --git a/awesome_dashboard/static/src/pie_chart/pie_chart.xml b/awesome_dashboard/static/src/pie_chart/pie_chart.xml new file mode 100644 index 00000000000..18416e9a223 --- /dev/null +++ b/awesome_dashboard/static/src/pie_chart/pie_chart.xml @@ -0,0 +1,10 @@ + + + +
+
+ +
+
+
+
\ No newline at end of file From c8416e28104fea58837e2c948bb3370af2b3c249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 10 May 2023 22:06:54 +0200 Subject: [PATCH 22/69] [Solution] 2.7 Real life update --- awesome_dashboard/static/src/dashboard.js | 7 ++----- awesome_dashboard/static/src/dashboard.xml | 2 +- .../static/src/statistics_service.js | 17 ++++++++++++----- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 28985e2809b..555e188f911 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { Component, onWillStart } from "@odoo/owl"; +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"; @@ -13,13 +13,10 @@ class AwesomeDashboard extends Component { setup() { this.action = useService("action"); - this.statistics = useService("awesome_dashboard.statistics"); + this.statistics = useState(useService("awesome_dashboard.statistics")); this.display = { controlPanel: {}, }; - onWillStart(async () => { - this.statistics = await this.statistics.loadStatistics(); - }); } openCustomerView() { diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index ade2f967823..c3b353c68ba 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -7,7 +7,7 @@ -
+
Average amount of t-shirt by order this month
diff --git a/awesome_dashboard/static/src/statistics_service.js b/awesome_dashboard/static/src/statistics_service.js index 6b26cf54bb1..158212622da 100644 --- a/awesome_dashboard/static/src/statistics_service.js +++ b/awesome_dashboard/static/src/statistics_service.js @@ -1,15 +1,22 @@ /** @odoo-module */ import { registry } from "@web/core/registry"; -import { memoize } from "@web/core/utils/functions"; +import { reactive } from "@odoo/owl"; const statisticsService = { dependencies: ["rpc"], - async: ["loadStatistics"], start(env, { rpc }) { - return { - loadStatistics: memoize(() => rpc("/awesome_dashboard/statistics")), - }; + const statistics = reactive({ isReady: false }); + + async function loadData() { + const updates = await rpc("/awesome_dashboard/statistics"); + Object.assign(statistics, updates, { isReady: true }); + } + + setInterval(loadData, 10*60*1000); + loadData(); + + return statistics; }, }; From b9c09ae962431bd6ca2757c43a52019bdc00679e Mon Sep 17 00:00:00 2001 From: fdardenne Date: Fri, 9 Jun 2023 14:56:28 +0200 Subject: [PATCH 23/69] [Solution] 2.8 Lazy loading the dashboard --- awesome_dashboard/__manifest__.py | 5 +++++ .../static/src/{ => dashboard}/dashboard.js | 4 ++-- .../static/src/{ => dashboard}/dashboard.scss | 0 .../static/src/{ => dashboard}/dashboard.xml | 0 .../dashboard_item/dashboard_item.js | 0 .../dashboard_item/dashboard_item.xml | 0 .../src/{ => dashboard}/pie_chart/pie_chart.js | 0 .../src/{ => dashboard}/pie_chart/pie_chart.xml | 0 .../src/{ => dashboard}/statistics_service.js | 0 awesome_dashboard/static/src/dashboard_loader.js | 15 +++++++++++++++ 10 files changed, 22 insertions(+), 2 deletions(-) rename awesome_dashboard/static/src/{ => dashboard}/dashboard.js (87%) rename awesome_dashboard/static/src/{ => dashboard}/dashboard.scss (100%) rename awesome_dashboard/static/src/{ => dashboard}/dashboard.xml (100%) rename awesome_dashboard/static/src/{ => dashboard}/dashboard_item/dashboard_item.js (100%) rename awesome_dashboard/static/src/{ => dashboard}/dashboard_item/dashboard_item.xml (100%) rename awesome_dashboard/static/src/{ => dashboard}/pie_chart/pie_chart.js (100%) rename awesome_dashboard/static/src/{ => dashboard}/pie_chart/pie_chart.xml (100%) rename awesome_dashboard/static/src/{ => dashboard}/statistics_service.js (100%) create mode 100644 awesome_dashboard/static/src/dashboard_loader.js diff --git a/awesome_dashboard/__manifest__.py b/awesome_dashboard/__manifest__.py index 31406e8addb..c8f5694cd3a 100644 --- a/awesome_dashboard/__manifest__.py +++ b/awesome_dashboard/__manifest__.py @@ -24,7 +24,12 @@ 'assets': { 'web.assets_backend': [ 'awesome_dashboard/static/src/**/*', + ('remove', 'awesome_dashboard/static/src/dashboard/**/*'), ], + 'awesome_dashboard.dashboard': [ + 'awesome_dashboard/static/src/dashboard/**/*' + ] + }, 'license': 'AGPL-3' } diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard/dashboard.js similarity index 87% rename from awesome_dashboard/static/src/dashboard.js rename to awesome_dashboard/static/src/dashboard/dashboard.js index 555e188f911..36145db9b52 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard/dashboard.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { Component, onWillStart, useState } 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"; @@ -36,4 +36,4 @@ class AwesomeDashboard extends Component { } } -registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard); +registry.category("lazy_components").add("AwesomeDashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard.scss b/awesome_dashboard/static/src/dashboard/dashboard.scss similarity index 100% rename from awesome_dashboard/static/src/dashboard.scss rename to awesome_dashboard/static/src/dashboard/dashboard.scss diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard/dashboard.xml similarity index 100% rename from awesome_dashboard/static/src/dashboard.xml rename to awesome_dashboard/static/src/dashboard/dashboard.xml diff --git a/awesome_dashboard/static/src/dashboard_item/dashboard_item.js b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js similarity index 100% rename from awesome_dashboard/static/src/dashboard_item/dashboard_item.js rename to awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js diff --git a/awesome_dashboard/static/src/dashboard_item/dashboard_item.xml b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml similarity index 100% rename from awesome_dashboard/static/src/dashboard_item/dashboard_item.xml rename to awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml diff --git a/awesome_dashboard/static/src/pie_chart/pie_chart.js b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js similarity index 100% rename from awesome_dashboard/static/src/pie_chart/pie_chart.js rename to awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js diff --git a/awesome_dashboard/static/src/pie_chart/pie_chart.xml b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml similarity index 100% rename from awesome_dashboard/static/src/pie_chart/pie_chart.xml rename to awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml diff --git a/awesome_dashboard/static/src/statistics_service.js b/awesome_dashboard/static/src/dashboard/statistics_service.js similarity index 100% rename from awesome_dashboard/static/src/statistics_service.js rename to awesome_dashboard/static/src/dashboard/statistics_service.js diff --git a/awesome_dashboard/static/src/dashboard_loader.js b/awesome_dashboard/static/src/dashboard_loader.js new file mode 100644 index 00000000000..35296129c1f --- /dev/null +++ b/awesome_dashboard/static/src/dashboard_loader.js @@ -0,0 +1,15 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { LazyComponent } from "@web/core/assets"; +import { Component, xml } from "@odoo/owl"; + +class AwesomeDashboardLoader extends Component { + static components = { LazyComponent }; + static template = xml` + + `; + +} + +registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboardLoader); From f11304a2a1b22910001786e7ef1548f7f848c1fc Mon Sep 17 00:00:00 2001 From: fdardenne Date: Fri, 9 Jun 2023 16:07:50 +0200 Subject: [PATCH 24/69] [Solution] 2.9 Making our dashboard generic --- .../static/src/dashboard/dashboard.js | 6 +- .../static/src/dashboard/dashboard.xml | 40 ++---------- .../static/src/dashboard/dashboard_items.js | 62 +++++++++++++++++++ .../src/dashboard/number_card/number_card.js | 15 +++++ .../src/dashboard/number_card/number_card.xml | 10 +++ .../pie_chart_card/pie_chart_card.js | 17 +++++ .../pie_chart_card/pie_chart_card.xml | 7 +++ 7 files changed, 121 insertions(+), 36 deletions(-) create mode 100644 awesome_dashboard/static/src/dashboard/dashboard_items.js create mode 100644 awesome_dashboard/static/src/dashboard/number_card/number_card.js create mode 100644 awesome_dashboard/static/src/dashboard/number_card/number_card.xml create mode 100644 awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.js create mode 100644 awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml diff --git a/awesome_dashboard/static/src/dashboard/dashboard.js b/awesome_dashboard/static/src/dashboard/dashboard.js index 36145db9b52..a82b7fe7b4b 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.js +++ b/awesome_dashboard/static/src/dashboard/dashboard.js @@ -5,11 +5,11 @@ import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { DashboardItem } from "./dashboard_item/dashboard_item"; -import { PieChart } from "./pie_chart/pie_chart"; +import { items } from "./dashboard_items"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; - static components = { Layout, DashboardItem, PieChart }; + static components = { Layout, DashboardItem }; setup() { this.action = useService("action"); @@ -17,8 +17,10 @@ class AwesomeDashboard extends Component { this.display = { controlPanel: {}, }; + this.items = items; } + openCustomerView() { this.action.doAction("base.action_partner_form"); } diff --git a/awesome_dashboard/static/src/dashboard/dashboard.xml b/awesome_dashboard/static/src/dashboard/dashboard.xml index c3b353c68ba..c4b04ac7dc0 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard/dashboard.xml @@ -8,40 +8,12 @@
- - Average amount of t-shirt by order this month -
- -
-
- - Average time for an order to go from 'new' to 'sent' or 'cancelled' -
- -
-
- - Number of new orders this month -
- -
-
- - Number of cancelled orders this month -
- -
-
- - Total amount of new orders this month -
- -
-
- - Shirt orders by size - - + + + + + +
diff --git a/awesome_dashboard/static/src/dashboard/dashboard_items.js b/awesome_dashboard/static/src/dashboard/dashboard_items.js new file mode 100644 index 00000000000..ca1997cd6f0 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/dashboard_items.js @@ -0,0 +1,62 @@ +/** @odoo-module */ + +import { NumberCard } from "./number_card/number_card"; +import { PieChartCard } from "./pie_chart_card/pie_chart_card"; + +export const items = [ + { + id: "average_quantity", + description: "Average amount of t-shirt", + Component: NumberCard, + props: (data) => ({ + title: "Average amount of t-shirt by order this month", + value: data.average_quantity, + }) + }, + { + id: "average_time", + description: "Average time for an order", + Component: NumberCard, + props: (data) => ({ + title: "Average time for an order to go from 'new' to 'sent' or 'cancelled'", + value: data.average_time, + }) + }, + { + id: "number_new_orders", + description: "New orders this month", + Component: NumberCard, + props: (data) => ({ + title: "Number of new orders this month", + value: data.nb_new_orders, + }) + }, + { + id: "cancelled_orders", + description: "Cancelled orders this month", + Component: NumberCard, + props: (data) => ({ + title: "Number of cancelled orders this month", + value: data.nb_cancelled_orders, + }) + }, + { + id: "amount_new_orders", + description: "amount orders this month", + Component: NumberCard, + props: (data) => ({ + title: "Total amount of new orders this month", + value: data.total_amount, + }) + }, + { + id: "pie_chart", + description: "Shirt orders by size", + Component: PieChartCard, + size: 2, + props: (data) => ({ + title: "Shirt orders by size", + values: data.orders_by_size, + }) + } +] diff --git a/awesome_dashboard/static/src/dashboard/number_card/number_card.js b/awesome_dashboard/static/src/dashboard/number_card/number_card.js new file mode 100644 index 00000000000..0de2c3f98b4 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/number_card/number_card.js @@ -0,0 +1,15 @@ +/** @odoo-module */ + +import { Component } from "@odoo/owl"; + +export class NumberCard extends Component { + static template = "awesome_dashboard.NumberCard"; + static props = { + title: { + type: String, + }, + value: { + type: Number, + } + } +} diff --git a/awesome_dashboard/static/src/dashboard/number_card/number_card.xml b/awesome_dashboard/static/src/dashboard/number_card/number_card.xml new file mode 100644 index 00000000000..2452ba16975 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/number_card/number_card.xml @@ -0,0 +1,10 @@ + + + + + +
+ +
+
+
diff --git a/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.js b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.js new file mode 100644 index 00000000000..a28c2f48c6f --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.js @@ -0,0 +1,17 @@ +/** @odoo-module */ + +import { Component } from "@odoo/owl"; +import { PieChart } from "../pie_chart/pie_chart"; + +export class PieChartCard extends Component { + static template = "awesome_dashboard.PieChartCard"; + static components = { PieChart } + static props = { + title: { + type: String, + }, + values: { + type: Object, + }, + } +} diff --git a/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml new file mode 100644 index 00000000000..58a6811c83a --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml @@ -0,0 +1,7 @@ + + + + + + + From 75404523bfc50456b13b9096e92c016844c83e07 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Fri, 9 Jun 2023 16:15:06 +0200 Subject: [PATCH 25/69] [Solution] 2.10 Making our dashboard extensible --- awesome_dashboard/static/src/dashboard/dashboard.js | 3 +-- awesome_dashboard/static/src/dashboard/dashboard.xml | 1 - awesome_dashboard/static/src/dashboard/dashboard_items.js | 7 ++++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard/dashboard.js b/awesome_dashboard/static/src/dashboard/dashboard.js index a82b7fe7b4b..47dfec7ee0c 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.js +++ b/awesome_dashboard/static/src/dashboard/dashboard.js @@ -5,7 +5,6 @@ import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { DashboardItem } from "./dashboard_item/dashboard_item"; -import { items } from "./dashboard_items"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; @@ -17,7 +16,7 @@ class AwesomeDashboard extends Component { this.display = { controlPanel: {}, }; - this.items = items; + this.items = registry.category("awesome_dashboard").getAll(); } diff --git a/awesome_dashboard/static/src/dashboard/dashboard.xml b/awesome_dashboard/static/src/dashboard/dashboard.xml index c4b04ac7dc0..790657bdce5 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard/dashboard.xml @@ -17,5 +17,4 @@
- diff --git a/awesome_dashboard/static/src/dashboard/dashboard_items.js b/awesome_dashboard/static/src/dashboard/dashboard_items.js index ca1997cd6f0..906ac125d76 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard_items.js +++ b/awesome_dashboard/static/src/dashboard/dashboard_items.js @@ -2,8 +2,9 @@ import { NumberCard } from "./number_card/number_card"; import { PieChartCard } from "./pie_chart_card/pie_chart_card"; +import { registry } from "@web/core/registry"; -export const items = [ +const items = [ { id: "average_quantity", description: "Average amount of t-shirt", @@ -60,3 +61,7 @@ export const items = [ }) } ] + +items.forEach(item => { + registry.category("awesome_dashboard").add(item.id, item); +}); From d7d44a14fed25b623dec7902ce08ca9472720f52 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Fri, 9 Jun 2023 19:19:45 +0200 Subject: [PATCH 26/69] [Solution] 2.11 Add and remove dashboard items --- .../static/src/dashboard/dashboard.js | 52 +++++++++++++++++++ .../static/src/dashboard/dashboard.xml | 24 ++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/awesome_dashboard/static/src/dashboard/dashboard.js b/awesome_dashboard/static/src/dashboard/dashboard.js index 47dfec7ee0c..9ae72d3814c 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.js +++ b/awesome_dashboard/static/src/dashboard/dashboard.js @@ -5,6 +5,9 @@ import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { DashboardItem } from "./dashboard_item/dashboard_item"; +import { Dialog } from "@web/core/dialog/dialog"; +import { CheckBox } from "@web/core/checkbox/checkbox"; +import { browser } from "@web/core/browser/browser"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; @@ -13,12 +16,27 @@ class AwesomeDashboard extends Component { setup() { this.action = useService("action"); this.statistics = useState(useService("awesome_dashboard.statistics")); + this.dialog = useService("dialog"); this.display = { controlPanel: {}, }; this.items = registry.category("awesome_dashboard").getAll(); + this.state = useState({ + disabledItems: browser.localStorage.getItem("disabledDashboardItems")?.split(",") || [] + }); + } + + openConfiguration() { + this.dialog.add(ConfigurationDialog, { + items: this.items, + disabledItems: this.state.disabledItems, + onUpdateConfiguration: this.updateConfiguration.bind(this), + }) } + updateConfiguration(newDisabledItems) { + this.state.disabledItems = newDisabledItems; + } openCustomerView() { this.action.doAction("base.action_partner_form"); @@ -37,4 +55,38 @@ class AwesomeDashboard extends Component { } } +class ConfigurationDialog extends Component { + static template = "awesome_dashboard.ConfigurationDialog"; + static components = { Dialog, CheckBox }; + static props = ["close", "items", "disabledItems", "onUpdateConfiguration"]; + + setup() { + this.items = useState(this.props.items.map((item) => { + return { + ...item, + enabled: !this.props.disabledItems.includes(item.id), + } + })); + } + + done() { + this.props.close(); + } + + onChange(checked, changedItem) { + changedItem.enabled = checked; + const newDisabledItems = Object.values(this.items).filter( + (item) => !item.enabled + ).map((item) => item.id) + + browser.localStorage.setItem( + "disabledDashboardItems", + newDisabledItems, + ); + + this.props.onUpdateConfiguration(newDisabledItems); + } + +} + registry.category("lazy_components").add("AwesomeDashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard/dashboard.xml b/awesome_dashboard/static/src/dashboard/dashboard.xml index 790657bdce5..07e0d109946 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard/dashboard.xml @@ -7,9 +7,15 @@ + + + +
- + @@ -17,4 +23,20 @@
+ + + + Which cards do you whish to see ? + + + + + + + + + + From e42122161465bef3355c9125eea6d92bdf04d500 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Wed, 16 Aug 2023 11:05:19 +0200 Subject: [PATCH 27/69] [Solution] 3.1 Create a systray item --- .../clicker_systray_item.js | 23 +++++++++++++++++++ .../clicker_systray_item.xml | 11 +++++++++ 2 files changed, 34 insertions(+) create mode 100644 awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js create mode 100644 awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js new file mode 100644 index 00000000000..5331d92e948 --- /dev/null +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js @@ -0,0 +1,23 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { Component, useState } from "@odoo/owl"; + +export class ClickerSystray extends Component { + static template = "awesome_clicker.ClickerSystray"; + + setup() { + this.state = useState({ counter: 0 }); + } + + increment() { + this.state.counter++; + } + +} + +export const systrayItem = { + Component: ClickerSystray, +}; + +registry.category("systray").add("awesome_clicker.ClickerSystray", systrayItem, { sequence: 1000 }); diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml new file mode 100644 index 00000000000..c40964f4b7b --- /dev/null +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml @@ -0,0 +1,11 @@ + + + +
+ Clicks: + +
+
+
From 2fc331e3b01c40484b79d000d8a03b800957e579 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Wed, 16 Aug 2023 11:10:44 +0200 Subject: [PATCH 28/69] [Solution] 3.2 Count external clicks --- .../static/src/clicker_systray_item/clicker_systray_item.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js index 5331d92e948..4325c5d49f2 100644 --- a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js @@ -1,19 +1,19 @@ /** @odoo-module */ import { registry } from "@web/core/registry"; -import { Component, useState } from "@odoo/owl"; +import { Component, useState, useExternalListener } from "@odoo/owl"; export class ClickerSystray extends Component { static template = "awesome_clicker.ClickerSystray"; setup() { this.state = useState({ counter: 0 }); + useExternalListener(document.body, "click", () => this.state.counter++, true); } increment() { - this.state.counter++; + this.state.counter += 9; } - } export const systrayItem = { From d8c6ce8185c960abb63c2e6be8bfb3e3146d11b0 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Wed, 16 Aug 2023 11:22:22 +0200 Subject: [PATCH 29/69] [Solution] 3.3 Create a client action --- .../clicker_systray_item/clicker_systray_item.js | 13 ++++++++++++- .../clicker_systray_item/clicker_systray_item.xml | 4 ++++ .../static/src/client_action/client_action.js | 10 ++++++++++ .../static/src/client_action/client_action.xml | 7 +++++++ 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 awesome_clicker/static/src/client_action/client_action.js create mode 100644 awesome_clicker/static/src/client_action/client_action.xml diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js index 4325c5d49f2..ca188eef758 100644 --- a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js @@ -1,19 +1,30 @@ /** @odoo-module */ -import { registry } from "@web/core/registry"; import { Component, useState, useExternalListener } from "@odoo/owl"; +import { registry } from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; export class ClickerSystray extends Component { static template = "awesome_clicker.ClickerSystray"; setup() { this.state = useState({ counter: 0 }); + this.action = useService("action"); useExternalListener(document.body, "click", () => this.state.counter++, true); } increment() { this.state.counter += 9; } + + openClientAction() { + this.action.doAction({ + type: "ir.actions.client", + tag: "awesome_clicker.client_action", + target: "new", + name: "Clicker Game" + }); + } } export const systrayItem = { diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml index c40964f4b7b..b06a7190f68 100644 --- a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml @@ -6,6 +6,10 @@ + +
diff --git a/awesome_clicker/static/src/client_action/client_action.js b/awesome_clicker/static/src/client_action/client_action.js new file mode 100644 index 00000000000..37c9a6f627d --- /dev/null +++ b/awesome_clicker/static/src/client_action/client_action.js @@ -0,0 +1,10 @@ +/** @odoo-module */ + +import { Component } from "@odoo/owl"; +import { registry } from "@web/core/registry"; + +class ClickerClientAction extends Component { + static template = "awesome_clicker.ClickerClientAction"; +} + +registry.category("actions").add("awesome_clicker.client_action", ClickerClientAction); diff --git a/awesome_clicker/static/src/client_action/client_action.xml b/awesome_clicker/static/src/client_action/client_action.xml new file mode 100644 index 00000000000..d268a9bc708 --- /dev/null +++ b/awesome_clicker/static/src/client_action/client_action.xml @@ -0,0 +1,7 @@ + + + + Clicker client action + + + From 932559335ad70908e6c6ea8a8657eef6d299ae23 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Wed, 16 Aug 2023 11:45:43 +0200 Subject: [PATCH 30/69] [Solution] 3.4 Move the state to a service --- awesome_clicker/static/src/clicker_service.js | 23 +++++++++++++++++++ .../clicker_systray_item.js | 9 ++------ .../clicker_systray_item.xml | 4 ++-- .../static/src/client_action/client_action.js | 7 +++++- .../src/client_action/client_action.xml | 7 +++++- 5 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 awesome_clicker/static/src/clicker_service.js diff --git a/awesome_clicker/static/src/clicker_service.js b/awesome_clicker/static/src/clicker_service.js new file mode 100644 index 00000000000..c28f938e7c1 --- /dev/null +++ b/awesome_clicker/static/src/clicker_service.js @@ -0,0 +1,23 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { reactive } from "@odoo/owl"; + +const clickerService = { + start(env) { + const state = reactive({ clicks: 0 }); + + function increment(inc) { + state.clicks += inc; + } + + document.addEventListener("click", () => increment(1), true ); + + return { + state, + increment, + }; + }, +}; + +registry.category("services").add("awesome_clicker.clicker", clickerService); diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js index ca188eef758..42309272f0c 100644 --- a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js @@ -1,6 +1,6 @@ /** @odoo-module */ -import { Component, useState, useExternalListener } from "@odoo/owl"; +import { Component, useState } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; @@ -8,13 +8,8 @@ export class ClickerSystray extends Component { static template = "awesome_clicker.ClickerSystray"; setup() { - this.state = useState({ counter: 0 }); this.action = useService("action"); - useExternalListener(document.body, "click", () => this.state.counter++, true); - } - - increment() { - this.state.counter += 9; + this.clickService = useState(useService("awesome_clicker.clicker")); } openClientAction() { diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml index b06a7190f68..f5ad2e21643 100644 --- a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml @@ -2,8 +2,8 @@
- Clicks: - diff --git a/awesome_clicker/static/src/client_action/client_action.js b/awesome_clicker/static/src/client_action/client_action.js index 37c9a6f627d..eff925a1798 100644 --- a/awesome_clicker/static/src/client_action/client_action.js +++ b/awesome_clicker/static/src/client_action/client_action.js @@ -1,10 +1,15 @@ /** @odoo-module */ -import { Component } from "@odoo/owl"; +import { Component, useState } from "@odoo/owl"; import { registry } from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; class ClickerClientAction extends Component { static template = "awesome_clicker.ClickerClientAction"; + + setup() { + this.clickService = useState(useService("awesome_clicker.clicker")); + } } registry.category("actions").add("awesome_clicker.client_action", ClickerClientAction); diff --git a/awesome_clicker/static/src/client_action/client_action.xml b/awesome_clicker/static/src/client_action/client_action.xml index d268a9bc708..d463e6a64d4 100644 --- a/awesome_clicker/static/src/client_action/client_action.xml +++ b/awesome_clicker/static/src/client_action/client_action.xml @@ -1,7 +1,12 @@ - Clicker client action +
+ Clicks: + +
From 8d17775490f4cd962e26b1aabbbc28993ece8d3f Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 9 Oct 2023 15:06:51 +0200 Subject: [PATCH 31/69] [Solution] 3.5 Use a custom hook --- awesome_clicker/static/src/clicker_hook.js | 8 ++++++++ .../src/clicker_systray_item/clicker_systray_item.js | 5 +++-- .../src/clicker_systray_item/clicker_systray_item.xml | 4 ++-- awesome_clicker/static/src/client_action/client_action.js | 6 +++--- .../static/src/client_action/client_action.xml | 4 ++-- 5 files changed, 18 insertions(+), 9 deletions(-) create mode 100644 awesome_clicker/static/src/clicker_hook.js diff --git a/awesome_clicker/static/src/clicker_hook.js b/awesome_clicker/static/src/clicker_hook.js new file mode 100644 index 00000000000..1e6d341479e --- /dev/null +++ b/awesome_clicker/static/src/clicker_hook.js @@ -0,0 +1,8 @@ +/** @odoo-module */ + +import { useService } from "@web/core/utils/hooks"; +import { useState } from "@odoo/owl"; + +export function useClicker() { + return useState(useService("awesome_clicker.clicker")); +} diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js index 42309272f0c..40993256f10 100644 --- a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js @@ -1,15 +1,16 @@ /** @odoo-module */ -import { Component, useState } from "@odoo/owl"; +import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; +import { useClicker } from "../clicker_hook"; export class ClickerSystray extends Component { static template = "awesome_clicker.ClickerSystray"; setup() { this.action = useService("action"); - this.clickService = useState(useService("awesome_clicker.clicker")); + this.clicker = useClicker(); } openClientAction() { diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml index f5ad2e21643..1cc26a60c1f 100644 --- a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml @@ -2,8 +2,8 @@
- Clicks: - diff --git a/awesome_clicker/static/src/client_action/client_action.js b/awesome_clicker/static/src/client_action/client_action.js index eff925a1798..9795277b849 100644 --- a/awesome_clicker/static/src/client_action/client_action.js +++ b/awesome_clicker/static/src/client_action/client_action.js @@ -1,14 +1,14 @@ /** @odoo-module */ -import { Component, useState } from "@odoo/owl"; +import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; -import { useService } from "@web/core/utils/hooks"; +import { useClicker } from "../clicker_hook"; class ClickerClientAction extends Component { static template = "awesome_clicker.ClickerClientAction"; setup() { - this.clickService = useState(useService("awesome_clicker.clicker")); + this.clicker = useClicker(); } } diff --git a/awesome_clicker/static/src/client_action/client_action.xml b/awesome_clicker/static/src/client_action/client_action.xml index d463e6a64d4..47255065835 100644 --- a/awesome_clicker/static/src/client_action/client_action.xml +++ b/awesome_clicker/static/src/client_action/client_action.xml @@ -2,8 +2,8 @@
- Clicks: -
From 89465239ff3285a6a44265e6339d681e12e2987d Mon Sep 17 00:00:00 2001 From: fdardenne Date: Thu, 28 Sep 2023 15:45:27 +0200 Subject: [PATCH 32/69] [Solution] 3.6 Humanize the displayed value --- .../clicker_systray_item.js | 2 ++ .../clicker_systray_item.xml | 2 +- .../static/src/clicker_value/clicker_value.js | 19 +++++++++++++++++++ .../src/clicker_value/clicker_value.xml | 5 +++++ .../static/src/client_action/client_action.js | 3 ++- .../src/client_action/client_action.xml | 2 +- 6 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 awesome_clicker/static/src/clicker_value/clicker_value.js create mode 100644 awesome_clicker/static/src/clicker_value/clicker_value.xml diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js index 40993256f10..ec1e2de862e 100644 --- a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js @@ -4,9 +4,11 @@ import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; import { useClicker } from "../clicker_hook"; +import { ClickerValue } from "../clicker_value/clicker_value"; export class ClickerSystray extends Component { static template = "awesome_clicker.ClickerSystray"; + static components = { ClickerValue }; setup() { this.action = useService("action"); diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml index 1cc26a60c1f..66a09811485 100644 --- a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml @@ -2,7 +2,7 @@
- Clicks: + Clicks: diff --git a/awesome_clicker/static/src/clicker_value/clicker_value.js b/awesome_clicker/static/src/clicker_value/clicker_value.js new file mode 100644 index 00000000000..c29f9ade8e6 --- /dev/null +++ b/awesome_clicker/static/src/clicker_value/clicker_value.js @@ -0,0 +1,19 @@ +/** @odoo-module */ + +import { Component } from "@odoo/owl"; +import { humanNumber } from "@web/core/utils/numbers"; +import { useClicker } from "../clicker_hook"; + +export class ClickerValue extends Component { + static template = "awesome_clicker.ClickerValue"; + + setup() { + this.clicker = useClicker(); + } + + get humanizedClicks() { + return humanNumber(this.clicker.state.clicks, { + decimals: 1, + }); + } +} diff --git a/awesome_clicker/static/src/clicker_value/clicker_value.xml b/awesome_clicker/static/src/clicker_value/clicker_value.xml new file mode 100644 index 00000000000..bc88cbdf683 --- /dev/null +++ b/awesome_clicker/static/src/clicker_value/clicker_value.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/awesome_clicker/static/src/client_action/client_action.js b/awesome_clicker/static/src/client_action/client_action.js index 9795277b849..80bb65c00db 100644 --- a/awesome_clicker/static/src/client_action/client_action.js +++ b/awesome_clicker/static/src/client_action/client_action.js @@ -3,9 +3,10 @@ import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { useClicker } from "../clicker_hook"; - +import { ClickerValue } from "../clicker_value/clicker_value"; class ClickerClientAction extends Component { static template = "awesome_clicker.ClickerClientAction"; + static components = { ClickerValue }; setup() { this.clicker = useClicker(); diff --git a/awesome_clicker/static/src/client_action/client_action.xml b/awesome_clicker/static/src/client_action/client_action.xml index 47255065835..ad8955a77f5 100644 --- a/awesome_clicker/static/src/client_action/client_action.xml +++ b/awesome_clicker/static/src/client_action/client_action.xml @@ -2,7 +2,7 @@
- Clicks: + Clicks: From ab573c93a323d91ce0d85a434d10a464fad3ffe7 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 9 Oct 2023 17:24:03 +0200 Subject: [PATCH 33/69] [Solution] 3.7 Add a tooltip in ClickValue component --- awesome_clicker/static/src/clicker_value/clicker_value.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awesome_clicker/static/src/clicker_value/clicker_value.xml b/awesome_clicker/static/src/clicker_value/clicker_value.xml index bc88cbdf683..bace5faedb5 100644 --- a/awesome_clicker/static/src/clicker_value/clicker_value.xml +++ b/awesome_clicker/static/src/clicker_value/clicker_value.xml @@ -1,5 +1,5 @@ - + From b54d8a582d21ddce83b488cfbd32747d6fc32fe5 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Fri, 29 Sep 2023 10:16:28 +0200 Subject: [PATCH 34/69] [Solution] 3.8 Buy ClickBots --- awesome_clicker/static/src/clicker_service.js | 23 ++++++++++++++++++- .../src/client_action/client_action.xml | 14 +++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/awesome_clicker/static/src/clicker_service.js b/awesome_clicker/static/src/clicker_service.js index c28f938e7c1..1a794d97f16 100644 --- a/awesome_clicker/static/src/clicker_service.js +++ b/awesome_clicker/static/src/clicker_service.js @@ -5,10 +5,30 @@ import { reactive } from "@odoo/owl"; const clickerService = { start(env) { - const state = reactive({ clicks: 0 }); + const state = reactive({ + clicks: 0, + level: 0, + clickBots: 0, + }); + + setInterval(() => { + state.clicks += state.clickBots * 10; + }, 10000); function increment(inc) { state.clicks += inc; + if (state.level < 1 && state.clicks >= 1000) { + state.level++; + } + } + + function buyClickBot() { + const clickBotPrice = 1000; + if (state.clicks < clickBotPrice) { + return false; + } + state.clicks -= clickBotPrice; + state.clickBots += 1; } document.addEventListener("click", () => increment(1), true ); @@ -16,6 +36,7 @@ const clickerService = { return { state, increment, + buyClickBot, }; }, }; diff --git a/awesome_clicker/static/src/client_action/client_action.xml b/awesome_clicker/static/src/client_action/client_action.xml index ad8955a77f5..2b3e760dc02 100644 --- a/awesome_clicker/static/src/client_action/client_action.xml +++ b/awesome_clicker/static/src/client_action/client_action.xml @@ -7,6 +7,20 @@ Increment
+
+

Bots

+
+
+ x ClickBots (10 clicks/10seconds) + +
+
+ +
+
+
From 7ab2433be6b51882c45727cd542b90f90f4ede47 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Tue, 10 Oct 2023 13:33:42 +0200 Subject: [PATCH 35/69] [Solution] 3.9 Refactor to a class model --- awesome_clicker/static/src/clicker_model.js | 33 +++++++++++++++++ awesome_clicker/static/src/clicker_service.js | 36 ++----------------- .../static/src/clicker_value/clicker_value.js | 2 +- .../src/clicker_value/clicker_value.xml | 2 +- .../src/client_action/client_action.xml | 6 ++-- 5 files changed, 40 insertions(+), 39 deletions(-) create mode 100644 awesome_clicker/static/src/clicker_model.js diff --git a/awesome_clicker/static/src/clicker_model.js b/awesome_clicker/static/src/clicker_model.js new file mode 100644 index 00000000000..7a28a7eedd5 --- /dev/null +++ b/awesome_clicker/static/src/clicker_model.js @@ -0,0 +1,33 @@ +/** @odoo-module */ + +import { Reactive } from "@web/core/utils/reactive"; + +export class ClickerModel extends Reactive { + constructor() { + super(); + this.clicks = 0; + this.level = 0; + this.clickBots = 0; + + document.addEventListener("click", () => this.increment(1), true); + setInterval(() => { + this.clicks += this.clickBots * 10; + }, 10000); + } + + increment(inc) { + this.clicks += inc; + if (this.level < 1 && this.clicks >= 1000) { + this.level++; + } + } + + buyClickBot() { + const clickBotPrice = 1000; + if (this.clicks < clickBotPrice) { + return false; + } + this.clicks -= clickBotPrice; + this.clickBots += 1; + } +} diff --git a/awesome_clicker/static/src/clicker_service.js b/awesome_clicker/static/src/clicker_service.js index 1a794d97f16..303ea484819 100644 --- a/awesome_clicker/static/src/clicker_service.js +++ b/awesome_clicker/static/src/clicker_service.js @@ -1,43 +1,11 @@ /** @odoo-module */ import { registry } from "@web/core/registry"; -import { reactive } from "@odoo/owl"; +import { ClickerModel } from "./clicker_model"; const clickerService = { start(env) { - const state = reactive({ - clicks: 0, - level: 0, - clickBots: 0, - }); - - setInterval(() => { - state.clicks += state.clickBots * 10; - }, 10000); - - function increment(inc) { - state.clicks += inc; - if (state.level < 1 && state.clicks >= 1000) { - state.level++; - } - } - - function buyClickBot() { - const clickBotPrice = 1000; - if (state.clicks < clickBotPrice) { - return false; - } - state.clicks -= clickBotPrice; - state.clickBots += 1; - } - - document.addEventListener("click", () => increment(1), true ); - - return { - state, - increment, - buyClickBot, - }; + return new ClickerModel(); }, }; diff --git a/awesome_clicker/static/src/clicker_value/clicker_value.js b/awesome_clicker/static/src/clicker_value/clicker_value.js index c29f9ade8e6..668da36170c 100644 --- a/awesome_clicker/static/src/clicker_value/clicker_value.js +++ b/awesome_clicker/static/src/clicker_value/clicker_value.js @@ -12,7 +12,7 @@ export class ClickerValue extends Component { } get humanizedClicks() { - return humanNumber(this.clicker.state.clicks, { + return humanNumber(this.clicker.clicks, { decimals: 1, }); } diff --git a/awesome_clicker/static/src/clicker_value/clicker_value.xml b/awesome_clicker/static/src/clicker_value/clicker_value.xml index bace5faedb5..24fd29643f2 100644 --- a/awesome_clicker/static/src/clicker_value/clicker_value.xml +++ b/awesome_clicker/static/src/clicker_value/clicker_value.xml @@ -1,5 +1,5 @@ - + diff --git a/awesome_clicker/static/src/client_action/client_action.xml b/awesome_clicker/static/src/client_action/client_action.xml index 2b3e760dc02..e3677b6a968 100644 --- a/awesome_clicker/static/src/client_action/client_action.xml +++ b/awesome_clicker/static/src/client_action/client_action.xml @@ -7,15 +7,15 @@ Increment
-
+

Bots

- x ClickBots (10 clicks/10seconds) + x ClickBots (10 clicks/10seconds)
-
From 95aa12eb77e43afb0eb3144a1e838e7e5a49f9ea Mon Sep 17 00:00:00 2001 From: fdardenne Date: Fri, 29 Sep 2023 10:30:29 +0200 Subject: [PATCH 36/69] [Solution] 3.10 Notify when a milestone is reached --- awesome_clicker/static/src/clicker_model.js | 3 +++ awesome_clicker/static/src/clicker_service.js | 13 +++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/awesome_clicker/static/src/clicker_model.js b/awesome_clicker/static/src/clicker_model.js index 7a28a7eedd5..0c0a9c76441 100644 --- a/awesome_clicker/static/src/clicker_model.js +++ b/awesome_clicker/static/src/clicker_model.js @@ -1,6 +1,7 @@ /** @odoo-module */ import { Reactive } from "@web/core/utils/reactive"; +import { EventBus } from "@odoo/owl"; export class ClickerModel extends Reactive { constructor() { @@ -8,6 +9,7 @@ export class ClickerModel extends Reactive { this.clicks = 0; this.level = 0; this.clickBots = 0; + this.bus = new EventBus(); document.addEventListener("click", () => this.increment(1), true); setInterval(() => { @@ -18,6 +20,7 @@ export class ClickerModel extends Reactive { increment(inc) { this.clicks += inc; if (this.level < 1 && this.clicks >= 1000) { + this.bus.trigger("MILESTONE_1k"); this.level++; } } diff --git a/awesome_clicker/static/src/clicker_service.js b/awesome_clicker/static/src/clicker_service.js index 303ea484819..8d38285ee55 100644 --- a/awesome_clicker/static/src/clicker_service.js +++ b/awesome_clicker/static/src/clicker_service.js @@ -4,8 +4,17 @@ import { registry } from "@web/core/registry"; import { ClickerModel } from "./clicker_model"; const clickerService = { - start(env) { - return new ClickerModel(); + dependencies: ["effect"], + start(env, services) { + const clickerModel = new ClickerModel(); + const bus = clickerModel.bus; + bus.addEventListener("MILESTONE_1k", () => { + services.effect.add({ + message: "Milestone reached! You can now buy clickbots", + type: "rainbow_man", + }); + }); + return clickerModel; }, }; From 5319268994729ca801b95c31185dc8494faf1133 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Fri, 29 Sep 2023 14:00:59 +0200 Subject: [PATCH 37/69] Solution] 3.11 Add BigBots --- awesome_clicker/static/src/clicker_model.js | 49 +++++++++++++++---- awesome_clicker/static/src/clicker_service.js | 6 +-- .../src/client_action/client_action.xml | 24 +++++---- 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/awesome_clicker/static/src/clicker_model.js b/awesome_clicker/static/src/clicker_model.js index 0c0a9c76441..192bdc4587a 100644 --- a/awesome_clicker/static/src/clicker_model.js +++ b/awesome_clicker/static/src/clicker_model.js @@ -8,29 +8,58 @@ export class ClickerModel extends Reactive { super(); this.clicks = 0; this.level = 0; - this.clickBots = 0; this.bus = new EventBus(); + this.bots = { + clickbot: { + price: 1000, + level: 1, + increment: 10, + purchased: 0, + }, + bigbot: { + price: 5000, + level: 2, + increment: 100, + purchased: 0, + } + } + document.addEventListener("click", () => this.increment(1), true); setInterval(() => { - this.clicks += this.clickBots * 10; + for (const bot in this.bots) { + this.clicks += this.bots[bot].increment * this.bots[bot].purchased; + } }, 10000); } increment(inc) { this.clicks += inc; - if (this.level < 1 && this.clicks >= 1000) { - this.bus.trigger("MILESTONE_1k"); - this.level++; + if ( + this.milestones[this.level] && + this.clicks >= this.milestones[this.level].clicks + ) { + this.bus.trigger("MILESTONE", this.milestones[this.level]); + this.level += 1; } } - buyClickBot() { - const clickBotPrice = 1000; - if (this.clicks < clickBotPrice) { + buyBot(name) { + if (!Object.keys(this.bots).includes(name)) { + throw new Error(`Invalid bot name ${name}`); + } + if (this.clicks < this.bots[name].price) { return false; } - this.clicks -= clickBotPrice; - this.clickBots += 1; + + this.clicks -= this.bots[name].price; + this.bots[name].purchased += 1; + } + + get milestones() { + return [ + { clicks: 1000, unlock: "clickBot" }, + { clicks: 5000, unlock: "bigBot" }, + ]; } } diff --git a/awesome_clicker/static/src/clicker_service.js b/awesome_clicker/static/src/clicker_service.js index 8d38285ee55..8ea723f1a1e 100644 --- a/awesome_clicker/static/src/clicker_service.js +++ b/awesome_clicker/static/src/clicker_service.js @@ -7,10 +7,10 @@ const clickerService = { dependencies: ["effect"], start(env, services) { const clickerModel = new ClickerModel(); - const bus = clickerModel.bus; - bus.addEventListener("MILESTONE_1k", () => { + const bus = clickerModel.bus + bus.addEventListener("MILESTONE", (ev) => { services.effect.add({ - message: "Milestone reached! You can now buy clickbots", + message: `Milestone reached! You can now buy ${ev.detail.unlock}`, type: "rainbow_man", }); }); diff --git a/awesome_clicker/static/src/client_action/client_action.xml b/awesome_clicker/static/src/client_action/client_action.xml index e3677b6a968..467c7741792 100644 --- a/awesome_clicker/static/src/client_action/client_action.xml +++ b/awesome_clicker/static/src/client_action/client_action.xml @@ -9,16 +9,20 @@

Bots

-
-
- x ClickBots (10 clicks/10seconds) - -
-
- -
+
+ +
+
+ x ( clicks/10seconds) + +
+
+ +
+
+
From cf18b0aa9275c9cc714f945be0453b2aaefec1ad Mon Sep 17 00:00:00 2001 From: fdardenne Date: Fri, 29 Sep 2023 14:55:41 +0200 Subject: [PATCH 38/69] [Solution] 3.12 Add a new type of resource: power --- awesome_clicker/static/src/clicker_model.js | 12 +++++++++++- .../static/src/client_action/client_action.xml | 18 +++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/awesome_clicker/static/src/clicker_model.js b/awesome_clicker/static/src/clicker_model.js index 192bdc4587a..cb6b7d2490c 100644 --- a/awesome_clicker/static/src/clicker_model.js +++ b/awesome_clicker/static/src/clicker_model.js @@ -23,16 +23,25 @@ export class ClickerModel extends Reactive { purchased: 0, } } + this.multiplier = 1 document.addEventListener("click", () => this.increment(1), true); setInterval(() => { for (const bot in this.bots) { - this.clicks += this.bots[bot].increment * this.bots[bot].purchased; + this.clicks += this.bots[bot].increment * this.bots[bot].purchased * this.multiplier; } }, 10000); } + buyMultiplier() { + if (this.clicks < 50000) { + return false; + } + this.clicks -= 50000; + this.multiplier++; + } + increment(inc) { this.clicks += inc; if ( @@ -60,6 +69,7 @@ export class ClickerModel extends Reactive { return [ { clicks: 1000, unlock: "clickBot" }, { clicks: 5000, unlock: "bigBot" }, + { clicks: 100000, unlock: "power multiplier" }, ]; } } diff --git a/awesome_clicker/static/src/client_action/client_action.xml b/awesome_clicker/static/src/client_action/client_action.xml index 467c7741792..d72706545ce 100644 --- a/awesome_clicker/static/src/client_action/client_action.xml +++ b/awesome_clicker/static/src/client_action/client_action.xml @@ -13,7 +13,7 @@
- x ( clicks/10seconds) + x ( clicks/10seconds)
@@ -25,6 +25,22 @@
+
+

Power multiplier

+
+
+
+ x + +
+
+ +
+
+
+
From 496878beeb1c59e44b223c40ceaefc195b1a987c Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 2 Oct 2023 10:17:50 +0200 Subject: [PATCH 39/69] [Solution] 3.13 Define some random rewards --- awesome_clicker/static/src/click_rewards.js | 26 +++++++++++++++++++++ awesome_clicker/static/src/clicker_model.js | 14 +++++++++++ awesome_clicker/static/src/utils.js | 5 ++++ 3 files changed, 45 insertions(+) create mode 100644 awesome_clicker/static/src/click_rewards.js create mode 100644 awesome_clicker/static/src/utils.js diff --git a/awesome_clicker/static/src/click_rewards.js b/awesome_clicker/static/src/click_rewards.js new file mode 100644 index 00000000000..af32f42d6cd --- /dev/null +++ b/awesome_clicker/static/src/click_rewards.js @@ -0,0 +1,26 @@ +/** @odoo-module */ + +export const rewards = [ + { + description: "Get 1 click bot", + apply(clicker) { + clicker.increment(1); + }, + maxLevel: 3, + }, + { + description: "Get 10 click bot", + apply(clicker) { + clicker.increment(10); + }, + minLevel: 3, + maxLevel: 4, + }, + { + description: "Increase bot power!", + apply(clicker) { + clicker.multipler += 1; + }, + minLevel: 3, + }, +]; diff --git a/awesome_clicker/static/src/clicker_model.js b/awesome_clicker/static/src/clicker_model.js index cb6b7d2490c..a3354695420 100644 --- a/awesome_clicker/static/src/clicker_model.js +++ b/awesome_clicker/static/src/clicker_model.js @@ -2,6 +2,8 @@ import { Reactive } from "@web/core/utils/reactive"; import { EventBus } from "@odoo/owl"; +import { rewards } from "./click_rewards"; +import { choose } from "./utils"; export class ClickerModel extends Reactive { constructor() { @@ -65,6 +67,18 @@ export class ClickerModel extends Reactive { this.bots[name].purchased += 1; } + giveReward() { + const availableReward = []; + for (const reward of rewards) { + if (reward.minLevel <= this.level || !reward.minLevel) { + if (reward.maxLevel >= this.level || !reward.maxLevel) { + availableReward.push(reward); + } + } + } + return choose(availableReward); + } + get milestones() { return [ { clicks: 1000, unlock: "clickBot" }, diff --git a/awesome_clicker/static/src/utils.js b/awesome_clicker/static/src/utils.js new file mode 100644 index 00000000000..fa5451b6621 --- /dev/null +++ b/awesome_clicker/static/src/utils.js @@ -0,0 +1,5 @@ +/** @odoo-module */ + +export function choose(list) { + return list[Math.floor(Math.random() * list.length)]; +} From d78c12b0e61ea10aa190b5df9726b6d7f29d5645 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 2 Oct 2023 11:10:20 +0200 Subject: [PATCH 40/69] [Solution] 3.14 Provide a reward when opening a form view --- awesome_clicker/static/src/clicker_model.js | 2 ++ awesome_clicker/static/src/clicker_service.js | 28 ++++++++++++++++++- .../form_controller/form_controller_patch.js | 17 +++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 awesome_clicker/static/src/form_controller/form_controller_patch.js diff --git a/awesome_clicker/static/src/clicker_model.js b/awesome_clicker/static/src/clicker_model.js index a3354695420..ac220884b9c 100644 --- a/awesome_clicker/static/src/clicker_model.js +++ b/awesome_clicker/static/src/clicker_model.js @@ -76,6 +76,8 @@ export class ClickerModel extends Reactive { } } } + const reward = choose(availableReward); + this.bus.trigger("REWARD", reward); return choose(availableReward); } diff --git a/awesome_clicker/static/src/clicker_service.js b/awesome_clicker/static/src/clicker_service.js index 8ea723f1a1e..be04ac54e7e 100644 --- a/awesome_clicker/static/src/clicker_service.js +++ b/awesome_clicker/static/src/clicker_service.js @@ -4,7 +4,7 @@ import { registry } from "@web/core/registry"; import { ClickerModel } from "./clicker_model"; const clickerService = { - dependencies: ["effect"], + dependencies: ["action", "effect", "notification"], start(env, services) { const clickerModel = new ClickerModel(); const bus = clickerModel.bus @@ -14,6 +14,32 @@ const clickerService = { type: "rainbow_man", }); }); + + bus.addEventListener("REWARD", (ev) => { + const reward = ev.detail; + const closeNotification = services.notification.add( + `Congrats you won a reward: "${reward.description}"`, + { + type: "success", + sticky: true, + buttons: [ + { + name: "Collect", + onClick: () => { + reward.apply(clickerModel); + closeNotification(); + services.action.doAction({ + type: "ir.actions.client", + tag: "awesome_clicker.client_action", + target: "new", + name: "Clicker Game" + }); + }, + }, + ], + } + ); + }) return clickerModel; }, }; diff --git a/awesome_clicker/static/src/form_controller/form_controller_patch.js b/awesome_clicker/static/src/form_controller/form_controller_patch.js new file mode 100644 index 00000000000..93676931a2b --- /dev/null +++ b/awesome_clicker/static/src/form_controller/form_controller_patch.js @@ -0,0 +1,17 @@ +/** @odoo-module */ + +import { FormController } from "@web/views/form/form_controller"; +import { patch } from "@web/core/utils/patch"; +import { useClicker } from "../clicker_hook"; + +const FormControllerPatch = { + setup() { + super.setup(...arguments); + const clicker = useClicker(); + if (Math.random() < 0.01) { + clicker.giveReward(); + } + }, +}; + +patch(FormController.prototype, FormControllerPatch); From fbaf0daca108fbd9e20d45e5de7fc073bad27aec Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 2 Oct 2023 14:34:37 +0200 Subject: [PATCH 41/69] [Solution] 3.15 Add commands in command palette --- .../static/src/clicker_provider.js | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 awesome_clicker/static/src/clicker_provider.js diff --git a/awesome_clicker/static/src/clicker_provider.js b/awesome_clicker/static/src/clicker_provider.js new file mode 100644 index 00000000000..3d085615eab --- /dev/null +++ b/awesome_clicker/static/src/clicker_provider.js @@ -0,0 +1,29 @@ +/** @odoo-module **/ + +import { registry } from "@web/core/registry"; + +const commandProviderRegistry = registry.category("command_provider"); + +commandProviderRegistry.add("clicker", { + provide: (env, options) => { + return [ + { + name: "Buy 1 click bot", + action() { + env.services["awesome_clicker.clicker_service"].buyBot("clickbot"); + }, + }, + { + name: "Open Clicker Game", + action() { + env.services.action.doAction({ + type: "ir.actions.client", + tag: "awesome_clicker.client_action", + target: "new", + name: "Clicker Game", + }); + }, + } + ] + }, +}); From 3b0ecff6259dd62a07154da7c8d32de034671211 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 2 Oct 2023 16:16:53 +0200 Subject: [PATCH 42/69] [Solution] 3.16 Add yet another resource: trees --- awesome_clicker/static/src/clicker_model.js | 36 +++++++++++++++++++ .../src/client_action/client_action.xml | 30 ++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/awesome_clicker/static/src/clicker_model.js b/awesome_clicker/static/src/clicker_model.js index ac220884b9c..f318d11340a 100644 --- a/awesome_clicker/static/src/clicker_model.js +++ b/awesome_clicker/static/src/clicker_model.js @@ -25,6 +25,24 @@ export class ClickerModel extends Reactive { purchased: 0, } } + this.trees = { + pearTree: { + price: 1000000, + level: 4, + produce: "pear", + purchased: 0, + }, + cherryTree: { + price: 1000000, + level: 4, + produce: "cherry", + purchased: 0, + }, + } + this.fruits = { + pear: 0, + cherry: 0, + }, this.multiplier = 1 @@ -34,6 +52,12 @@ export class ClickerModel extends Reactive { this.clicks += this.bots[bot].increment * this.bots[bot].purchased * this.multiplier; } }, 10000); + + setInterval(() => { + for (const tree in this.trees) { + this.fruits[this.trees[tree].produce] += this.trees[tree].purchased; + } + }, 30000); } buyMultiplier() { @@ -81,11 +105,23 @@ export class ClickerModel extends Reactive { return choose(availableReward); } + buyTree(name) { + if (!Object.keys(this.trees).includes(name)) { + throw new Error(`Invalid tree name ${name}`); + } + if (this.clicks < this.trees[name].price) { + return false; + } + this.clicks -= this.trees[name].price; + this.trees[name].purchased += 1; + } + get milestones() { return [ { clicks: 1000, unlock: "clickBot" }, { clicks: 5000, unlock: "bigBot" }, { clicks: 100000, unlock: "power multiplier" }, + { clicks: 1000000, unlock: "pear tree & cherry tree" }, ]; } } diff --git a/awesome_clicker/static/src/client_action/client_action.xml b/awesome_clicker/static/src/client_action/client_action.xml index d72706545ce..62c8bbd5237 100644 --- a/awesome_clicker/static/src/client_action/client_action.xml +++ b/awesome_clicker/static/src/client_action/client_action.xml @@ -41,6 +41,36 @@
+ +
+

Trees

+
+ +
+
+ x (1x /30seconds) + +
+
+ +
+
+
+
+ +

Fruits

+
+ +
+
+ x +
+
+
+
+
From 424987842036a8752cd2e3612794dc1e259689cd Mon Sep 17 00:00:00 2001 From: fdardenne Date: Tue, 3 Oct 2023 13:03:45 +0200 Subject: [PATCH 43/69] [Solution] 3.17 Use a dropdown menu for the systray item --- .../clicker_systray_item.js | 20 ++++++++++++- .../clicker_systray_item.xml | 29 ++++++++++++++----- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js index ec1e2de862e..63c5d733737 100644 --- a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.js @@ -5,10 +5,12 @@ import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; import { useClicker } from "../clicker_hook"; import { ClickerValue } from "../clicker_value/clicker_value"; +import { Dropdown } from "@web/core/dropdown/dropdown"; +import { DropdownItem } from "@web/core/dropdown/dropdown_item"; export class ClickerSystray extends Component { static template = "awesome_clicker.ClickerSystray"; - static components = { ClickerValue }; + static components = { ClickerValue, Dropdown, DropdownItem }; setup() { this.action = useService("action"); @@ -23,6 +25,22 @@ export class ClickerSystray extends Component { name: "Clicker Game" }); } + + get numberTrees() { + let sum = 0; + for (const tree in this.clicker.trees) { + sum += this.clicker.trees[tree].purchased; + } + return sum; + } + + get numberFruits() { + let sum = 0; + for (const fruit in this.clicker.fruits) { + sum += this.clicker.fruits[fruit]; + } + return sum; + } } export const systrayItem = { diff --git a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml index 66a09811485..91306500753 100644 --- a/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml +++ b/awesome_clicker/static/src/clicker_systray_item/clicker_systray_item.xml @@ -2,14 +2,27 @@
- Clicks: - - - + + + , + , + + + + + + + + + + x + + + + x + + +
From f4a507193b28c424fbeb7028f01e85c84d3ca617 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 2 Oct 2023 17:02:56 +0200 Subject: [PATCH 44/69] [Solution] 3.18 Use a Notebook component --- .../static/src/client_action/client_action.js | 3 +- .../src/client_action/client_action.xml | 121 +++++++++--------- 2 files changed, 66 insertions(+), 58 deletions(-) diff --git a/awesome_clicker/static/src/client_action/client_action.js b/awesome_clicker/static/src/client_action/client_action.js index 80bb65c00db..0faeb53a704 100644 --- a/awesome_clicker/static/src/client_action/client_action.js +++ b/awesome_clicker/static/src/client_action/client_action.js @@ -4,9 +4,10 @@ import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { useClicker } from "../clicker_hook"; import { ClickerValue } from "../clicker_value/clicker_value"; +import { Notebook } from "@web/core/notebook/notebook"; class ClickerClientAction extends Component { static template = "awesome_clicker.ClickerClientAction"; - static components = { ClickerValue }; + static components = { ClickerValue, Notebook }; setup() { this.clicker = useClicker(); diff --git a/awesome_clicker/static/src/client_action/client_action.xml b/awesome_clicker/static/src/client_action/client_action.xml index 62c8bbd5237..aac9e7b75e9 100644 --- a/awesome_clicker/static/src/client_action/client_action.xml +++ b/awesome_clicker/static/src/client_action/client_action.xml @@ -7,70 +7,77 @@ Increment
-
-

Bots

-
- -
-
- x ( clicks/10seconds) - -
-
- -
-
-
-
-
-
-

Power multiplier

-
-
-
- x - + + +
+

Bots

+
+ +
+
+ x ( clicks/10seconds) + +
+
+ +
+
+
-
- +
+
+

Power multiplier

+
+
+
+ x + +
+
+ +
+
-
-
+ -
-

Trees

-
- -
-
- x (1x /30seconds) - -
-
- -
+ +
+

Trees

+
+ +
+
+ x (1x /30seconds) + +
+
+ +
+
+
- -
-

Fruits

-
- -
-
- x -
+

Fruits

+
+ +
+
+ x +
+
+
- -
-
+
+
+ + From cea4fde37df19058112fcef09431573ad61ffd67 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Tue, 3 Oct 2023 13:48:33 +0200 Subject: [PATCH 45/69] [Solution] 3.19 Persist the game state --- awesome_clicker/static/src/clicker_model.js | 13 +++++++++++++ awesome_clicker/static/src/clicker_service.js | 9 ++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/awesome_clicker/static/src/clicker_model.js b/awesome_clicker/static/src/clicker_model.js index f318d11340a..ec1486ab3b3 100644 --- a/awesome_clicker/static/src/clicker_model.js +++ b/awesome_clicker/static/src/clicker_model.js @@ -116,6 +116,19 @@ export class ClickerModel extends Reactive { this.trees[name].purchased += 1; } + toJSON() { + const json = Object.assign({}, this); + delete json["bus"]; + return json; + + } + + static fromJSON(json) { + const clicker = new ClickerModel(); + const clickerInstance = Object.assign(clicker, json); + return clickerInstance; + } + get milestones() { return [ { clicks: 1000, unlock: "clickBot" }, diff --git a/awesome_clicker/static/src/clicker_service.js b/awesome_clicker/static/src/clicker_service.js index be04ac54e7e..d33b2d350be 100644 --- a/awesome_clicker/static/src/clicker_service.js +++ b/awesome_clicker/static/src/clicker_service.js @@ -2,11 +2,18 @@ import { registry } from "@web/core/registry"; import { ClickerModel } from "./clicker_model"; +import { browser } from "@web/core/browser/browser"; const clickerService = { dependencies: ["action", "effect", "notification"], start(env, services) { - const clickerModel = new ClickerModel(); + const localState = JSON.parse(browser.localStorage.getItem("clickerState")); + const clickerModel = localState ? ClickerModel.fromJSON(localState): new ClickerModel(); + + setInterval(() => { + browser.localStorage.setItem("clickerState", JSON.stringify(clickerModel)) + }, 10000); + const bus = clickerModel.bus bus.addEventListener("MILESTONE", (ev) => { services.effect.add({ From b7d16ea8920615e5be876e49206c4452ff35af0b Mon Sep 17 00:00:00 2001 From: fdardenne Date: Tue, 3 Oct 2023 13:56:45 +0200 Subject: [PATCH 46/69] [Solution] 3.20 Introduce state migration system --- awesome_clicker/static/src/clicker_migration.js | 17 +++++++++++++++++ awesome_clicker/static/src/clicker_model.js | 2 ++ awesome_clicker/static/src/clicker_service.js | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 awesome_clicker/static/src/clicker_migration.js diff --git a/awesome_clicker/static/src/clicker_migration.js b/awesome_clicker/static/src/clicker_migration.js new file mode 100644 index 00000000000..e03fe2a25f0 --- /dev/null +++ b/awesome_clicker/static/src/clicker_migration.js @@ -0,0 +1,17 @@ +/** @odoo-module */ + +export const CURRENT_VERSION = 1.0; +export const migrations = []; + +export function migrate(localState) { + if (localState?.version < CURRENT_VERSION) { + for (const migration of migrations) { + if (localState.version === migration.fromVersion) { + migration.apply(localState); + localState.version = migration.toVersion + } + } + localState.version = CURRENT_VERSION; + } + return localState; +} diff --git a/awesome_clicker/static/src/clicker_model.js b/awesome_clicker/static/src/clicker_model.js index ec1486ab3b3..553c0e9801b 100644 --- a/awesome_clicker/static/src/clicker_model.js +++ b/awesome_clicker/static/src/clicker_model.js @@ -4,10 +4,12 @@ import { Reactive } from "@web/core/utils/reactive"; import { EventBus } from "@odoo/owl"; import { rewards } from "./click_rewards"; import { choose } from "./utils"; +import { CURRENT_VERSION } from "./clicker_migration"; export class ClickerModel extends Reactive { constructor() { super(); + this.version = CURRENT_VERSION; this.clicks = 0; this.level = 0; this.bus = new EventBus(); diff --git a/awesome_clicker/static/src/clicker_service.js b/awesome_clicker/static/src/clicker_service.js index d33b2d350be..df2b710e776 100644 --- a/awesome_clicker/static/src/clicker_service.js +++ b/awesome_clicker/static/src/clicker_service.js @@ -3,11 +3,12 @@ import { registry } from "@web/core/registry"; import { ClickerModel } from "./clicker_model"; import { browser } from "@web/core/browser/browser"; +import { migrate } from "./clicker_migration"; const clickerService = { dependencies: ["action", "effect", "notification"], start(env, services) { - const localState = JSON.parse(browser.localStorage.getItem("clickerState")); + const localState = migrate(JSON.parse(browser.localStorage.getItem("clickerState"))); const clickerModel = localState ? ClickerModel.fromJSON(localState): new ClickerModel(); setInterval(() => { From b5fb6dd13245719c98709ccb477f04fe96805b5c Mon Sep 17 00:00:00 2001 From: fdardenne Date: Tue, 3 Oct 2023 14:21:25 +0200 Subject: [PATCH 47/69] [Solution] 3.21 Add another type of trees --- .../static/src/clicker_migration.js | 18 ++++++++++++++++-- awesome_clicker/static/src/clicker_model.js | 7 +++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/awesome_clicker/static/src/clicker_migration.js b/awesome_clicker/static/src/clicker_migration.js index e03fe2a25f0..87e2789b5e7 100644 --- a/awesome_clicker/static/src/clicker_migration.js +++ b/awesome_clicker/static/src/clicker_migration.js @@ -1,7 +1,21 @@ /** @odoo-module */ -export const CURRENT_VERSION = 1.0; -export const migrations = []; +export const CURRENT_VERSION = 2.0; +export const migrations = [ + { + fromVersion: 1.0, + toVersion: 2.0, + apply: (state) => { + state.trees.peachTree = { + price: 1500000, + level: 4, + produce: "peach", + purchased: 0, + }; + state.fruits.peach = 0; + }, + }, +]; export function migrate(localState) { if (localState?.version < CURRENT_VERSION) { diff --git a/awesome_clicker/static/src/clicker_model.js b/awesome_clicker/static/src/clicker_model.js index 553c0e9801b..7e71e83317e 100644 --- a/awesome_clicker/static/src/clicker_model.js +++ b/awesome_clicker/static/src/clicker_model.js @@ -40,10 +40,17 @@ export class ClickerModel extends Reactive { produce: "cherry", purchased: 0, }, + peachTree: { + price: 1500000, + level: 4, + produce: "peach", + purchased: 0, + }, } this.fruits = { pear: 0, cherry: 0, + peach: 0, }, this.multiplier = 1 From 3cca34830a8f857efd0017a491ee8201d712def0 Mon Sep 17 00:00:00 2001 From: "Dardenne Florent (dafl)" Date: Tue, 27 Sep 2022 14:57:05 +0200 Subject: [PATCH 48/69] [Solution] 4.1 Make a hello world view --- awesome_gallery/static/src/gallery_controller.js | 11 +++++++++++ awesome_gallery/static/src/gallery_controller.xml | 8 ++++++++ awesome_gallery/static/src/gallery_view.js | 13 ++++++++++++- awesome_gallery/views/views.xml | 10 +++++++++- 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 awesome_gallery/static/src/gallery_controller.js create mode 100644 awesome_gallery/static/src/gallery_controller.xml diff --git a/awesome_gallery/static/src/gallery_controller.js b/awesome_gallery/static/src/gallery_controller.js new file mode 100644 index 00000000000..b2664c03164 --- /dev/null +++ b/awesome_gallery/static/src/gallery_controller.js @@ -0,0 +1,11 @@ +/** @odoo-module */ + +import { Component } from "@odoo/owl"; +import { standardViewProps } from "@web/views/standard_view_props"; + +export class GalleryController extends Component { + static template = "awesome_gallery.GalleryController"; + static props = { + ...standardViewProps, + }; +} diff --git a/awesome_gallery/static/src/gallery_controller.xml b/awesome_gallery/static/src/gallery_controller.xml new file mode 100644 index 00000000000..b2f62272a0e --- /dev/null +++ b/awesome_gallery/static/src/gallery_controller.xml @@ -0,0 +1,8 @@ + + + + +
Hello world
+
+ +
diff --git a/awesome_gallery/static/src/gallery_view.js b/awesome_gallery/static/src/gallery_view.js index db904d1f478..1f77cd041cb 100644 --- a/awesome_gallery/static/src/gallery_view.js +++ b/awesome_gallery/static/src/gallery_view.js @@ -1,3 +1,14 @@ /** @odoo-module */ -// TODO: Begin here! +import { registry } from "@web/core/registry"; +import { GalleryController } from "./gallery_controller"; + +export const galleryView = { + type: "gallery", + display_name: "Gallery", + icon: "fa fa-picture-o", + multiRecord: true, + Controller: GalleryController, +}; + +registry.category("views").add("gallery", galleryView); diff --git a/awesome_gallery/views/views.xml b/awesome_gallery/views/views.xml index 56327365875..a66decaef65 100644 --- a/awesome_gallery/views/views.xml +++ b/awesome_gallery/views/views.xml @@ -1,10 +1,18 @@ + + awesome_gallery.orders.gallery + res.partner + + + + + Contacts res.partner - kanban,tree,form,activity + kanban,tree,form,activity,gallery {'default_is_company': True} From b1d6f57de43aa00713f9f2c3f606d962041a1637 Mon Sep 17 00:00:00 2001 From: "Dardenne Florent (dafl)" Date: Tue, 27 Sep 2022 15:53:01 +0200 Subject: [PATCH 49/69] [Solution] 4.2 Use the Layout component --- awesome_gallery/static/src/gallery_controller.js | 2 ++ awesome_gallery/static/src/gallery_controller.xml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/awesome_gallery/static/src/gallery_controller.js b/awesome_gallery/static/src/gallery_controller.js index b2664c03164..72e8c58641b 100644 --- a/awesome_gallery/static/src/gallery_controller.js +++ b/awesome_gallery/static/src/gallery_controller.js @@ -1,5 +1,6 @@ /** @odoo-module */ +import { Layout } from "@web/search/layout"; import { Component } from "@odoo/owl"; import { standardViewProps } from "@web/views/standard_view_props"; @@ -8,4 +9,5 @@ export class GalleryController extends Component { static props = { ...standardViewProps, }; + static components = { Layout }; } diff --git a/awesome_gallery/static/src/gallery_controller.xml b/awesome_gallery/static/src/gallery_controller.xml index b2f62272a0e..273f6552015 100644 --- a/awesome_gallery/static/src/gallery_controller.xml +++ b/awesome_gallery/static/src/gallery_controller.xml @@ -2,7 +2,7 @@ -
Hello world
+
From 9dcdbceb50f592501294fd48586549e1b4f7605b Mon Sep 17 00:00:00 2001 From: "Dardenne Florent (dafl)" Date: Tue, 27 Sep 2022 16:58:48 +0200 Subject: [PATCH 50/69] [Solution] 4.3 Parse the arch --- awesome_gallery/static/src/gallery_arch_parser.js | 10 ++++++++++ awesome_gallery/static/src/gallery_controller.js | 1 + awesome_gallery/static/src/gallery_view.js | 13 +++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 awesome_gallery/static/src/gallery_arch_parser.js diff --git a/awesome_gallery/static/src/gallery_arch_parser.js b/awesome_gallery/static/src/gallery_arch_parser.js new file mode 100644 index 00000000000..920f41a89f9 --- /dev/null +++ b/awesome_gallery/static/src/gallery_arch_parser.js @@ -0,0 +1,10 @@ +/** @odoo-module */ + +export class GalleryArchParser { + parse(xmlDoc) { + const imageField = xmlDoc.getAttribute("image_field"); + return { + imageField, + }; + } +} diff --git a/awesome_gallery/static/src/gallery_controller.js b/awesome_gallery/static/src/gallery_controller.js index 72e8c58641b..016db468471 100644 --- a/awesome_gallery/static/src/gallery_controller.js +++ b/awesome_gallery/static/src/gallery_controller.js @@ -8,6 +8,7 @@ export class GalleryController extends Component { static template = "awesome_gallery.GalleryController"; static props = { ...standardViewProps, + archInfo: Object, }; static components = { Layout }; } diff --git a/awesome_gallery/static/src/gallery_view.js b/awesome_gallery/static/src/gallery_view.js index 1f77cd041cb..ca6631b991a 100644 --- a/awesome_gallery/static/src/gallery_view.js +++ b/awesome_gallery/static/src/gallery_view.js @@ -2,6 +2,7 @@ import { registry } from "@web/core/registry"; import { GalleryController } from "./gallery_controller"; +import { GalleryArchParser } from "./gallery_arch_parser"; export const galleryView = { type: "gallery", @@ -9,6 +10,18 @@ export const galleryView = { icon: "fa fa-picture-o", multiRecord: true, Controller: GalleryController, + ArchParser: GalleryArchParser, + + props(genericProps, view) { + const { ArchParser } = view; + const { arch } = genericProps; + const archInfo = new ArchParser().parse(arch); + + return { + ...genericProps, + archInfo, + }; + }, }; registry.category("views").add("gallery", galleryView); From a58611d6567b7ca89ea076a35e7f14b7dfd5d2c4 Mon Sep 17 00:00:00 2001 From: "Dardenne Florent (dafl)" Date: Tue, 27 Sep 2022 18:19:23 +0200 Subject: [PATCH 51/69] [Solution] 4.4 Load some data --- .../static/src/gallery_arch_parser.js | 2 ++ .../static/src/gallery_controller.js | 31 ++++++++++++++++++- .../static/src/gallery_controller.xml | 9 +++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/awesome_gallery/static/src/gallery_arch_parser.js b/awesome_gallery/static/src/gallery_arch_parser.js index 920f41a89f9..59d11b62cdf 100644 --- a/awesome_gallery/static/src/gallery_arch_parser.js +++ b/awesome_gallery/static/src/gallery_arch_parser.js @@ -3,8 +3,10 @@ export class GalleryArchParser { parse(xmlDoc) { const imageField = xmlDoc.getAttribute("image_field"); + const limit = xmlDoc.getAttribute("limit") || 80; return { imageField, + limit, }; } } diff --git a/awesome_gallery/static/src/gallery_controller.js b/awesome_gallery/static/src/gallery_controller.js index 016db468471..7ab0fd0b134 100644 --- a/awesome_gallery/static/src/gallery_controller.js +++ b/awesome_gallery/static/src/gallery_controller.js @@ -1,7 +1,8 @@ /** @odoo-module */ import { Layout } from "@web/search/layout"; -import { Component } from "@odoo/owl"; +import { useService } from "@web/core/utils/hooks"; +import { Component, onWillStart, onWillUpdateProps, useState } from "@odoo/owl"; import { standardViewProps } from "@web/views/standard_view_props"; export class GalleryController extends Component { @@ -11,4 +12,32 @@ export class GalleryController extends Component { archInfo: Object, }; static components = { Layout }; + + setup() { + this.orm = useService("orm"); + this.images = useState({ data: [] }); + onWillStart(async () => { + const { records } = await this.loadImages(this.props.domain); + this.images.data = records; + }); + + onWillUpdateProps(async (nextProps) => { + if (JSON.stringify(nextProps.domain) !== JSON.stringify(this.props.domain)) { + const { records } = await this.loadImages(nextProps.domain); + this.images.data = records; + } + }); + } + + loadImages(domain) { + return this.orm.webSearchRead(this.props.resModel, domain, { + limit: this.props.archInfo.limit, + specification: { + [this.props.archInfo.imageField]: {}, + }, + context: { + bin_size: true, + } + }); + } } diff --git a/awesome_gallery/static/src/gallery_controller.xml b/awesome_gallery/static/src/gallery_controller.xml index 273f6552015..a06179bad76 100644 --- a/awesome_gallery/static/src/gallery_controller.xml +++ b/awesome_gallery/static/src/gallery_controller.xml @@ -2,7 +2,14 @@ - + + +

+ id: + bin_size: +

+
+
From 67caf396fc392dff6921fca1aead5b9d55894b1a Mon Sep 17 00:00:00 2001 From: fdardenne Date: Wed, 18 Oct 2023 15:23:43 +0200 Subject: [PATCH 52/69] [Solution] 4.5 Solve the concurrency problem --- .../static/src/gallery_controller.js | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/awesome_gallery/static/src/gallery_controller.js b/awesome_gallery/static/src/gallery_controller.js index 7ab0fd0b134..ea04624a3c2 100644 --- a/awesome_gallery/static/src/gallery_controller.js +++ b/awesome_gallery/static/src/gallery_controller.js @@ -2,6 +2,7 @@ import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; +import { KeepLast } from "@web/core/utils/concurrency"; import { Component, onWillStart, onWillUpdateProps, useState } from "@odoo/owl"; import { standardViewProps } from "@web/views/standard_view_props"; @@ -16,6 +17,7 @@ export class GalleryController extends Component { setup() { this.orm = useService("orm"); this.images = useState({ data: [] }); + this.keeplast = new KeepLast(); onWillStart(async () => { const { records } = await this.loadImages(this.props.domain); this.images.data = records; @@ -30,14 +32,16 @@ export class GalleryController extends Component { } loadImages(domain) { - return this.orm.webSearchRead(this.props.resModel, domain, { - limit: this.props.archInfo.limit, - specification: { - [this.props.archInfo.imageField]: {}, - }, - context: { - bin_size: true, - } - }); + return this.keeplast.add( + this.orm.webSearchRead(this.props.resModel, domain, { + limit: this.props.archInfo.limit, + specification: { + [this.props.archInfo.imageField]: {}, + }, + context: { + bin_size: true, + } + }) + ); } } From 77f9ad0a32e543a29cec7c54637135f91e7f5778 Mon Sep 17 00:00:00 2001 From: "Dardenne Florent (dafl)" Date: Wed, 28 Sep 2022 10:16:53 +0200 Subject: [PATCH 53/69] [Solution] 4.6 Reorganize code --- .../static/src/gallery_controller.js | 35 +++++++------------ .../static/src/gallery_controller.xml | 7 +--- awesome_gallery/static/src/gallery_model.js | 29 +++++++++++++++ .../static/src/gallery_renderer.js | 11 ++++++ .../static/src/gallery_renderer.xml | 11 ++++++ 5 files changed, 65 insertions(+), 28 deletions(-) create mode 100644 awesome_gallery/static/src/gallery_model.js create mode 100644 awesome_gallery/static/src/gallery_renderer.js create mode 100644 awesome_gallery/static/src/gallery_renderer.xml diff --git a/awesome_gallery/static/src/gallery_controller.js b/awesome_gallery/static/src/gallery_controller.js index ea04624a3c2..e4cf760911d 100644 --- a/awesome_gallery/static/src/gallery_controller.js +++ b/awesome_gallery/static/src/gallery_controller.js @@ -2,9 +2,10 @@ import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; -import { KeepLast } from "@web/core/utils/concurrency"; import { Component, onWillStart, onWillUpdateProps, useState } from "@odoo/owl"; import { standardViewProps } from "@web/views/standard_view_props"; +import { GalleryModel } from "./gallery_model"; +import { GalleryRenderer } from "./gallery_renderer"; export class GalleryController extends Component { static template = "awesome_gallery.GalleryController"; @@ -12,36 +13,26 @@ export class GalleryController extends Component { ...standardViewProps, archInfo: Object, }; - static components = { Layout }; + static components = { Layout, GalleryRenderer }; setup() { this.orm = useService("orm"); - this.images = useState({ data: [] }); - this.keeplast = new KeepLast(); + + this.model = useState( + new GalleryModel( + this.orm, + this.props.resModel, + this.props.archInfo, + ) + ); onWillStart(async () => { - const { records } = await this.loadImages(this.props.domain); - this.images.data = records; + await this.model.load(this.props.domain); }); onWillUpdateProps(async (nextProps) => { if (JSON.stringify(nextProps.domain) !== JSON.stringify(this.props.domain)) { - const { records } = await this.loadImages(nextProps.domain); - this.images.data = records; + await this.model.load(nextProps.domain); } }); } - - loadImages(domain) { - return this.keeplast.add( - this.orm.webSearchRead(this.props.resModel, domain, { - limit: this.props.archInfo.limit, - specification: { - [this.props.archInfo.imageField]: {}, - }, - context: { - bin_size: true, - } - }) - ); - } } diff --git a/awesome_gallery/static/src/gallery_controller.xml b/awesome_gallery/static/src/gallery_controller.xml index a06179bad76..a2ea9d148ac 100644 --- a/awesome_gallery/static/src/gallery_controller.xml +++ b/awesome_gallery/static/src/gallery_controller.xml @@ -3,12 +3,7 @@ - -

- id: - bin_size: -

-
+
diff --git a/awesome_gallery/static/src/gallery_model.js b/awesome_gallery/static/src/gallery_model.js new file mode 100644 index 00000000000..94dfa113e6b --- /dev/null +++ b/awesome_gallery/static/src/gallery_model.js @@ -0,0 +1,29 @@ +/** @odoo-module */ + +import { KeepLast } from "@web/core/utils/concurrency"; + +export class GalleryModel { + constructor(orm, resModel, archInfo) { + this.orm = orm; + this.resModel = resModel; + const { imageField, limit } = archInfo; + this.imageField = imageField; + this.limit = limit; + this.keepLast = new KeepLast(); + } + + async load(domain) { + const { records } = await this.keepLast.add( + this.orm.webSearchRead(this.resModel, domain, { + limit: this.limit, + specification: { + [this.imageField]: {}, + }, + context: { + bin_size: true, + } + }) + ); + this.records = records; + } +} diff --git a/awesome_gallery/static/src/gallery_renderer.js b/awesome_gallery/static/src/gallery_renderer.js new file mode 100644 index 00000000000..737df41f71c --- /dev/null +++ b/awesome_gallery/static/src/gallery_renderer.js @@ -0,0 +1,11 @@ +/** @odoo-module */ + +import { Component } from "@odoo/owl"; +import { GalleryModel } from "./gallery_model"; + +export class GalleryRenderer extends Component { + static template = "awesome_gallery.GalleryRenderer"; + static props = { + model: GalleryModel, + } +} diff --git a/awesome_gallery/static/src/gallery_renderer.xml b/awesome_gallery/static/src/gallery_renderer.xml new file mode 100644 index 00000000000..19b1e3ee8e2 --- /dev/null +++ b/awesome_gallery/static/src/gallery_renderer.xml @@ -0,0 +1,11 @@ + + + + +

+ id: + bin_size: +

+
+
+
From 3016eee9f39d632661536918c720b98b0b616423 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Fri, 13 Oct 2023 15:02:28 +0200 Subject: [PATCH 54/69] [Solution] 4.7 Make the view extensible --- awesome_gallery/static/src/gallery_controller.js | 8 ++++---- awesome_gallery/static/src/gallery_controller.xml | 2 +- awesome_gallery/static/src/gallery_view.js | 6 ++++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/awesome_gallery/static/src/gallery_controller.js b/awesome_gallery/static/src/gallery_controller.js index e4cf760911d..6062d8a6459 100644 --- a/awesome_gallery/static/src/gallery_controller.js +++ b/awesome_gallery/static/src/gallery_controller.js @@ -4,22 +4,22 @@ import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { Component, onWillStart, onWillUpdateProps, useState } from "@odoo/owl"; import { standardViewProps } from "@web/views/standard_view_props"; -import { GalleryModel } from "./gallery_model"; -import { GalleryRenderer } from "./gallery_renderer"; export class GalleryController extends Component { static template = "awesome_gallery.GalleryController"; static props = { ...standardViewProps, archInfo: Object, + Model: Function, + Renderer: Function, }; - static components = { Layout, GalleryRenderer }; + static components = { Layout }; setup() { this.orm = useService("orm"); this.model = useState( - new GalleryModel( + new this.props.Model( this.orm, this.props.resModel, this.props.archInfo, diff --git a/awesome_gallery/static/src/gallery_controller.xml b/awesome_gallery/static/src/gallery_controller.xml index a2ea9d148ac..c5560883d4a 100644 --- a/awesome_gallery/static/src/gallery_controller.xml +++ b/awesome_gallery/static/src/gallery_controller.xml @@ -3,7 +3,7 @@ - + diff --git a/awesome_gallery/static/src/gallery_view.js b/awesome_gallery/static/src/gallery_view.js index ca6631b991a..b6248d51774 100644 --- a/awesome_gallery/static/src/gallery_view.js +++ b/awesome_gallery/static/src/gallery_view.js @@ -3,6 +3,8 @@ import { registry } from "@web/core/registry"; import { GalleryController } from "./gallery_controller"; import { GalleryArchParser } from "./gallery_arch_parser"; +import { GalleryModel } from "./gallery_model"; +import { GalleryRenderer } from "./gallery_renderer"; export const galleryView = { type: "gallery", @@ -11,6 +13,8 @@ export const galleryView = { multiRecord: true, Controller: GalleryController, ArchParser: GalleryArchParser, + Model: GalleryModel, + Renderer: GalleryRenderer, props(genericProps, view) { const { ArchParser } = view; @@ -19,6 +23,8 @@ export const galleryView = { return { ...genericProps, + Model: view.Model, + Renderer: view.Renderer, archInfo, }; }, From efe62c0a2f6eeae76455d80b2300a6516a56c62e Mon Sep 17 00:00:00 2001 From: "Dardenne Florent (dafl)" Date: Wed, 28 Sep 2022 15:45:14 +0200 Subject: [PATCH 55/69] [Solution] 4.8 Display images --- awesome_gallery/static/src/gallery_image.js | 21 +++++++++++++++++++ awesome_gallery/static/src/gallery_image.xml | 8 +++++++ .../static/src/gallery_renderer.js | 2 ++ .../static/src/gallery_renderer.xml | 13 ++++++------ 4 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 awesome_gallery/static/src/gallery_image.js create mode 100644 awesome_gallery/static/src/gallery_image.xml diff --git a/awesome_gallery/static/src/gallery_image.js b/awesome_gallery/static/src/gallery_image.js new file mode 100644 index 00000000000..e00aadde6f3 --- /dev/null +++ b/awesome_gallery/static/src/gallery_image.js @@ -0,0 +1,21 @@ +/** @odoo-module */ + +import { Component } from "@odoo/owl"; +import { url } from "@web/core/utils/urls"; +import { GalleryModel } from "./gallery_model"; + +export class GalleryImage extends Component { + static template = "awesome_gallery.GalleryImage"; + static props = { + record: Object, + model: GalleryModel, + }; + + get imageUrl() { + return url("/web/image", { + model: this.props.model.resModel, + id: this.props.record.id, + field: this.props.model.imageField, + }); + } +} diff --git a/awesome_gallery/static/src/gallery_image.xml b/awesome_gallery/static/src/gallery_image.xml new file mode 100644 index 00000000000..7290c72faf4 --- /dev/null +++ b/awesome_gallery/static/src/gallery_image.xml @@ -0,0 +1,8 @@ + + + +
+ +
+
+
diff --git a/awesome_gallery/static/src/gallery_renderer.js b/awesome_gallery/static/src/gallery_renderer.js index 737df41f71c..bbe0a2f85a5 100644 --- a/awesome_gallery/static/src/gallery_renderer.js +++ b/awesome_gallery/static/src/gallery_renderer.js @@ -2,8 +2,10 @@ import { Component } from "@odoo/owl"; import { GalleryModel } from "./gallery_model"; +import { GalleryImage } from "./gallery_image"; export class GalleryRenderer extends Component { + static components = { GalleryImage }; static template = "awesome_gallery.GalleryRenderer"; static props = { model: GalleryModel, diff --git a/awesome_gallery/static/src/gallery_renderer.xml b/awesome_gallery/static/src/gallery_renderer.xml index 19b1e3ee8e2..a7bbd331232 100644 --- a/awesome_gallery/static/src/gallery_renderer.xml +++ b/awesome_gallery/static/src/gallery_renderer.xml @@ -1,11 +1,12 @@ - -

- id: - bin_size: -

-
+
+ +
+ +
+
+
From ac465adc873d4e04aa4a9c8970c41d708f663874 Mon Sep 17 00:00:00 2001 From: "Dardenne Florent (dafl)" Date: Thu, 29 Sep 2022 08:13:25 +0200 Subject: [PATCH 56/69] [Solution] 4.9 Switch to form view on click --- awesome_gallery/static/src/gallery_image.js | 9 +++++++++ awesome_gallery/static/src/gallery_image.xml | 2 +- awesome_gallery/static/src/gallery_renderer.js | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/awesome_gallery/static/src/gallery_image.js b/awesome_gallery/static/src/gallery_image.js index e00aadde6f3..2aa9b52ee71 100644 --- a/awesome_gallery/static/src/gallery_image.js +++ b/awesome_gallery/static/src/gallery_image.js @@ -3,6 +3,7 @@ import { Component } from "@odoo/owl"; import { url } from "@web/core/utils/urls"; import { GalleryModel } from "./gallery_model"; +import { useService } from "@web/core/utils/hooks"; export class GalleryImage extends Component { static template = "awesome_gallery.GalleryImage"; @@ -11,6 +12,14 @@ export class GalleryImage extends Component { model: GalleryModel, }; + setup() { + this.action = useService("action"); + } + + onImageClick(resId) { + this.action.switchView("form", { resId }); + } + get imageUrl() { return url("/web/image", { model: this.props.model.resModel, diff --git a/awesome_gallery/static/src/gallery_image.xml b/awesome_gallery/static/src/gallery_image.xml index 7290c72faf4..f956c8214fb 100644 --- a/awesome_gallery/static/src/gallery_image.xml +++ b/awesome_gallery/static/src/gallery_image.xml @@ -1,7 +1,7 @@ -
+
diff --git a/awesome_gallery/static/src/gallery_renderer.js b/awesome_gallery/static/src/gallery_renderer.js index bbe0a2f85a5..290266c3272 100644 --- a/awesome_gallery/static/src/gallery_renderer.js +++ b/awesome_gallery/static/src/gallery_renderer.js @@ -10,4 +10,5 @@ export class GalleryRenderer extends Component { static props = { model: GalleryModel, } + } From d3e90353f377a3850789dc850f03b67849ac2c2a Mon Sep 17 00:00:00 2001 From: "Dardenne Florent (dafl)" Date: Thu, 29 Sep 2022 10:27:36 +0200 Subject: [PATCH 57/69] [Solution] 4.10 Add an optional tooltip --- .../static/src/gallery_arch_parser.js | 2 ++ .../static/src/gallery_controller.js | 1 + .../static/src/gallery_controller.xml | 2 +- awesome_gallery/static/src/gallery_image.xml | 2 +- awesome_gallery/static/src/gallery_model.js | 30 +++++++++++++++++-- awesome_gallery/views/views.xml | 2 +- 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/awesome_gallery/static/src/gallery_arch_parser.js b/awesome_gallery/static/src/gallery_arch_parser.js index 59d11b62cdf..d1e4a1a143a 100644 --- a/awesome_gallery/static/src/gallery_arch_parser.js +++ b/awesome_gallery/static/src/gallery_arch_parser.js @@ -4,9 +4,11 @@ export class GalleryArchParser { parse(xmlDoc) { const imageField = xmlDoc.getAttribute("image_field"); const limit = xmlDoc.getAttribute("limit") || 80; + const tooltipField = xmlDoc.getAttribute("tooltip_field"); return { imageField, limit, + tooltipField, }; } } diff --git a/awesome_gallery/static/src/gallery_controller.js b/awesome_gallery/static/src/gallery_controller.js index 6062d8a6459..842082aa2a2 100644 --- a/awesome_gallery/static/src/gallery_controller.js +++ b/awesome_gallery/static/src/gallery_controller.js @@ -22,6 +22,7 @@ export class GalleryController extends Component { new this.props.Model( this.orm, this.props.resModel, + this.props.fields, this.props.archInfo, ) ); diff --git a/awesome_gallery/static/src/gallery_controller.xml b/awesome_gallery/static/src/gallery_controller.xml index c5560883d4a..c171d8b9fe2 100644 --- a/awesome_gallery/static/src/gallery_controller.xml +++ b/awesome_gallery/static/src/gallery_controller.xml @@ -2,7 +2,7 @@ - + diff --git a/awesome_gallery/static/src/gallery_image.xml b/awesome_gallery/static/src/gallery_image.xml index f956c8214fb..876698065ad 100644 --- a/awesome_gallery/static/src/gallery_image.xml +++ b/awesome_gallery/static/src/gallery_image.xml @@ -1,7 +1,7 @@ -
+
diff --git a/awesome_gallery/static/src/gallery_model.js b/awesome_gallery/static/src/gallery_model.js index 94dfa113e6b..5acc42193c0 100644 --- a/awesome_gallery/static/src/gallery_model.js +++ b/awesome_gallery/static/src/gallery_model.js @@ -3,12 +3,14 @@ import { KeepLast } from "@web/core/utils/concurrency"; export class GalleryModel { - constructor(orm, resModel, archInfo) { + constructor(orm, resModel, fields, archInfo) { this.orm = orm; this.resModel = resModel; - const { imageField, limit } = archInfo; + const { imageField, limit, tooltipField } = archInfo; this.imageField = imageField; + this.fields = fields; this.limit = limit; + this.tooltipField = tooltipField; this.keepLast = new KeepLast(); } @@ -18,12 +20,34 @@ export class GalleryModel { limit: this.limit, specification: { [this.imageField]: {}, + ...( this.tooltipField ? {[this.tooltipField]: {}}: {}), }, context: { bin_size: true, } }) ); - this.records = records; + + if (!this.tooltipField) { + this.records = records; + return; + } + + switch (this.fields[this.tooltipField].type) { + case "many2one": + this.records = records.map((record) => ({ + ...record, + [this.tooltipField]: record[this.tooltipField][1], + })); + break; + case "integer": + this.records = records.map((record) => ({ + ...record, + [this.tooltipField]: String(record[this.tooltipField]), + })); + break; + default: + this.records = records; + } } } diff --git a/awesome_gallery/views/views.xml b/awesome_gallery/views/views.xml index a66decaef65..de51189a683 100644 --- a/awesome_gallery/views/views.xml +++ b/awesome_gallery/views/views.xml @@ -5,7 +5,7 @@ awesome_gallery.orders.gallery res.partner - + From d85d2031ce9309b4c5b4a9953a9f6c7ca55a0043 Mon Sep 17 00:00:00 2001 From: "Dardenne Florent (dafl)" Date: Thu, 29 Sep 2022 13:26:55 +0200 Subject: [PATCH 58/69] [Solution] 4.11 Add pagination --- awesome_gallery/static/src/gallery_controller.js | 15 +++++++++++++++ awesome_gallery/static/src/gallery_model.js | 7 +++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/awesome_gallery/static/src/gallery_controller.js b/awesome_gallery/static/src/gallery_controller.js index 842082aa2a2..94d9037956d 100644 --- a/awesome_gallery/static/src/gallery_controller.js +++ b/awesome_gallery/static/src/gallery_controller.js @@ -4,6 +4,7 @@ import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { Component, onWillStart, onWillUpdateProps, useState } from "@odoo/owl"; import { standardViewProps } from "@web/views/standard_view_props"; +import { usePager } from "@web/search/pager_hook"; export class GalleryController extends Component { static template = "awesome_gallery.GalleryController"; @@ -26,6 +27,20 @@ export class GalleryController extends Component { this.props.archInfo, ) ); + + usePager(() => { + return { + offset: this.model.pager.offset, + limit: this.model.pager.limit, + total: this.model.recordsLength, + onUpdate: async ({ offset, limit }) => { + this.model.pager.offset = offset; + this.model.pager.limit = limit; + await this.model.load(this.props.domain); + }, + }; + }); + onWillStart(async () => { await this.model.load(this.props.domain); }); diff --git a/awesome_gallery/static/src/gallery_model.js b/awesome_gallery/static/src/gallery_model.js index 5acc42193c0..d1511ace302 100644 --- a/awesome_gallery/static/src/gallery_model.js +++ b/awesome_gallery/static/src/gallery_model.js @@ -12,12 +12,14 @@ export class GalleryModel { this.limit = limit; this.tooltipField = tooltipField; this.keepLast = new KeepLast(); + this.pager = { offset: 0, limit: limit }; } async load(domain) { - const { records } = await this.keepLast.add( + const { length, records } = await this.keepLast.add( this.orm.webSearchRead(this.resModel, domain, { - limit: this.limit, + limit: this.pager.limit, + offset: this.pager.offset, specification: { [this.imageField]: {}, ...( this.tooltipField ? {[this.tooltipField]: {}}: {}), @@ -27,6 +29,7 @@ export class GalleryModel { } }) ); + this.recordsLength = length; if (!this.tooltipField) { this.records = records; From 90d7ad89a3a1c4c23b3028ff21c057a26f26e91f Mon Sep 17 00:00:00 2001 From: "Dardenne Florent (dafl)" Date: Fri, 30 Sep 2022 14:48:29 +0200 Subject: [PATCH 59/69] [Solution] 4.12 Validating views --- awesome_gallery/__init__.py | 1 + awesome_gallery/rng/gallery.rng | 17 +++++++++++++++++ awesome_gallery/validation.py | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 awesome_gallery/rng/gallery.rng create mode 100644 awesome_gallery/validation.py diff --git a/awesome_gallery/__init__.py b/awesome_gallery/__init__.py index a0fdc10fe11..9724f5e7f8d 100644 --- a/awesome_gallery/__init__.py +++ b/awesome_gallery/__init__.py @@ -1,2 +1,3 @@ # -*- coding: utf-8 -*- from . import models +from . import validation diff --git a/awesome_gallery/rng/gallery.rng b/awesome_gallery/rng/gallery.rng new file mode 100644 index 00000000000..f2e9dea28cd --- /dev/null +++ b/awesome_gallery/rng/gallery.rng @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/awesome_gallery/validation.py b/awesome_gallery/validation.py new file mode 100644 index 00000000000..f6c35a136d0 --- /dev/null +++ b/awesome_gallery/validation.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +import logging +import os + +from lxml import etree + +from odoo.loglevels import ustr +from odoo.tools import misc, view_validation + +_logger = logging.getLogger(__name__) + +_gallery_validator = None + + +@view_validation.validate('gallery') +def schema_gallery(arch, **kwargs): + """ Check the gallery view against its schema + + :type arch: etree._Element + """ + global _gallery_validator + + if _gallery_validator is None: + with misc.file_open(os.path.join('awesome_gallery', 'rng', 'gallery.rng')) as f: + _gallery_validator = etree.RelaxNG(etree.parse(f)) + + if _gallery_validator.validate(arch): + return True + + for error in _gallery_validator.error_log: + _logger.error(ustr(error)) + return False From d5d4d74cfc682981347cd2d480268f91a88740c2 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 16 Oct 2023 10:43:45 +0200 Subject: [PATCH 60/69] [Solution] 4.13 Upload button on images --- awesome_gallery/static/src/gallery_controller.js | 4 ++++ awesome_gallery/static/src/gallery_controller.xml | 2 +- awesome_gallery/static/src/gallery_image.js | 8 ++++++++ awesome_gallery/static/src/gallery_image.xml | 10 ++++++++++ awesome_gallery/static/src/gallery_model.js | 15 +++++++++++++++ awesome_gallery/static/src/gallery_renderer.js | 1 + awesome_gallery/static/src/gallery_renderer.xml | 2 +- 7 files changed, 40 insertions(+), 2 deletions(-) diff --git a/awesome_gallery/static/src/gallery_controller.js b/awesome_gallery/static/src/gallery_controller.js index 94d9037956d..715b35ea32d 100644 --- a/awesome_gallery/static/src/gallery_controller.js +++ b/awesome_gallery/static/src/gallery_controller.js @@ -51,4 +51,8 @@ export class GalleryController extends Component { } }); } + + async onImageUpload(record_id, image_binary) { + this.model.uploadImage(record_id, image_binary, this.props.domain); + } } diff --git a/awesome_gallery/static/src/gallery_controller.xml b/awesome_gallery/static/src/gallery_controller.xml index c171d8b9fe2..1f49aa6a371 100644 --- a/awesome_gallery/static/src/gallery_controller.xml +++ b/awesome_gallery/static/src/gallery_controller.xml @@ -3,7 +3,7 @@ - + diff --git a/awesome_gallery/static/src/gallery_image.js b/awesome_gallery/static/src/gallery_image.js index 2aa9b52ee71..dddf2506544 100644 --- a/awesome_gallery/static/src/gallery_image.js +++ b/awesome_gallery/static/src/gallery_image.js @@ -4,12 +4,15 @@ import { Component } from "@odoo/owl"; import { url } from "@web/core/utils/urls"; import { GalleryModel } from "./gallery_model"; import { useService } from "@web/core/utils/hooks"; +import { FileUploader } from "@web/views/fields/file_handler"; export class GalleryImage extends Component { + static components = { FileUploader } static template = "awesome_gallery.GalleryImage"; static props = { record: Object, model: GalleryModel, + onImageUpload: Function, }; setup() { @@ -25,6 +28,11 @@ export class GalleryImage extends Component { model: this.props.model.resModel, id: this.props.record.id, field: this.props.model.imageField, + unique: this.props.record.write_date, }); } + + async _onFileUploaded({ data }) { + await this.props.onImageUpload(this.props.record.id, data); + } } diff --git a/awesome_gallery/static/src/gallery_image.xml b/awesome_gallery/static/src/gallery_image.xml index 876698065ad..a4a157a5a73 100644 --- a/awesome_gallery/static/src/gallery_image.xml +++ b/awesome_gallery/static/src/gallery_image.xml @@ -3,6 +3,16 @@
+
+ + + + + +
diff --git a/awesome_gallery/static/src/gallery_model.js b/awesome_gallery/static/src/gallery_model.js index d1511ace302..099323efb83 100644 --- a/awesome_gallery/static/src/gallery_model.js +++ b/awesome_gallery/static/src/gallery_model.js @@ -23,6 +23,7 @@ export class GalleryModel { specification: { [this.imageField]: {}, ...( this.tooltipField ? {[this.tooltipField]: {}}: {}), + write_date: {} }, context: { bin_size: true, @@ -53,4 +54,18 @@ export class GalleryModel { this.records = records; } } + + async uploadImage(record_id, image_binary, domain) { + await this.orm.webSave( + this.resModel, + [record_id], + { + [this.imageField]: image_binary, + }, + { + specification: {}, + } + ) + await this.load(domain); + } } diff --git a/awesome_gallery/static/src/gallery_renderer.js b/awesome_gallery/static/src/gallery_renderer.js index 290266c3272..113ba991634 100644 --- a/awesome_gallery/static/src/gallery_renderer.js +++ b/awesome_gallery/static/src/gallery_renderer.js @@ -9,6 +9,7 @@ export class GalleryRenderer extends Component { static template = "awesome_gallery.GalleryRenderer"; static props = { model: GalleryModel, + onImageUpload: Function, } } diff --git a/awesome_gallery/static/src/gallery_renderer.xml b/awesome_gallery/static/src/gallery_renderer.xml index a7bbd331232..cf4f0c9d3e4 100644 --- a/awesome_gallery/static/src/gallery_renderer.xml +++ b/awesome_gallery/static/src/gallery_renderer.xml @@ -4,7 +4,7 @@
- +
From dba2e6227d1ac0ba64d3e13b98872d93ec465c2c Mon Sep 17 00:00:00 2001 From: fdardenne Date: Wed, 18 Oct 2023 11:18:26 +0200 Subject: [PATCH 61/69] [Solution] 4.14 Advanced tooltip template --- awesome_gallery/rng/gallery.rng | 36 ++++++++++++++++- .../static/src/gallery_arch_parser.js | 16 +++++++- .../static/src/gallery_controller.xml | 2 +- awesome_gallery/static/src/gallery_image.js | 12 ++++++ awesome_gallery/static/src/gallery_image.xml | 2 +- awesome_gallery/static/src/gallery_model.js | 40 +++++-------------- .../static/src/gallery_renderer.js | 20 ++++++++++ .../static/src/gallery_renderer.xml | 2 +- awesome_gallery/views/views.xml | 17 +++++--- 9 files changed, 106 insertions(+), 41 deletions(-) diff --git a/awesome_gallery/rng/gallery.rng b/awesome_gallery/rng/gallery.rng index f2e9dea28cd..a2dfebb0738 100644 --- a/awesome_gallery/rng/gallery.rng +++ b/awesome_gallery/rng/gallery.rng @@ -5,10 +5,42 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/awesome_gallery/static/src/gallery_arch_parser.js b/awesome_gallery/static/src/gallery_arch_parser.js index d1e4a1a143a..37c66e2c2ae 100644 --- a/awesome_gallery/static/src/gallery_arch_parser.js +++ b/awesome_gallery/static/src/gallery_arch_parser.js @@ -1,14 +1,26 @@ /** @odoo-module */ +import { visitXML } from "@web/core/utils/xml"; + export class GalleryArchParser { parse(xmlDoc) { const imageField = xmlDoc.getAttribute("image_field"); const limit = xmlDoc.getAttribute("limit") || 80; - const tooltipField = xmlDoc.getAttribute("tooltip_field"); + const fieldsForTooltip = []; + let tooltipTemplate = undefined; + visitXML(xmlDoc, (node) => { + if (node.tagName === "field") { + fieldsForTooltip.push(node.getAttribute("name")); + } + if (node.tagName === "tooltip-template") { + tooltipTemplate = node; + } + }) return { imageField, limit, - tooltipField, + fieldsForTooltip, + tooltipTemplate, }; } } diff --git a/awesome_gallery/static/src/gallery_controller.xml b/awesome_gallery/static/src/gallery_controller.xml index 1f49aa6a371..a6aa024533d 100644 --- a/awesome_gallery/static/src/gallery_controller.xml +++ b/awesome_gallery/static/src/gallery_controller.xml @@ -3,7 +3,7 @@ - + diff --git a/awesome_gallery/static/src/gallery_image.js b/awesome_gallery/static/src/gallery_image.js index dddf2506544..39264948d1d 100644 --- a/awesome_gallery/static/src/gallery_image.js +++ b/awesome_gallery/static/src/gallery_image.js @@ -5,6 +5,7 @@ import { url } from "@web/core/utils/urls"; import { GalleryModel } from "./gallery_model"; import { useService } from "@web/core/utils/hooks"; import { FileUploader } from "@web/views/fields/file_handler"; +import { useTooltip } from "@web/core/tooltip/tooltip_hook"; export class GalleryImage extends Component { static components = { FileUploader } @@ -13,10 +14,21 @@ export class GalleryImage extends Component { record: Object, model: GalleryModel, onImageUpload: Function, + tooltipTemplate: { + optional: true, + type: String, + }, }; setup() { this.action = useService("action"); + + if (this.props.tooltipTemplate) { + useTooltip("tooltip", { + info: { record: this.props.record }, + template: this.props.tooltipTemplate, + }); + } } onImageClick(resId) { diff --git a/awesome_gallery/static/src/gallery_image.xml b/awesome_gallery/static/src/gallery_image.xml index a4a157a5a73..dcbf0a8be4f 100644 --- a/awesome_gallery/static/src/gallery_image.xml +++ b/awesome_gallery/static/src/gallery_image.xml @@ -1,7 +1,7 @@ -
+
({ - ...record, - [this.tooltipField]: record[this.tooltipField][1], - })); - break; - case "integer": - this.records = records.map((record) => ({ - ...record, - [this.tooltipField]: String(record[this.tooltipField]), - })); - break; - default: - this.records = records; - } + this.records = records; } async uploadImage(record_id, image_binary, domain) { diff --git a/awesome_gallery/static/src/gallery_renderer.js b/awesome_gallery/static/src/gallery_renderer.js index 113ba991634..a6f199ae583 100644 --- a/awesome_gallery/static/src/gallery_renderer.js +++ b/awesome_gallery/static/src/gallery_renderer.js @@ -3,6 +3,8 @@ import { Component } from "@odoo/owl"; import { GalleryModel } from "./gallery_model"; import { GalleryImage } from "./gallery_image"; +import { createElement } from "@web/core/utils/xml"; +import { xml } from "@odoo/owl"; export class GalleryRenderer extends Component { static components = { GalleryImage }; @@ -10,6 +12,24 @@ export class GalleryRenderer extends Component { static props = { model: GalleryModel, onImageUpload: Function, + tooltipTemplate: { + optional: true, + type: Element, + }, + } + + setup() { + if (this.props.tooltipTemplate) { + const fieldsToReplace = this.props.tooltipTemplate.querySelectorAll("field"); + for (const field of fieldsToReplace) { + const fieldName = field.getAttribute("name") + const t = document.createElement("t") + t.setAttribute("t-esc", `record.${fieldName}`) + field.replaceWith(t); + } + const tooltipHTML = createElement("t", [this.props.tooltipTemplate]).outerHTML + this.owlTooltipTemplate = xml`${tooltipHTML}` + } } } diff --git a/awesome_gallery/static/src/gallery_renderer.xml b/awesome_gallery/static/src/gallery_renderer.xml index cf4f0c9d3e4..5daf3cc8ae8 100644 --- a/awesome_gallery/static/src/gallery_renderer.xml +++ b/awesome_gallery/static/src/gallery_renderer.xml @@ -4,7 +4,7 @@
- +
diff --git a/awesome_gallery/views/views.xml b/awesome_gallery/views/views.xml index de51189a683..df20dec92a1 100644 --- a/awesome_gallery/views/views.xml +++ b/awesome_gallery/views/views.xml @@ -2,11 +2,18 @@ - awesome_gallery.orders.gallery - res.partner - - - + awesome_gallery.orders.gallery + res.partner + + + + + +

name:

+

e-mail:

+
+
+
From 651d92a1b835b9ae625ef9b71e2b2576ebd27901 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 23 Oct 2023 14:14:38 +0200 Subject: [PATCH 62/69] [Solution] 5.1: Create a new kanban view --- awesome_kanban/static/src/awesome_kanban_view.js | 11 ++++++++++- awesome_kanban/static/src/kanban_controller.js | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 awesome_kanban/static/src/kanban_controller.js diff --git a/awesome_kanban/static/src/awesome_kanban_view.js b/awesome_kanban/static/src/awesome_kanban_view.js index 9f33fc1300b..52887d55f5a 100644 --- a/awesome_kanban/static/src/awesome_kanban_view.js +++ b/awesome_kanban/static/src/awesome_kanban_view.js @@ -1,3 +1,12 @@ /** @odoo-module */ -// TODO: Define here your AwesomeKanban view +import { kanbanView } from "@web/views/kanban/kanban_view"; +import { registry } from "@web/core/registry"; +import { AwesomeKanbanController } from "./kanban_controller"; + +const awesomeKanbanController = { + ...kanbanView, + Controller: AwesomeKanbanController, +}; + +registry.category("views").add("awesome_kanban", awesomeKanbanController); diff --git a/awesome_kanban/static/src/kanban_controller.js b/awesome_kanban/static/src/kanban_controller.js new file mode 100644 index 00000000000..de51ecf6816 --- /dev/null +++ b/awesome_kanban/static/src/kanban_controller.js @@ -0,0 +1,5 @@ +/** @odoo-module */ + +import { KanbanController } from "@web/views/kanban/kanban_controller"; + +export class AwesomeKanbanController extends KanbanController {} From a2e866e1526e85af353a0a2c57708292ebe45464 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 23 Oct 2023 14:39:40 +0200 Subject: [PATCH 63/69] [Solution] 5.2: Create a CustomerList component --- .../static/src/customer_list/customer_list.js | 12 ++++++++++++ .../static/src/customer_list/customer_list.xml | 8 ++++++++ awesome_kanban/static/src/kanban_controller.js | 14 +++++++++++++- awesome_kanban/static/src/kanban_controller.scss | 5 +++++ awesome_kanban/static/src/kanban_controller.xml | 10 ++++++++++ 5 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 awesome_kanban/static/src/customer_list/customer_list.js create mode 100644 awesome_kanban/static/src/customer_list/customer_list.xml create mode 100644 awesome_kanban/static/src/kanban_controller.scss create mode 100644 awesome_kanban/static/src/kanban_controller.xml diff --git a/awesome_kanban/static/src/customer_list/customer_list.js b/awesome_kanban/static/src/customer_list/customer_list.js new file mode 100644 index 00000000000..560da540abb --- /dev/null +++ b/awesome_kanban/static/src/customer_list/customer_list.js @@ -0,0 +1,12 @@ +/** @odoo-module */ + +import { Component } from "@odoo/owl"; + +export class CustomerList extends Component { + static template = "awesome_kanban.CustomerList"; + static props = { + selectCustomer: { + type: Function, + }, + }; +} diff --git a/awesome_kanban/static/src/customer_list/customer_list.xml b/awesome_kanban/static/src/customer_list/customer_list.xml new file mode 100644 index 00000000000..0fdbc5e0593 --- /dev/null +++ b/awesome_kanban/static/src/customer_list/customer_list.xml @@ -0,0 +1,8 @@ + + + +
+ Hello owl +
+
+
diff --git a/awesome_kanban/static/src/kanban_controller.js b/awesome_kanban/static/src/kanban_controller.js index de51ecf6816..3224a801ed2 100644 --- a/awesome_kanban/static/src/kanban_controller.js +++ b/awesome_kanban/static/src/kanban_controller.js @@ -1,5 +1,17 @@ /** @odoo-module */ import { KanbanController } from "@web/views/kanban/kanban_controller"; +import { CustomerList } from "./customer_list/customer_list"; -export class AwesomeKanbanController extends KanbanController {} +export class AwesomeKanbanController extends KanbanController { + static components = { ...KanbanController.components, CustomerList} + static template = "awesome_kanban.AwesomeKanbanController"; + + setup() { + super.setup(); + } + + selectCustomer(customer_id) { + console.log(customer_id); + } +} diff --git a/awesome_kanban/static/src/kanban_controller.scss b/awesome_kanban/static/src/kanban_controller.scss new file mode 100644 index 00000000000..75199697e7c --- /dev/null +++ b/awesome_kanban/static/src/kanban_controller.scss @@ -0,0 +1,5 @@ + +.o_awesome_kanban_sidebar { + width: 300px; + float: left; +} diff --git a/awesome_kanban/static/src/kanban_controller.xml b/awesome_kanban/static/src/kanban_controller.xml new file mode 100644 index 00000000000..b70cd567f10 --- /dev/null +++ b/awesome_kanban/static/src/kanban_controller.xml @@ -0,0 +1,10 @@ + + + + +
+ +
+
+
+
From 76f4b4b902a43203255500d9e53984a1702696ba Mon Sep 17 00:00:00 2001 From: fdardenne Date: Thu, 26 Oct 2023 14:02:05 +0200 Subject: [PATCH 64/69] [Solution] 5.3: Load and display data --- .../static/src/customer_list/customer_list.js | 10 +++++++++- .../static/src/customer_list/customer_list.scss | 5 +++++ .../static/src/customer_list/customer_list.xml | 17 ++++++++++++++--- 3 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 awesome_kanban/static/src/customer_list/customer_list.scss diff --git a/awesome_kanban/static/src/customer_list/customer_list.js b/awesome_kanban/static/src/customer_list/customer_list.js index 560da540abb..53b32ac2364 100644 --- a/awesome_kanban/static/src/customer_list/customer_list.js +++ b/awesome_kanban/static/src/customer_list/customer_list.js @@ -1,6 +1,7 @@ /** @odoo-module */ -import { Component } from "@odoo/owl"; +import { useService } from "@web/core/utils/hooks"; +import { Component, onWillStart } from "@odoo/owl"; export class CustomerList extends Component { static template = "awesome_kanban.CustomerList"; @@ -9,4 +10,11 @@ export class CustomerList extends Component { type: Function, }, }; + + setup() { + this.orm = useService("orm"); + onWillStart(async () => { + this.partners = await this.orm.searchRead("res.partner", [], ["display_name"]); + }) + } } diff --git a/awesome_kanban/static/src/customer_list/customer_list.scss b/awesome_kanban/static/src/customer_list/customer_list.scss new file mode 100644 index 00000000000..293a76606d2 --- /dev/null +++ b/awesome_kanban/static/src/customer_list/customer_list.scss @@ -0,0 +1,5 @@ +.o_awesome_kanban_customer_hover { + &:hover { + background-color: $gray-200; + } +} diff --git a/awesome_kanban/static/src/customer_list/customer_list.xml b/awesome_kanban/static/src/customer_list/customer_list.xml index 0fdbc5e0593..2789a6e2882 100644 --- a/awesome_kanban/static/src/customer_list/customer_list.xml +++ b/awesome_kanban/static/src/customer_list/customer_list.xml @@ -1,8 +1,19 @@ -
- Hello owl -
+ + + + + + + + + + +
+ Customers +
+
From 9085cf35e2830a96a8ff97da24eb4d3edfc1c294 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Fri, 27 Oct 2023 14:11:19 +0200 Subject: [PATCH 65/69] [Solution] 5.4: Update the main kanban view --- .../static/src/customer_list/customer_list.xml | 2 +- awesome_kanban/static/src/kanban_controller.js | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/awesome_kanban/static/src/customer_list/customer_list.xml b/awesome_kanban/static/src/customer_list/customer_list.xml index 2789a6e2882..e9fdd737d94 100644 --- a/awesome_kanban/static/src/customer_list/customer_list.xml +++ b/awesome_kanban/static/src/customer_list/customer_list.xml @@ -11,7 +11,7 @@ - + diff --git a/awesome_kanban/static/src/kanban_controller.js b/awesome_kanban/static/src/kanban_controller.js index 3224a801ed2..0a2cf61cd87 100644 --- a/awesome_kanban/static/src/kanban_controller.js +++ b/awesome_kanban/static/src/kanban_controller.js @@ -9,9 +9,22 @@ export class AwesomeKanbanController extends KanbanController { setup() { super.setup(); + this.searchKey = Symbol("isFromAwesomeKanban"); } - selectCustomer(customer_id) { - console.log(customer_id); + selectCustomer(partner_id, partner_name) { + const customerFilters = this.env.searchModel.getSearchItems((searchItem) => + searchItem[this.searchKey] + ); + for (const customerFilter of customerFilters) { + if (customerFilter.isActive) { + this.env.searchModel.toggleSearchItem(customerFilter.id); + } + } + this.env.searchModel.createNewFilters([{ + description: partner_name, + domain: [["partner_id", "=", partner_id]], + [this.searchKey]: true, + }]) } } From 3c61c5416c146808340ec750bbd08c7375129768 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 30 Oct 2023 09:43:05 +0100 Subject: [PATCH 66/69] [Solution] 5.5: Only display customers which have an active order --- .../static/src/customer_list/customer_list.js | 19 +++++++++++++++++-- .../src/customer_list/customer_list.xml | 10 ++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/awesome_kanban/static/src/customer_list/customer_list.js b/awesome_kanban/static/src/customer_list/customer_list.js index 53b32ac2364..773cb68ab80 100644 --- a/awesome_kanban/static/src/customer_list/customer_list.js +++ b/awesome_kanban/static/src/customer_list/customer_list.js @@ -1,7 +1,8 @@ /** @odoo-module */ import { useService } from "@web/core/utils/hooks"; -import { Component, onWillStart } from "@odoo/owl"; +import { Component, onWillStart, useState} from "@odoo/owl"; +import { KeepLast } from "@web/core/utils/concurrency"; export class CustomerList extends Component { static template = "awesome_kanban.CustomerList"; @@ -13,8 +14,22 @@ export class CustomerList extends Component { setup() { this.orm = useService("orm"); + this.partners = useState({ data: [] }); + this.keepLast = new KeepLast(); + onWillStart(async () => { - this.partners = await this.orm.searchRead("res.partner", [], ["display_name"]); + this.partners.data = await this.loadCustomers([]); }) } + + async onChangeActiveCustomers(ev) { + const checked = ev.target.checked; + const domain = checked ? [["opportunity_ids", "!=", false]] : []; + this.partners.data = await this.keepLast.add(this.loadCustomers(domain)); + } + + loadCustomers(domain) { + return this.orm.searchRead("res.partner", domain, ["display_name"]); + } + } diff --git a/awesome_kanban/static/src/customer_list/customer_list.xml b/awesome_kanban/static/src/customer_list/customer_list.xml index e9fdd737d94..b489645f6d6 100644 --- a/awesome_kanban/static/src/customer_list/customer_list.xml +++ b/awesome_kanban/static/src/customer_list/customer_list.xml @@ -5,12 +5,18 @@ - Customers + Customers with active orders +
+ + +
- + From 0b949e54269927fc101409e2fad1bfdf82b9b3be Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 30 Oct 2023 10:00:26 +0100 Subject: [PATCH 67/69] [Solution] 5.6. Add a search bar to the customer list --- .../static/src/customer_list/customer_list.js | 22 +++++++++++++++++++ .../src/customer_list/customer_list.xml | 7 +++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/awesome_kanban/static/src/customer_list/customer_list.js b/awesome_kanban/static/src/customer_list/customer_list.js index 773cb68ab80..8f449991ed6 100644 --- a/awesome_kanban/static/src/customer_list/customer_list.js +++ b/awesome_kanban/static/src/customer_list/customer_list.js @@ -3,6 +3,7 @@ import { useService } from "@web/core/utils/hooks"; import { Component, onWillStart, useState} from "@odoo/owl"; import { KeepLast } from "@web/core/utils/concurrency"; +import { fuzzyLookup } from "@web/core/utils/search"; export class CustomerList extends Component { static template = "awesome_kanban.CustomerList"; @@ -15,10 +16,13 @@ export class CustomerList extends Component { setup() { this.orm = useService("orm"); this.partners = useState({ data: [] }); + this.displayedPartners = useState({ data: [] }); + this.filterName = ""; this.keepLast = new KeepLast(); onWillStart(async () => { this.partners.data = await this.loadCustomers([]); + this.displayedPartners.data = this.partners.data; }) } @@ -26,6 +30,24 @@ export class CustomerList extends Component { const checked = ev.target.checked; const domain = checked ? [["opportunity_ids", "!=", false]] : []; this.partners.data = await this.keepLast.add(this.loadCustomers(domain)); + this.filterCustomers(this.filterName); + } + + onCustomerFilter(ev) { + this.filterName = ev.target.value; + this.filterCustomers(ev.target.value); + } + + filterCustomers(name) { + if (name) { + this.displayedPartners.data = fuzzyLookup( + name, + this.partners.data, + (partner) => partner.display_name + ); + } else { + this.displayedPartners.data = this.partners.data; + } } loadCustomers(domain) { diff --git a/awesome_kanban/static/src/customer_list/customer_list.xml b/awesome_kanban/static/src/customer_list/customer_list.xml index b489645f6d6..721d427e3e1 100644 --- a/awesome_kanban/static/src/customer_list/customer_list.xml +++ b/awesome_kanban/static/src/customer_list/customer_list.xml @@ -16,7 +16,12 @@ - + + + + + + From f2f8d99794ee9f3bb3bd560c173065d8b1aef300 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 30 Oct 2023 10:25:48 +0100 Subject: [PATCH 68/69] [Solution] 5.7: Refactor the code to use t-model --- .../static/src/customer_list/customer_list.js | 33 ++++++++----------- .../src/customer_list/customer_list.xml | 4 +-- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/awesome_kanban/static/src/customer_list/customer_list.js b/awesome_kanban/static/src/customer_list/customer_list.js index 8f449991ed6..8aaf9a940bf 100644 --- a/awesome_kanban/static/src/customer_list/customer_list.js +++ b/awesome_kanban/static/src/customer_list/customer_list.js @@ -16,41 +16,36 @@ export class CustomerList extends Component { setup() { this.orm = useService("orm"); this.partners = useState({ data: [] }); - this.displayedPartners = useState({ data: [] }); - this.filterName = ""; this.keepLast = new KeepLast(); + this.state = useState({ + searchString: "", + displayActiveCustomers: false, + }) onWillStart(async () => { - this.partners.data = await this.loadCustomers([]); - this.displayedPartners.data = this.partners.data; + this.partners.data = await this.loadCustomers(); }) } - async onChangeActiveCustomers(ev) { - const checked = ev.target.checked; - const domain = checked ? [["opportunity_ids", "!=", false]] : []; - this.partners.data = await this.keepLast.add(this.loadCustomers(domain)); - this.filterCustomers(this.filterName); + get displayedPartners() { + return this.filterCustomers(this.state.searchString); } - onCustomerFilter(ev) { - this.filterName = ev.target.value; - this.filterCustomers(ev.target.value); + async onChangeActiveCustomers(ev) { + this.state.displayActiveCustomers = ev.target.checked; + this.partners.data = await this.keepLast.add(this.loadCustomers()); } filterCustomers(name) { if (name) { - this.displayedPartners.data = fuzzyLookup( - name, - this.partners.data, - (partner) => partner.display_name - ); + return fuzzyLookup(name, this.partners.data, (partner) => partner.display_name); } else { - this.displayedPartners.data = this.partners.data; + return this.partners.data; } } - loadCustomers(domain) { + loadCustomers() { + const domain = this.state.displayActiveCustomers ? [["opportunity_ids", "!=", false]] : []; return this.orm.searchRead("res.partner", domain, ["display_name"]); } diff --git a/awesome_kanban/static/src/customer_list/customer_list.xml b/awesome_kanban/static/src/customer_list/customer_list.xml index 721d427e3e1..e865a262f22 100644 --- a/awesome_kanban/static/src/customer_list/customer_list.xml +++ b/awesome_kanban/static/src/customer_list/customer_list.xml @@ -18,10 +18,10 @@ - + - + From 5e9d4bd639cf8605f12ff020a828a969b5a2c497 Mon Sep 17 00:00:00 2001 From: fdardenne Date: Mon, 30 Oct 2023 10:47:08 +0100 Subject: [PATCH 69/69] [Solution] 5.8: Paginate customers! --- .../static/src/customer_list/customer_list.js | 27 +++++++++++++++++-- .../src/customer_list/customer_list.xml | 1 + 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/awesome_kanban/static/src/customer_list/customer_list.js b/awesome_kanban/static/src/customer_list/customer_list.js index 8aaf9a940bf..4ee29f0497a 100644 --- a/awesome_kanban/static/src/customer_list/customer_list.js +++ b/awesome_kanban/static/src/customer_list/customer_list.js @@ -4,8 +4,10 @@ import { useService } from "@web/core/utils/hooks"; import { Component, onWillStart, useState} from "@odoo/owl"; import { KeepLast } from "@web/core/utils/concurrency"; import { fuzzyLookup } from "@web/core/utils/search"; +import { Pager } from "@web/core/pager/pager"; export class CustomerList extends Component { + static components = { Pager }; static template = "awesome_kanban.CustomerList"; static props = { selectCustomer: { @@ -16,6 +18,7 @@ export class CustomerList extends Component { setup() { this.orm = useService("orm"); this.partners = useState({ data: [] }); + this.pager = useState({ offset: 0, limit: 20 }); this.keepLast = new KeepLast(); this.state = useState({ searchString: "", @@ -23,7 +26,9 @@ export class CustomerList extends Component { }) onWillStart(async () => { - this.partners.data = await this.loadCustomers(); + const { length, records } = await this.loadCustomers(); + this.partners.data = records; + this.pager.total = length; }) } @@ -34,6 +39,10 @@ export class CustomerList extends Component { async onChangeActiveCustomers(ev) { this.state.displayActiveCustomers = ev.target.checked; this.partners.data = await this.keepLast.add(this.loadCustomers()); + this.pager.offset = 0; + const { length, records } = await this.keepLast.add(this.loadCustomers()); + this.partners.data = records; + this.pager.total = length; } filterCustomers(name) { @@ -45,8 +54,22 @@ export class CustomerList extends Component { } loadCustomers() { + const { limit, offset } = this.pager; const domain = this.state.displayActiveCustomers ? [["opportunity_ids", "!=", false]] : []; - return this.orm.searchRead("res.partner", domain, ["display_name"]); + return this.orm.webSearchRead("res.partner", domain, { + specification: { + "display_name": {}, + }, + limit, + offset, + }) } + + async onUpdatePager(newState) { + Object.assign(this.pager, newState); + const { records } = await this.loadCustomers(); + this.partners.data = records; + this.filterCustomers(this.filterName); + } } diff --git a/awesome_kanban/static/src/customer_list/customer_list.xml b/awesome_kanban/static/src/customer_list/customer_list.xml index e865a262f22..fddfa9e1c54 100644 --- a/awesome_kanban/static/src/customer_list/customer_list.xml +++ b/awesome_kanban/static/src/customer_list/customer_list.xml @@ -12,6 +12,7 @@ Active customers
+