[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>
This commit is contained in:
Géry Debongnie 2023-04-24 10:37:04 +00:00 committed by Antoine Vandevenne (anv)
parent 1da701d69f
commit b6b9de70d2
62 changed files with 319 additions and 309 deletions

View File

@ -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

View File

@ -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`

View File

@ -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/>`_

View File

@ -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%

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

View 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`

View File

@ -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::

View File

@ -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

View File

@ -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%

View File

@ -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::

View File

@ -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::

View File

@ -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