[IMP] developer/tutorials: separate js framework tutorial in two parts
This commit splits the 7 chapters of the JS tutorial in two smaller and more focused tutorials: - a basic one (Discover the JS framework) - and an advanced one (Master the odoo web framework) closes odoo/documentation#4243 Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
@ -10,6 +10,7 @@ Tutorials
|
||||
|
||||
tutorials/getting_started
|
||||
tutorials/discover_js_framework
|
||||
tutorials/master_odoo_web_framework
|
||||
tutorials/define_module_data
|
||||
tutorials/restrict_data_access
|
||||
tutorials/unit_tests
|
||||
@ -31,9 +32,16 @@ Tutorials
|
||||
:tag: Beginner
|
||||
:large:
|
||||
|
||||
Learn everything you need to know about the JavaScript framework of Odoo. This tutorial will
|
||||
teach you how to build custom components and views, give life to your application, and even
|
||||
re-introduce the kitten mode.
|
||||
Learn the basics of the JavaScript framework of Odoo. This tutorial will teach you how to work
|
||||
with Owl components and introduce the basic principles underlying the Odoo JavaScript
|
||||
codebase.
|
||||
|
||||
.. card:: Master the Odoo Web Framework
|
||||
:target: tutorials/master_odoo_web_framework
|
||||
:tag: Advanced
|
||||
|
||||
Become an expert in the Odoo Web Framework. A large variety of features are covered such as
|
||||
fields, views, and even the kitten mode.
|
||||
|
||||
.. card:: Define module data
|
||||
:target: tutorials/define_module_data
|
||||
|
@ -1,8 +1,8 @@
|
||||
:show-content:
|
||||
|
||||
=================================
|
||||
Discover the JavaScript Framework
|
||||
=================================
|
||||
=========================
|
||||
Discover the JS Framework
|
||||
=========================
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
@ -10,50 +10,36 @@ Discover the JavaScript Framework
|
||||
|
||||
discover_js_framework/*
|
||||
|
||||
For this training, we will step into the shoes of the IT staff at the fictional company Awesome
|
||||
T-Shirt, which is dedicated to printing custom t-shirts for online customers. The Awesome T-Shirt
|
||||
company uses Odoo to manage orders and has created a dedicated Odoo module to manage their workflow.
|
||||
The project is currently a simple kanban view, with a few columns.
|
||||
This tutorial is designed to introduce you to the basics of the Odoo Javascript framework. Whether
|
||||
you are new to the framework or have some prior experience, this tutorial will provide you with a
|
||||
solid foundation for using the Odoo JavaScript framework in your projects.
|
||||
|
||||
The usual process is as follows: a customer looking for a nice t-shirt can simply order it from the
|
||||
Awesome T-Shirt site and give the url for any image they want. They must also fill in some basic
|
||||
information, such as the desired size and quantity of t-shirts. Once they have confirmed their
|
||||
order, and once the payment has been validated, the system will create a task in our application.
|
||||
This tutorial is divided into two parts. The first part covers the basics of Owl components, which
|
||||
are a key part of the Odoo JS framework. Owl components are reusable UI components that can be used
|
||||
to build complex web interfaces quickly and efficiently. We will explore how to create and use Owl
|
||||
components in Odoo.
|
||||
|
||||
The big boss of Awesome T-shirt, Bafien Carpink, is unhappy with our implementation. He believes
|
||||
that by micromanaging more, he will be able to get more revenue from his employees. As the IT staff
|
||||
for Awesome T-shirt, we are responsible with improving the system. Various independent tasks must be
|
||||
performed.
|
||||
The second part of the tutorial focuses on creating a dashboard using various features of Odoo.
|
||||
Dashboards are an essential part of any web application, and provide a nice starting point to use
|
||||
and interact with the Odoo codebase.
|
||||
|
||||
Let us now practice our Odoo skills!
|
||||
This tutorial assumes that you have some basic knowledge of development with Odoo in general
|
||||
(models, controllers, QWeb, ...). If you are new to Odoo, we recommend that you start with the
|
||||
:doc:`Getting started </developer/tutorials/getting_started>` tutorial before proceeding with this
|
||||
one.
|
||||
|
||||
.. _howtos/discover_js_framework/setup:
|
||||
.. _tutorials/discover_js_framework/setup:
|
||||
|
||||
Setup
|
||||
=====
|
||||
|
||||
To follow the training, it is necessary to have basic knowledge on Git and a recent version of Odoo
|
||||
installed. If you have not installed it yet, we recommend installing it from :ref:`source
|
||||
<setup/install/source>` (:dfn:`running Odoo from source code`).
|
||||
#. Clone the `official Odoo tutorials repository <https://github.com/odoo/tutorials>`_ and switch to
|
||||
the branch `{BRANCH}`.
|
||||
#. Add the cloned repository to the :option:`--addons-path <odoo-bin --addons-path>`.
|
||||
#. Start a new Odoo database and install the modules `owl_playground` and `awesome_tshirt`.
|
||||
|
||||
To setup your development environment, you can also follow the dedicated chapter in :doc:`Getting
|
||||
Started: Development environment setup <../tutorials/getting_started/02_setup>` tutorial.
|
||||
Content
|
||||
=======
|
||||
|
||||
The last things to do are:
|
||||
|
||||
- Clone the `official Odoo tutorials repository <https://github.com/odoo/tutorials>`_ and switch to
|
||||
the branch `{BRANCH}`.
|
||||
- Add the cloned repository to the :option:`--addons-path <odoo-bin --addons-path>`.
|
||||
- Start a new Odoo database and install the modules `owl_playground`, `awesome_tshirt`, and
|
||||
`awesome_gallery`.
|
||||
|
||||
Exercises
|
||||
=========
|
||||
|
||||
* :doc:`discover_js_framework/01_components`
|
||||
* :doc:`discover_js_framework/02_odoo_web_framework`
|
||||
* :doc:`discover_js_framework/03_fields_and_views`
|
||||
* :doc:`discover_js_framework/04_miscellaneous`
|
||||
* :doc:`discover_js_framework/05_custom_kanban_view`
|
||||
* :doc:`discover_js_framework/06_creating_view_from_scratch`
|
||||
* :doc:`discover_js_framework/07_testing`
|
||||
- :doc:`discover_js_framework/01_owl_components`
|
||||
- :doc:`discover_js_framework/02_web_framework`
|
||||
|
@ -1,6 +1,6 @@
|
||||
=====================
|
||||
Chapter 1: Components
|
||||
=====================
|
||||
=========================
|
||||
Chapter 1: Owl Components
|
||||
=========================
|
||||
|
||||
This chapter introduces the `Owl framework <https://github.com/odoo/owl>`_, a tailor-made component
|
||||
system for Odoo. The main building blocks of OWL are `components
|
||||
@ -10,58 +10,64 @@ In Owl, every part of user interface is managed by a component: they hold the lo
|
||||
templates that are used to render the user interface. In practice, a component is represented by a
|
||||
small JavaScript class subclassing the `Component` class.
|
||||
|
||||
.. _jstraining/chapter1/intro_example:
|
||||
|
||||
.. example::
|
||||
The `Counter` class implements a component that holds the internal state of a counter and defines
|
||||
how it should be incremented.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const { Component, useState } = owl;
|
||||
|
||||
class Counter extends Component {
|
||||
static template = "my_module.Counter";
|
||||
|
||||
state = useState({ value: 0 });
|
||||
|
||||
increment() {
|
||||
this.state.value++;
|
||||
}
|
||||
}
|
||||
|
||||
The `Counter` class specifies the name of the template to render. The template is written in XML
|
||||
and defines a part of user interface.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="my_module.Counter" owl="1">
|
||||
<p>Counter: <t t-esc="state.value"/></p>
|
||||
<button class="btn btn-primary" t-on-click="increment">Increment</button>
|
||||
</t>
|
||||
</templates>
|
||||
|
||||
You maybe noticed the `owl="1"` temporary attribute, it allows Odoo to differentiate Owl
|
||||
templates from the old JavaScript framework templates.
|
||||
|
||||
Let us take some time to get used to Owl itself. Below, you will find a series of exercises
|
||||
intended to quickly understand and practice the basics of Owl.
|
||||
|
||||
.. todo:: update screenshot
|
||||
|
||||
.. admonition:: Goal
|
||||
|
||||
Here is an overview of what we are going to achieve in this chapter.
|
||||
|
||||
.. image:: 01_components/overview.png
|
||||
:scale: 50%
|
||||
:align: center
|
||||
Before getting into the exercises, make sure you have followed all the steps described in this
|
||||
:ref:`tutorial introduction <tutorials/discover_js_framework/setup>`.
|
||||
|
||||
.. spoiler:: Solutions
|
||||
|
||||
The solutions for each exercise of the chapter are hosted on the `official Odoo tutorials
|
||||
repository <https://github.com/odoo/tutorials/commits/{BRANCH}-solutions/owl_playground>`_.
|
||||
repository <https://github.com/odoo/tutorials/commits/{BRANCH}-solutions/owl_playground>`_. It is
|
||||
recommended to try to solve them first without looking at the solution!
|
||||
|
||||
.. tip::
|
||||
If you use Chrome as your web browser, you can install the `Owl Devtools` extension. This
|
||||
extension provides many features to help you understand and profile any Owl application.
|
||||
|
||||
`Video: How to use the DevTools <https://www.youtube.com/watch?v=IUyQjwnrpzM>`_
|
||||
|
||||
In this chapter, we use the `owl_playground` addon, which provides a simplified environment that
|
||||
only contains Owl and a few other files. The goal is to learn Owl itself, without relying on Odoo
|
||||
web client code. To get started, open the `/owl_playground/playground` route with your browser: it
|
||||
should display an Owl component with the text *hello world*.
|
||||
|
||||
Example: a `Counter` component
|
||||
==============================
|
||||
|
||||
First, let us have a look at a simple example. The `Counter` component shown below is a component
|
||||
that maintains an internal number value, displays it, and updates it whenever the user clicks on the
|
||||
button.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
import { Component, useState } from "@odoo/owl";
|
||||
|
||||
class Counter extends Component {
|
||||
static template = "my_module.Counter";
|
||||
|
||||
setup() {
|
||||
state = useState({ value: 0 });
|
||||
}
|
||||
|
||||
increment() {
|
||||
this.state.value++;
|
||||
}
|
||||
}
|
||||
|
||||
The `Counter` component specifies the name of the template to render. The template is written in XML
|
||||
and defines a part of user interface:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="my_module.Counter" owl="1">
|
||||
<p>Counter: <t t-esc="state.value"/></p>
|
||||
<button class="btn btn-primary" t-on-click="increment">Increment</button>
|
||||
</t>
|
||||
</templates>
|
||||
|
||||
You maybe noticed the `owl="1"` temporary attribute, it allows Odoo to differentiate Owl
|
||||
templates from the old JavaScript framework templates. Note that Owl templates are not the same
|
||||
as QWeb templates: they can contain additional directives, such as `t-on-click`.
|
||||
|
||||
1. Displaying a counter
|
||||
=======================
|
||||
@ -70,14 +76,10 @@ As a first exercise, let us implement a counter in the `Playground` component lo
|
||||
:file:`owl_playground/static/src/`. To see the result, you can go to the `/owl_playground/playground`
|
||||
route with your browser.
|
||||
|
||||
.. tip::
|
||||
The Odoo JavaScript files downloaded by the browser are minified. For debugging purpose, it's
|
||||
easier when the files are not minified. Switch to :ref:`debug mode with assets <developer-mode/url>` so that the files are not minified.
|
||||
|
||||
.. exercise::
|
||||
|
||||
#. Modify :file:`playground.js` so that it acts as a counter like in :ref:`the example above
|
||||
<jstraining/chapter1/intro_example>`. You will need to use the `useState
|
||||
#. Modify :file:`playground.js` so that it acts as a counter like in the example above. You will
|
||||
need to use the `useState
|
||||
<{OWL_PATH}/doc/reference/hooks.md#usestate>`_ function so that the component is re-rendered
|
||||
whenever any part of the state object has been read by this component is modified.
|
||||
#. In the same component, create an `increment` method.
|
||||
@ -87,12 +89,14 @@ route with your browser.
|
||||
<{OWL_PATH}/doc/reference/event_handling.md#event-handling>`_ attribute in the button to
|
||||
trigger the `increment` method whenever the button is clicked.
|
||||
|
||||
.. image:: 01_components/counter.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
.. image:: 01_owl_components/counter.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
||||
`Video: How to use the DevTools <https://www.youtube.com/watch?v=IUyQjwnrpzM>`_
|
||||
.. tip::
|
||||
The Odoo JavaScript files downloaded by the browser are minified. For debugging purpose, it's
|
||||
easier when the files are not minified. Switch to
|
||||
:ref:`debug mode with assets <developer-mode/url>` so that the files are not minified.
|
||||
|
||||
2. Extract counter in a component
|
||||
=================================
|
||||
@ -138,9 +142,9 @@ todos. This will be done incrementally in multiple exercises that will introduce
|
||||
this.todo = { id: 3, description: "buy milk", done: false };
|
||||
}
|
||||
|
||||
.. image:: 01_components/todo.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
.. image:: 01_owl_components/todo.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
||||
`Owl: Dynamic class attributes <{OWL_PATH}/doc/reference/templates.md#dynamic-class-attribute>`_
|
||||
@ -178,9 +182,9 @@ list.
|
||||
<{OWL_PATH}/doc/reference/templates.md#loops>`_ in the template.
|
||||
#. Think about how it should be keyed with the `t-key` directive.
|
||||
|
||||
.. image:: 01_components/todo_list.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
.. image:: 01_owl_components/todo_list.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
|
||||
6. Adding a todo
|
||||
================
|
||||
@ -207,9 +211,9 @@ a todo to the list.
|
||||
|
||||
this.todos = useState([]);
|
||||
|
||||
.. image:: 01_components/create_todo.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
.. image:: 01_owl_components/create_todo.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
||||
`Owl: Reactivity <{OWL_PATH}/doc/reference/reactivity.md>`_
|
||||
@ -248,9 +252,9 @@ way to do this is by using a `callback prop
|
||||
`toggleState` function with the todo id.
|
||||
#. Make it work!
|
||||
|
||||
.. image:: 01_components/toggle_todo.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
.. image:: 01_owl_components/toggle_todo.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
|
||||
9. Deleting todos
|
||||
=================
|
||||
@ -260,27 +264,25 @@ The final touch is to let the user delete a todo.
|
||||
.. exercise::
|
||||
|
||||
#. Add a new callback prop `removeTodo`.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you're using an array to store your todo list, you can use the JavaScript `splice` function
|
||||
to remove a todo from it.
|
||||
|
||||
.. code-block::
|
||||
|
||||
// find the index of the element to delete
|
||||
const index = list.findIndex((elem) => elem.id === elemId);
|
||||
if (index >= 0) {
|
||||
// remove the element at index from list
|
||||
list.splice(index, 1);
|
||||
}
|
||||
|
||||
#. Insert :code:`<span class="fa fa-remove">` in the template of the `Todo` component.
|
||||
#. Whenever the user clicks on it, it should call the `removeTodo` method.
|
||||
|
||||
.. image:: 01_components/delete_todo.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
.. tip::
|
||||
If you're using an array to store your todo list, you can use the JavaScript `splice` function
|
||||
to remove a todo from it.
|
||||
|
||||
.. code-block::
|
||||
|
||||
// find the index of the element to delete
|
||||
const index = list.findIndex((elem) => elem.id === elemId);
|
||||
if (index >= 0) {
|
||||
// remove the element at index from list
|
||||
list.splice(index, 1);
|
||||
}
|
||||
|
||||
.. image:: 01_owl_components/delete_todo.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
|
||||
10. Generic components with slots
|
||||
=================================
|
||||
@ -322,9 +324,9 @@ components. This is useful to factorize the common layout between different part
|
||||
|
||||
#. Bonus point: if the `title` slot is not given, the `h5` should not be rendered at all.
|
||||
|
||||
.. image:: 01_components/card.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
.. image:: 01_owl_components/card.png
|
||||
:scale: 70%
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
||||
`Bootstrap: documentation on cards <https://getbootstrap.com/docs/5.2/components/card/>`_
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
@ -1,9 +1,9 @@
|
||||
=============================
|
||||
Chapter 2: Odoo web framework
|
||||
Chapter 2: Odoo Web Framework
|
||||
=============================
|
||||
|
||||
In the previous chapter, we learned to use Owl framework and its different concepts. We can now
|
||||
learn how to use the Odoo JavaScript framework which is is built on top of Owl.
|
||||
The first part of this tutorial introduced you to most of Owl ideas. It is now time to learn
|
||||
about the Odoo JavaScript framework in its entirety, as used by the web client.
|
||||
|
||||
.. graph TD
|
||||
.. subgraph "Owl"
|
||||
@ -16,19 +16,16 @@ learn how to use the Odoo JavaScript framework which is is built on top of Owl.
|
||||
|
||||
.. odoo[Odoo JavaScript framework] --> Owl
|
||||
|
||||
.. figure:: 02_odoo_web_framework/previously_learned.svg
|
||||
.. figure:: 02_web_framework/previously_learned.svg
|
||||
:align: center
|
||||
:width: 50%
|
||||
|
||||
This is the progress that we have made in discovering the JavaScript web framework at the end of
|
||||
:doc:`01_components`.
|
||||
|
||||
In the `awesome_tshirt` module, we will build our Awesome dashboard. This will be a good
|
||||
opportunity to discover many useful features in the Odoo JavaScript framework.
|
||||
For this chapter, we will start from the empty dashboard provided by the `awesome_tshirt`
|
||||
addon. We will progressively add features to it, using the odoo framework.
|
||||
|
||||
.. admonition:: Goal
|
||||
|
||||
.. image:: 02_odoo_web_framework/overview_02.png
|
||||
.. image:: 02_web_framework/overview_02.png
|
||||
:align: center
|
||||
|
||||
.. spoiler:: Solutions
|
||||
@ -49,8 +46,8 @@ and a main content zone just below. This is done using a `Layout component
|
||||
`Layout` component. You can use :code:`{ "top-right": false, "bottom-right": false }` for the
|
||||
`display` props of the `Layout` component.
|
||||
|
||||
.. image:: 02_odoo_web_framework/new_layout.png
|
||||
:align: center
|
||||
.. image:: 02_web_framework/new_layout.png
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
||||
|
||||
@ -97,8 +94,8 @@ services, and components can import a service with the `useService()` hooks.
|
||||
#. A button `Cancelled Order`, which opens a list of all orders created in the last 7 days, but
|
||||
already cancelled.
|
||||
|
||||
.. image:: 02_odoo_web_framework/navigation_buttons.png
|
||||
:align: center
|
||||
.. image:: 02_web_framework/navigation_buttons.png
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
||||
- `Example: doAction use
|
||||
@ -150,8 +147,8 @@ Here is a short explanation on the various arguments:
|
||||
- Number of cancelled orders this month
|
||||
- Average time for an order to go from 'new' to 'sent' or 'cancelled'
|
||||
|
||||
.. image:: 02_odoo_web_framework/statistics.png
|
||||
:align: center
|
||||
.. image:: 02_web_framework/statistics.png
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
||||
|
||||
@ -222,9 +219,9 @@ chartjs code every time if they don't need it).
|
||||
correct quantity for each sold t-shirts in each size (that information is available in the
|
||||
statistics route).
|
||||
|
||||
.. image:: 02_odoo_web_framework/pie_chart.png
|
||||
:align: center
|
||||
:scale: 50%
|
||||
.. image:: 02_web_framework/pie_chart.png
|
||||
:align: center
|
||||
:scale: 50%
|
||||
|
||||
.. seealso::
|
||||
- `Example: lazy loading a js file
|
||||
@ -245,7 +242,7 @@ Here is a list of some small improvements you could try to do if you have the ti
|
||||
corresponding size.
|
||||
#. Add a SCSS file and see if you can change the background color of the dashboard action.
|
||||
|
||||
.. image:: 02_odoo_web_framework/misc.png
|
||||
.. image:: 02_web_framework/misc.png
|
||||
:align: center
|
||||
:scale: 50%
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 334 KiB |
Before Width: | Height: | Size: 13 KiB |
42
content/developer/tutorials/master_odoo_web_framework.rst
Normal file
@ -0,0 +1,42 @@
|
||||
:show-content:
|
||||
|
||||
=============================
|
||||
Master the Odoo Web Framework
|
||||
=============================
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:glob:
|
||||
|
||||
master_odoo_web_framework/*
|
||||
|
||||
This tutorial is designed for those who have completed the :doc:`discover_js_framework` tutorial and
|
||||
are looking to deepen their knowledge of the Odoo web framework.
|
||||
|
||||
For this training, we will step into the shoes of the IT staff at the fictional company Awesome
|
||||
T-Shirt, which is dedicated to printing custom t-shirts for online customers. The Awesome T-Shirt
|
||||
company uses Odoo to manage orders and has created a dedicated Odoo module to manage their workflow.
|
||||
|
||||
In this tutorial, we will explore various aspects of the Odoo web framework in detail, including
|
||||
fields and views, notifications, command palette, and much more. This tutorial will provide you with
|
||||
the knowledge and skills you need to take full advantage of the Odoo web framework. So, let's get
|
||||
started!
|
||||
|
||||
.. _howtos/master_odoo_web_framework/setup:
|
||||
|
||||
Setup
|
||||
=====
|
||||
|
||||
#. Clone the `official Odoo tutorials repository <https://github.com/odoo/tutorials>`_ and switch to
|
||||
the branch `{BRANCH}`.
|
||||
#. Add the cloned repository to the :option:`--addons-path <odoo-bin --addons-path>`.
|
||||
#. Start a new Odoo database and install the modules `awesome_tshirt` and `awesome_gallery`.
|
||||
|
||||
Content
|
||||
=======
|
||||
|
||||
- :doc:`master_odoo_web_framework/01_fields_and_views`
|
||||
- :doc:`master_odoo_web_framework/02_miscellaneous`
|
||||
- :doc:`master_odoo_web_framework/03_custom_kanban_view`
|
||||
- :doc:`master_odoo_web_framework/04_creating_view_from_scratch`
|
||||
- :doc:`master_odoo_web_framework/05_testing`
|
@ -1,117 +1,93 @@
|
||||
===========================
|
||||
Chapter 3: Fields and Views
|
||||
Chapter 1: Fields and Views
|
||||
===========================
|
||||
|
||||
In the previous chapter, we learned a range of skills, including how to create and use services,
|
||||
work with the Layout component, make the dashboard translatable, and lazy load a JavaScript library
|
||||
like Chart.js. Now, let's move on to learning how to create new fields and views.
|
||||
like Chart.js. Now, let's learn how to create new fields and views.
|
||||
|
||||
.. graph TD
|
||||
.. subgraph "Owl"
|
||||
.. C[Component]
|
||||
.. T[Template]
|
||||
.. H[Hook]
|
||||
.. S[Slot]
|
||||
.. E[Event]
|
||||
.. end
|
||||
.. spoiler:: Solutions
|
||||
|
||||
.. subgraph "odoo"[Odoo Javascript framework]
|
||||
.. Services
|
||||
.. Translation
|
||||
.. lazy[Lazy loading libraries]
|
||||
.. SCSS
|
||||
.. action --> Services
|
||||
.. rpc --> Services
|
||||
.. end
|
||||
|
||||
.. odoo[Odoo JavaScript framework] --> Owl
|
||||
|
||||
.. figure:: 03_fields_and_views/previously_learned.svg
|
||||
:align: center
|
||||
:width: 60%
|
||||
|
||||
This is the progress that we have made in discovering the JavaScript web framework at the end of
|
||||
:doc:`02_odoo_web_framework`.
|
||||
The solutions for each exercise of the chapter are hosted on the `official Odoo tutorials
|
||||
repository <https://github.com/odoo/tutorials/commits/{BRANCH}-solutions/awesome_tshirt>`_. It is
|
||||
recommended not to look at them before trying the exercises.
|
||||
|
||||
Fields and views are among the most important concepts in the Odoo user interface. They are key to
|
||||
many important user interactions, and should therefore work perfectly.
|
||||
|
||||
In the context of the JavaScript framework, fields are components specialized for
|
||||
visualizing/editing a specific field for a given record.
|
||||
|
||||
For example, a (Python) model may define a char field, which will be represented by a field
|
||||
component `CharField`.
|
||||
many important user interactions, and should therefore work perfectly. In the context of the
|
||||
JavaScript framework, fields are components specialized for visualizing/editing a specific field for
|
||||
a given record. For example, a (Python) model may define a char field, which will be represented by
|
||||
a field component `CharField`.
|
||||
|
||||
A field component is basically just a component registered in the `fields` :ref:`registry
|
||||
<frontend/registries>`. The field component may define some additional static keys (metadata), such
|
||||
as `displayName` or `supportedTypes`, and the most important one: `extractProps`, which prepare the
|
||||
base props received by the `CharField`.
|
||||
|
||||
.. example::
|
||||
Let us discuss a simplified implementation of a `CharField`.
|
||||
Example: a simple field
|
||||
=======================
|
||||
|
||||
First, here is the template:
|
||||
Let us discuss a simplified implementation of a `CharField`. First, here is the template:
|
||||
|
||||
.. code-block:: xml
|
||||
.. code-block:: xml
|
||||
|
||||
<t t-name="web.CharField" owl="1">
|
||||
<t t-if="props.readonly">
|
||||
<span t-esc="formattedValue" />
|
||||
</t>
|
||||
<t t-else="">
|
||||
<input
|
||||
class="o_input"
|
||||
t-att-type="props.isPassword ? 'password' : 'text'"
|
||||
t-att-placeholder="props.placeholder"
|
||||
t-on-change="updateValue"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-name="web.CharField" owl="1">
|
||||
<t t-if="props.readonly">
|
||||
<span t-esc="formattedValue" />
|
||||
</t>
|
||||
<t t-else="">
|
||||
<input
|
||||
class="o_input"
|
||||
t-att-type="props.isPassword ? 'password' : 'text'"
|
||||
t-att-placeholder="props.placeholder"
|
||||
t-on-change="updateValue"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
It features a readonly mode and an edit mode, which is an input with a few attributes. Now, here
|
||||
is the JavaScript code:
|
||||
It features a readonly mode and an edit mode, which is an input with a few attributes. Now, here
|
||||
is the JavaScript code:
|
||||
|
||||
.. code-block:: js
|
||||
.. code-block:: js
|
||||
|
||||
export class CharField extends Component {
|
||||
get formattedValue() {
|
||||
return formatChar(this.props.value, { isPassword: this.props.isPassword });
|
||||
}
|
||||
export class CharField extends Component {
|
||||
get formattedValue() {
|
||||
return formatChar(this.props.value, { isPassword: this.props.isPassword });
|
||||
}
|
||||
|
||||
updateValue(ev) {
|
||||
let value = ev.target.value;
|
||||
if (this.props.shouldTrim) {
|
||||
value = value.trim();
|
||||
}
|
||||
this.props.update(value);
|
||||
}
|
||||
}
|
||||
updateValue(ev) {
|
||||
let value = ev.target.value;
|
||||
if (this.props.shouldTrim) {
|
||||
value = value.trim();
|
||||
}
|
||||
this.props.update(value);
|
||||
}
|
||||
}
|
||||
|
||||
CharField.template = "web.CharField";
|
||||
CharField.displayName = _lt("Text");
|
||||
CharField.supportedTypes = ["char"];
|
||||
CharField.template = "web.CharField";
|
||||
CharField.displayName = _lt("Text");
|
||||
CharField.supportedTypes = ["char"];
|
||||
|
||||
CharField.extractProps = ({ attrs, field }) => {
|
||||
return {
|
||||
shouldTrim: field.trim && !archParseBoolean(attrs.password),
|
||||
maxLength: field.size,
|
||||
isPassword: archParseBoolean(attrs.password),
|
||||
placeholder: attrs.placeholder,
|
||||
};
|
||||
};
|
||||
CharField.extractProps = ({ attrs, field }) => {
|
||||
return {
|
||||
shouldTrim: field.trim && !archParseBoolean(attrs.password),
|
||||
maxLength: field.size,
|
||||
isPassword: archParseBoolean(attrs.password),
|
||||
placeholder: attrs.placeholder,
|
||||
};
|
||||
};
|
||||
|
||||
registry.category("fields").add("char", CharField);
|
||||
registry.category("fields").add("char", CharField);
|
||||
|
||||
There are a few important things to notice:
|
||||
There are a few important things to notice:
|
||||
|
||||
- The `CharField` receives its (raw) value in props. It needs to format it before displaying it.
|
||||
- It receives an `update` function in its props, which is used by the field to notify the owner
|
||||
of the state that the value of this field has been changed. Note that the field does not (and
|
||||
should not) maintain a local state with its value. Whenever the change has been applied, it
|
||||
will come back (possibly after an onchange) by the way of the props.
|
||||
- It defines an `extractProps` function. This is a step that translates generic standard props,
|
||||
specific to a view, to specialized props, useful to the component. This allows the component to
|
||||
have a better API, and may make it so that it is reusable.
|
||||
- The `CharField` receives its (raw) value in props. It needs to format it before displaying it.
|
||||
- It receives an `update` function in its props, which is used by the field to notify the owner of
|
||||
the state that the value of this field has been changed. Note that the field does not (and should
|
||||
not) maintain a local state with its value. Whenever the change has been applied, it will come
|
||||
back (possibly after an onchange) by the way of the props.
|
||||
- It defines an `extractProps` function. This is a step that translates generic standard props,
|
||||
specific to a view, to specialized props, useful to the component. This allows the component to
|
||||
have a better API, and may make it so that it is reusable.
|
||||
|
||||
Fields have to be registered in the `fields` registry. Once it's done, they can be used in some
|
||||
views (namely: `form`, `list`, `kanban`) by using the `widget` attribute.
|
||||
@ -122,16 +98,6 @@ views (namely: `form`, `list`, `kanban`) by using the `widget` attribute.
|
||||
|
||||
<field name="preview_moves" widget="account_resequence_widget"/>
|
||||
|
||||
.. admonition:: Goal
|
||||
|
||||
.. image:: 03_fields_and_views/overview_03.png
|
||||
:align: center
|
||||
|
||||
.. spoiler:: Solutions
|
||||
|
||||
The solutions for each exercise of the chapter are hosted on the `official Odoo tutorials
|
||||
repository <https://github.com/odoo/tutorials/commits/{BRANCH}-solutions/awesome_tshirt>`_.
|
||||
|
||||
1. An `image_preview` field
|
||||
===========================
|
||||
|
||||
@ -154,13 +120,13 @@ field, so it can be edited.
|
||||
#. Register your field in the proper :ref:`registry <frontend/registries>`.
|
||||
#. Update the arch of the form view to use your new field by setting the `widget` attribute.
|
||||
|
||||
.. note::
|
||||
It is possible to solve this exercise by inheriting `CharField` , but the goal of this
|
||||
exercise is to create a field from scratch.
|
||||
.. note::
|
||||
It is possible to solve this exercise by inheriting `CharField` , but the goal of this exercise
|
||||
is to create a field from scratch.
|
||||
|
||||
.. image:: 03_fields_and_views/image_field.png
|
||||
:align: center
|
||||
:scale: 50%
|
||||
.. image:: 01_fields_and_views/image_field.png
|
||||
:align: center
|
||||
:scale: 50%
|
||||
|
||||
.. seealso::
|
||||
|
||||
@ -175,8 +141,8 @@ field, so it can be edited.
|
||||
some action should be done. In particular, we want to display a warning "MISSING TSHIRT DESIGN"
|
||||
in red if there is no image URL specified on the order.
|
||||
|
||||
.. image:: 03_fields_and_views/missing_image.png
|
||||
:align: center
|
||||
.. image:: 01_fields_and_views/missing_image.png
|
||||
:align: center
|
||||
|
||||
3. Customizing a field component
|
||||
================================
|
||||
@ -195,8 +161,8 @@ whenever it is set to true.
|
||||
#. Use it in the list/kanban/form view.
|
||||
#. Modify it to add a red `Late` next to it, as requested.
|
||||
|
||||
.. image:: 03_fields_and_views/late_field.png
|
||||
:align: center
|
||||
.. image:: 01_fields_and_views/late_field.png
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
||||
|
||||
@ -222,8 +188,8 @@ insert arbitrary components in the form view. Let us see how we can use it.
|
||||
material".
|
||||
- Make sure that your widget is updated in real time.
|
||||
|
||||
.. image:: 03_fields_and_views/warning_widget.png
|
||||
:align: center
|
||||
.. image:: 01_fields_and_views/warning_widget.png
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
||||
|
||||
@ -247,11 +213,11 @@ the data has been marked explicitly with a `markup` function.
|
||||
#. Modify the previous exercise to put the `image` and `material` words in bold.
|
||||
#. The warnings should be markuped, and the template should be modified to use `t-out`.
|
||||
|
||||
.. note::
|
||||
This is an example of a safe use of `t-out` , since the string is static.
|
||||
.. note::
|
||||
This is an example of a safe use of `t-out` , since the string is static.
|
||||
|
||||
.. image:: 03_fields_and_views/warning_widget2.png
|
||||
:align: center
|
||||
.. image:: 01_fields_and_views/warning_widget2.png
|
||||
:align: center
|
||||
|
||||
6. Add buttons in the control panel
|
||||
===================================
|
||||
@ -334,7 +300,7 @@ Most (or all?) Odoo views share a common architecture:
|
||||
.. A --- C
|
||||
.. ```
|
||||
|
||||
.. image:: 03_fields_and_views/view_architecture.svg
|
||||
.. image:: 01_fields_and_views/view_architecture.svg
|
||||
:align: center
|
||||
:width: 75%
|
||||
:class: o-no-modal
|
||||
@ -389,7 +355,7 @@ There is a service dedicated to calling models methods: `orm_service`, located i
|
||||
task stage is `printed`. Otherwise, it is displayed as a secondary button.
|
||||
#. Bonus point: clicking twice on the button should not trigger 2 RPCs.
|
||||
|
||||
.. image:: 03_fields_and_views/form_button.png
|
||||
.. image:: 01_fields_and_views/form_button.png
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 453 KiB After Width: | Height: | Size: 453 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
@ -1,5 +1,5 @@
|
||||
========================
|
||||
Chapter 4: Miscellaneous
|
||||
Chapter 2: Miscellaneous
|
||||
========================
|
||||
|
||||
In the previous task, we learned how to create fields and views. There is still much more to
|
||||
@ -29,16 +29,16 @@ discover in the feature-rich Odoo web framework, so let's dive in and explore mo
|
||||
|
||||
.. odoo[Odoo JavaScript framework] --> Owl
|
||||
|
||||
.. figure:: 04_miscellaneous/previously_learned.svg
|
||||
.. figure:: 02_miscellaneous/previously_learned.svg
|
||||
:align: center
|
||||
:width: 70%
|
||||
|
||||
This is the progress that we have made in discovering the JavaScript web framework at the end of
|
||||
:doc:`03_fields_and_views`.
|
||||
:doc:`01_fields_and_views`.
|
||||
|
||||
.. admonition:: Goal
|
||||
|
||||
.. image:: 04_miscellaneous/kitten_mode.png
|
||||
.. image:: 02_miscellaneous/kitten_mode.png
|
||||
:align: center
|
||||
|
||||
.. spoiler:: Solutions
|
||||
@ -50,7 +50,7 @@ discover in the feature-rich Odoo web framework, so let's dive in and explore mo
|
||||
===========================================
|
||||
|
||||
.. note::
|
||||
This task depends on :doc:`the previous exercises <03_fields_and_views>`.
|
||||
This task depends on :doc:`the previous exercises <01_fields_and_views>`.
|
||||
|
||||
After using the :guilabel:`Print Label` button for some t-shirt tasks, it is apparent that there
|
||||
should be some feedback that the `print_label` action is completed (or failed, for example, the
|
||||
@ -61,7 +61,7 @@ printer is not connected or ran out of paper).
|
||||
completed successfully, and a warning if it failed.
|
||||
#. If it failed, the notification should be permanent.
|
||||
|
||||
.. image:: 04_miscellaneous/notification.png
|
||||
.. image:: 02_miscellaneous/notification.png
|
||||
:align: center
|
||||
:scale: 60%
|
||||
|
||||
@ -87,7 +87,7 @@ notifications and provide access to certain features.
|
||||
#. Bonus point: avoid making the initial RPC by adding the information to the session info. The
|
||||
session info is given to the web client by the server in the initial response.
|
||||
|
||||
.. image:: 04_miscellaneous/systray.png
|
||||
.. image:: 02_miscellaneous/systray.png
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
||||
@ -139,7 +139,7 @@ by pressing `CTRL+K` in the Odoo interface.
|
||||
|
||||
Make sure that the command is only active whenever a field preview is visible in the screen.
|
||||
|
||||
.. image:: 04_miscellaneous/new_command.png
|
||||
.. image:: 02_miscellaneous/new_command.png
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
||||
@ -197,11 +197,11 @@ these terms?".
|
||||
#. Update the code to display the message on click by using the dialog service. You can use
|
||||
`ConfirmationDialog`.
|
||||
|
||||
.. image:: 04_miscellaneous/bafien_eye.png
|
||||
.. image:: 02_miscellaneous/bafien_eye.png
|
||||
:align: center
|
||||
:scale: 60%
|
||||
|
||||
.. image:: 04_miscellaneous/confirmation_dialog.png
|
||||
.. image:: 02_miscellaneous/confirmation_dialog.png
|
||||
:align: center
|
||||
:scale: 60%
|
||||
|
||||
@ -236,7 +236,7 @@ from a given customer.
|
||||
#. Update the code to fetch the list of customers with the tshirt service, and display it in the
|
||||
autocomplete component, filtered by the `fuzzyLookup` method.
|
||||
|
||||
.. image:: 04_miscellaneous/autocomplete.png
|
||||
.. image:: 02_miscellaneous/autocomplete.png
|
||||
:align: center
|
||||
:scale: 60%
|
||||
|
||||
@ -274,7 +274,7 @@ the background of Odoo, because we like kittens.
|
||||
#. Add a command to the command palette to toggle the kitten mode. Toggling the kitten mode
|
||||
should toggle the `.o-kitten-mode` class and update the current URL accordingly.
|
||||
|
||||
.. image:: 04_miscellaneous/kitten_mode.png
|
||||
.. image:: 02_miscellaneous/kitten_mode.png
|
||||
:align: center
|
||||
|
||||
8. Lazy loading our dashboard
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 2.0 MiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
@ -1,11 +1,11 @@
|
||||
=============================
|
||||
Chapter 5: Custom kanban view
|
||||
Chapter 3: Custom kanban view
|
||||
=============================
|
||||
|
||||
.. todo:: It'd be cool to follow the naming convention of the previous chapters: "Chapter N: The concept studied in the chapter"
|
||||
|
||||
.. warning::
|
||||
It is highly recommended that you complete :doc:`03_fields_and_views` before starting this
|
||||
It is highly recommended that you complete :doc:`01_fields_and_views` before starting this
|
||||
chapter. The concepts introduced in Chapter 3, including views and examples, will be essential
|
||||
for understanding the material covered in this chapter.
|
||||
|
||||
@ -21,7 +21,7 @@ orders linked to that customer.
|
||||
|
||||
.. admonition:: Goal
|
||||
|
||||
.. image:: 05_custom_kanban_view/overview.png
|
||||
.. image:: 03_custom_kanban_view/overview.png
|
||||
:align: center
|
||||
|
||||
.. spoiler:: Solutions
|
||||
@ -57,7 +57,7 @@ We will need to display a list of customers, so we might as well create the comp
|
||||
#. Subclass the kanban controller to add `CustomerList` in its sub-components.
|
||||
#. Make sure you see your component in the kanban view.
|
||||
|
||||
.. image:: 05_custom_kanban_view/customer_list.png
|
||||
.. image:: 03_custom_kanban_view/customer_list.png
|
||||
:align: center
|
||||
:scale: 60%
|
||||
|
||||
@ -70,7 +70,7 @@ We will need to display a list of customers, so we might as well create the comp
|
||||
#. Display the list in the template with a `t-foreach`.
|
||||
#. Whenever a customer is selected, call the `selectCustomer` function prop.
|
||||
|
||||
.. image:: 05_custom_kanban_view/customer_data.png
|
||||
.. image:: 03_custom_kanban_view/customer_data.png
|
||||
:align: center
|
||||
:scale: 60%
|
||||
|
||||
@ -95,7 +95,7 @@ We will need to display a list of customers, so we might as well create the comp
|
||||
});
|
||||
}
|
||||
|
||||
.. image:: 05_custom_kanban_view/customer_filter.png
|
||||
.. image:: 03_custom_kanban_view/customer_filter.png
|
||||
:align: center
|
||||
:scale: 60%
|
||||
|
||||
@ -111,7 +111,7 @@ customers with an active order.
|
||||
next to it.
|
||||
#. Changing the value of the checkbox should filter the list on customers with an active order.
|
||||
|
||||
.. image:: 05_custom_kanban_view/active_customer.png
|
||||
.. image:: 03_custom_kanban_view/active_customer.png
|
||||
:align: center
|
||||
:scale: 60%
|
||||
|
||||
@ -126,7 +126,7 @@ customers with an active order.
|
||||
.. tip::
|
||||
You can use the `fuzzyLookup` function to perform the filter.
|
||||
|
||||
.. image:: 05_custom_kanban_view/customer_search.png
|
||||
.. image:: 03_custom_kanban_view/customer_search.png
|
||||
:align: center
|
||||
:scale: 60%
|
||||
|
||||
@ -164,6 +164,6 @@ us see how we could do it in a more declarative way, with the `t-model
|
||||
This is actually pretty hard, in particular in combination with the filtering done in the
|
||||
previous exercise. There are many edge cases to take into account.
|
||||
|
||||
.. image:: 05_custom_kanban_view/customer_pager.png
|
||||
.. image:: 03_custom_kanban_view/customer_pager.png
|
||||
:align: center
|
||||
:scale: 60%
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
@ -1,9 +1,9 @@
|
||||
=======================================
|
||||
Chapter 6: Creating a view from scratch
|
||||
Chapter 4: Creating a view from scratch
|
||||
=======================================
|
||||
|
||||
.. warning::
|
||||
It is highly recommended that you complete :doc:`03_fields_and_views` before starting this
|
||||
It is highly recommended that you complete :doc:`01_fields_and_views` before starting this
|
||||
chapter. The concepts introduced in Chapter 3, including views and examples, will be essential
|
||||
for understanding the material covered in this chapter.
|
||||
|
||||
@ -30,7 +30,7 @@ addon includes the necessary server files to add a new view.
|
||||
|
||||
.. admonition:: Goal
|
||||
|
||||
.. image:: 06_creating_view_from_scratch/overview.png
|
||||
.. image:: 04_creating_view_from_scratch/overview.png
|
||||
:align: center
|
||||
|
||||
.. spoiler:: Solutions
|
||||
@ -53,10 +53,10 @@ First step is to create a JavaScript implementation with a simple component.
|
||||
#. Add `gallery` as one of the view type in the orders action.
|
||||
#. Make sure that you can see your hello world component when switching to the gallery view.
|
||||
|
||||
.. image:: 06_creating_view_from_scratch/view_button.png
|
||||
.. image:: 04_creating_view_from_scratch/view_button.png
|
||||
:align: center
|
||||
|
||||
.. image:: 06_creating_view_from_scratch/new_view.png
|
||||
.. image:: 04_creating_view_from_scratch/new_view.png
|
||||
:align: center
|
||||
|
||||
2. Use the Layout component
|
||||
@ -71,7 +71,7 @@ have the standard features like other views.
|
||||
#. Update the template to use `Layout`. It needs a `display` prop, which can be found in
|
||||
`props.display`.
|
||||
|
||||
.. image:: 06_creating_view_from_scratch/layout.png
|
||||
.. image:: 04_creating_view_from_scratch/layout.png
|
||||
:align: center
|
||||
|
||||
3. Parse the arch
|
||||
@ -134,7 +134,7 @@ Let us now get some real data.
|
||||
.. note::
|
||||
The loading data code will be moved into a proper model in the next exercise.
|
||||
|
||||
.. image:: 06_creating_view_from_scratch/gallery_data.png
|
||||
.. image:: 04_creating_view_from_scratch/gallery_data.png
|
||||
:align: center
|
||||
|
||||
5. Reorganize code
|
||||
@ -157,7 +157,7 @@ to learn how to structure code in Odoo. Also, this will scale better with changi
|
||||
Update the renderer to display images in a nice way, if the field is set. If `image_field` is
|
||||
empty, display an empty box instead.
|
||||
|
||||
.. image:: 06_creating_view_from_scratch/tshirt_images.png
|
||||
.. image:: 04_creating_view_from_scratch/tshirt_images.png
|
||||
:align: center
|
||||
|
||||
7. Switch to form view on click
|
||||
@ -189,7 +189,7 @@ It is useful to have some additional information on mouse hover.
|
||||
char field, a number field or a many2one field.
|
||||
#. Update the orders gallery view to add the customer as tooltip field.
|
||||
|
||||
.. image:: 06_creating_view_from_scratch/image_tooltip.png
|
||||
.. image:: 04_creating_view_from_scratch/image_tooltip.png
|
||||
:align: center
|
||||
:scale: 60%
|
||||
|
||||
@ -204,7 +204,7 @@ It is useful to have some additional information on mouse hover.
|
||||
Let's add a pager on the control panel and manage all the pagination like in a normal Odoo view.
|
||||
Note that it is surprisingly difficult.
|
||||
|
||||
.. image:: 06_creating_view_from_scratch/pagination.png
|
||||
.. image:: 04_creating_view_from_scratch/pagination.png
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 382 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 124 KiB |
Before Width: | Height: | Size: 813 KiB After Width: | Height: | Size: 813 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 698 KiB After Width: | Height: | Size: 698 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@ -1,5 +1,5 @@
|
||||
==================
|
||||
Chapter 7: Testing
|
||||
Chapter 5: Testing
|
||||
==================
|
||||
|
||||
Automatically testing code is important when working on a codebase. It helps ensure we don't
|
||||
@ -48,7 +48,7 @@ It is also useful to test independently a component or a piece of code. :ref:`QU
|
||||
#. In the `awesome_tshirt` addon, add a :file:`static/tests/counter_tests.js` file.
|
||||
#. Add a QUnit test that instantiates a counter, clicks on it, and makes sure it is incremented.
|
||||
|
||||
.. image:: 07_testing/component_test.png
|
||||
.. image:: 05_testing/component_test.png
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
||||
@ -63,7 +63,7 @@ Many components need more setup to be tested. In particular, we often need to mo
|
||||
Let us see how to do that.
|
||||
|
||||
.. note::
|
||||
This depends on our Gallery View from :doc:`06_creating_view_from_scratch`.
|
||||
This depends on our Gallery View from :doc:`04_creating_view_from_scratch`.
|
||||
|
||||
.. exercise::
|
||||
|
||||
@ -72,7 +72,7 @@ Let us see how to do that.
|
||||
#. Add another test that checks that when the user clicks on an image, it is switched to the form
|
||||
view of the corresponding order.
|
||||
|
||||
.. image:: 07_testing/view_test.png
|
||||
.. image:: 05_testing/view_test.png
|
||||
:align: center
|
||||
|
||||
.. seealso::
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
@ -61,3 +61,13 @@ developer/howtos/discover_js_framework/07_testing.rst developer/tutorials/discov
|
||||
|
||||
developer/reference/frontend/icons_library.rst contributing/development/ui/icons.rst # Odoo UI icons -> UI Icons
|
||||
developer/reference/frontend/javascript_cheatsheet.rst developer/howtos/javascript_create_field.rst # refactor JavaScript cheatsheet into howtos
|
||||
|
||||
# developer/tutorials
|
||||
|
||||
developer/tutorials/discover_js_framework/01_components.rst developer/tutorials/discover_js_framework/01_owl_components.rst
|
||||
developer/tutorials/discover_js_framework/02_odoo_web_framework.rst developer/tutorials/discover_js_framework/02_web_framework.rst
|
||||
developer/tutorials/discover_js_framework/03_fields_and_views.rst developer/tutorials/master_odoo_web_framework/01_fields_and_views.rst
|
||||
developer/tutorials/discover_js_framework/04_miscellaneous.rst developer/tutorials/master_odoo_web_framework/02_miscellaneous.rst
|
||||
developer/tutorials/discover_js_framework/05_custom_kanban_view.rst developer/tutorials/master_odoo_web_framework/03_custom_kanban_view.rst
|
||||
developer/tutorials/discover_js_framework/06_creating_view_from_scratch.rst developer/tutorials/master_odoo_web_framework/04_creating_view_from_scratch.rst
|
||||
developer/tutorials/discover_js_framework/07_testing.rst developer/tutorials/master_odoo_web_framework/05_testing.rst
|
||||
|