documentation/content/developer/howtos/discover_js_framework/04_miscellaneous.rst
fdardenne 8a30786495 [IMP] developer: JavaScript tutorial: chapter 3-7
This commit adds the chapter 3,4,5,6 and 7 of the JavaScript web
framework tutorial.

This new tutorial allows people to discover Owl and the building blocks
of the Odoo JavaScript framework.

closes odoo/documentation#3325

X-original-commit: 54628b4f5b
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
Co-authored-by: Géry Debongnie <ged@odoo.com>
Co-authored-by: Antoine Vandevenne (anv) <anv@odoo.com>
2023-01-12 19:08:49 +01:00

311 lines
12 KiB
ReStructuredText

========================
Chapter 4: Miscellaneous
========================
In the previous task, we learned how to create fields and views. There is still much more to
discover in the feature-rich Odoo web framework, so let's dive in and explore more in this chapter!
.. graph TD
.. subgraph "Owl"
.. C[Component]
.. T[Template]
.. H[Hook]
.. S[Slot]
.. E[Event]
.. end
.. subgraph "odoo"[Odoo Javascript framework]
.. Services
.. Translation
.. lazy[Lazy loading libraries]
.. SCSS
.. action --> Services
.. rpc --> Services
.. orm --> Services
.. Fields
.. Views
.. Registries
.. end
.. odoo[Odoo JavaScript framework] --> Owl
.. figure:: 04_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`.
.. admonition:: Goal
.. image:: 04_miscellaneous/kitten_mode.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. Interacting with the notification system
===========================================
.. note::
This task depends on :doc:`the previous exercises <03_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
printer is not connected or ran out of paper).
.. exercise::
#. Display a :ref:`notification <frontend/services/notification>` message when the action is
completed successfully, and a warning if it failed.
#. If it failed, the notification should be permanent.
.. image:: 04_miscellaneous/notification.png
:align: center
:scale: 60%
.. seealso::
`Example: Code using the notification service
<{GITHUB_PATH}/addons/web/static/src/views/fields/image_url/image_url_field.js>`_
2. Add a systray item
=====================
Our beloved leader wants to keep a close eye on new orders. He wants to see the number of new,
unprocessed orders at all time. Let's do that with a systray item.
A :ref:`systray <frontend/registries/systray>` item is an element that appears in the system tray,
which is a small area located on the right-hand side of the navbar. The systray is used to display
notifications and provide access to certain features.
.. exercise::
#. Create a systray component that connects to the statistics service we made previously.
#. Use it to display the number of new orders.
#. Clicking on it should open a list view with all of those orders.
#. 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
:align: center
.. seealso::
- `Example: Systray item <{GITHUB_PATH}/addons/web/static/src/webclient/user_menu/user_menu.js>`_
- `Example: Adding some information to the "session info"
<{GITHUB_PATH}/addons/barcodes/models/ir_http.py>`_
- `Example: Reading the session information
<{GITHUB_PATH}/addons/barcodes/static/src/barcode_service.js#L5>`_
3. Real life update
===================
So far, the systray item from above does not update unless the user refreshes the browser. Let us
do that by calling periodically (for example, every minute) the server to reload the information.
.. exercise::
#. Modify the systray item code to get its data from the `tshirt` service.
#. The `tshirt` service should periodically reload its data.
Now, the question arises: how is the systray item notified that it should re-render itself? It can
be done in various ways but, for this training, we choose to use the most *declarative* approach:
.. exercise::
#. Modify the `tshirt` service to return a `reactive
<{OWL_PATH}/doc/reference/reactivity.md#reactive>`_ object. Reloading data should update the
reactive object in place.
#. The systray item can then perform a `useState` on the service return value.
#. This is not really necessary, but you can also *package* the calls to `useService` and
`useState` in a custom hook `useStatistics`.
.. seealso::
- `Documentation on reactivity <{OWL_PATH}/doc/reference/reactivity.md>`_
- `Example: Use of reactive in a service
<{GITHUB_PATH}/addons/web/static/src/core/debug/profiling/profiling_service.js#L30>`_
4. Add a command to the command palette
=======================================
Now, let us see how we can interact with the command palette. The command palette is a feature that
allows users to quickly access various commands and functions within the application. It is accessed
by pressing `CTRL+K` in the Odoo interface.
.. exercise::
Let us modify the image preview field (from a previous exercise) to add a command to the command
palette to open the image in a new browser tab (or window).
Make sure that the command is only active whenever a field preview is visible in the screen.
.. image:: 04_miscellaneous/new_command.png
:align: center
.. seealso::
- `Example: Using the useCommand hook
<{GITHUB_PATH}/addons/web/static/src/core/debug/debug_menu.js#L15>`_
- `Code: The command service
<{GITHUB_PATH}/addons/web/static/src/core/commands/command_service.js>`_
5. Monkey patching a component
==============================
Often, it is possible to do what we want by using existing extension points that allow
customization, such as registering something in a registry. But it happens that we want to modify
something that has no such mechanism. In that case, we have to fall back on a less safe form of
customization: monkey patching. Almost everything in Odoo can be monkey patched.
Bafien, our beloved leader, heard that employees perform better if they are constantly being
watched. Since he is not able to be there in person for each and every one of his employees, he
tasked you with the following: update the user interface to add a blinking red eye in the control
panel. Clicking on that eye should open a dialog with the following message: "Bafien is watching
you. This interaction is recorded and may be used in legal proceedings if necessary. Do you agree to
these terms?".
.. exercise::
#. Create the :file:`control_panel_patch.js` file, as well as corresponding CSS and XML files.
#. :doc:`Patch </developer/reference/frontend/patching_code>` the `ControlPanel` template to add
an icon next to the breadcrumbs. You might want to use the `fa-eye` or `fa-eyes` icons. Make
sure it is visible in all views!
.. tip::
There are two ways to inherit a template using XPath: by specifying
`t-inherit-mode="primary"`, which creates a new, independent template with the desired
modifications, or by using `t-inherit-mode="extension"`, which modifies the original
template in place.
.. code-block:: css
.blink {
animation: blink-animation 1s steps(5, start) infinite;
-webkit-animation: blink-animation 1s steps(5, start) infinite;
}
@keyframes blink-animation {
to {
visibility: hidden;
}
}
@-webkit-keyframes blink-animation {
to {
visibility: hidden;
}
}
#. Import the ControlPanel component and the `patch` function.
#. Update the code to display the message on click by using the dialog service. You can use
`ConfirmationDialog`.
.. image:: 04_miscellaneous/bafien_eye.png
:align: center
:scale: 60%
.. image:: 04_miscellaneous/confirmation_dialog.png
:align: center
:scale: 60%
.. seealso::
- `Code: The patch function <{GITHUB_PATH}/addons/web/static/src/core/utils/patch.js#L16>`_
- `Code: The ControlPanel component
<{GITHUB_PATH}/addons/web/static/src/search/control_panel/control_panel.js>`_
- `The Font Awesome website <https://fontawesome.com/>`_
- `Code: The dialog service <{GITHUB_PATH}/addons/web/static/src/core/dialog/dialog_service.js>`_
- `Code: ConfirmationDialog
<{GITHUB_PATH}/addons/web/static/src/core/confirmation_dialog/confirmation_dialog.js>`_
- `Example: Using the dialog service
<{GITHUB_PATH}/addons/board/static/src/board_controller.js#L88>`_
- `Example: XPath with t-inherit-mode="primary"
<{GITHUB_PATH}/addons/account/static/src/components/account_move_form/account_move_form_notebook.xml#L4>`_
- `Example: XPath with t-inherit-mode="extension"
<{GITHUB_PATH}/calendar/static/src/components/activity/activity.xml#L4>`_
6. Fetching orders from a customer
==================================
Let's see how to use some standard components to build a powerful feature combining autocomplete,
fetching data, and fuzzy lookup. We will add an input in our dashboard to easily search all orders
from a given customer.
.. exercise::
#. Update :file:`tshirt_service.js` to add a `loadCustomers` method, which returns a promise that
returns the list of all customers (and only performs the call once).
#. Import the `AutoComplete` component from `@web/core/autocomplete/autocomplete`.
#. Add it to the dashboard, next to the buttons in the control panel.
#. 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
:align: center
:scale: 60%
.. seealso::
- `Code: AutoComplete <{GITHUB_PATH}/addons/web/static/src/core/autocomplete/autocomplete.js>`_
- `Code: fuzzyLookup <{GITHUB_PATH}/addons/web/static/src/core/utils/search.js>`_
7. Reintroduce Kitten Mode
==========================
Let us add a special mode to Odoo: whenever the url contains `kitten=1`, we will display a kitten in
the background of Odoo, because we like kittens.
.. exercise::
#. Create a :file:`kitten_mode.js` file.
#. Create a `kitten` service, which should check the content of the active url hash with the
help of the :ref:`router service <frontend/services/router>`.
#. If `kitten` is set, we are in kitten mode. This should add a class `.o-kitten-mode` on the
document body.
#. Add the following CSS in :file:`kitten_mode.scss`:
.. code-block:: css
.o-kitten-mode {
background-image: url(https://upload.wikimedia.org/wikipedia/commons/5/58/Mellow_kitten_%28Unsplash%29.jpg);
background-size: cover;
background-attachment: fixed;
}
.o-kitten-mode > * {
opacity: 0.9;
}
#. 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
:align: center
8. Lazy loading our dashboard
=============================
This is not really necessary, but the exercise is interesting. Imagine that our awesome dashboard
is a large application, with potentially multiple external libraries, lots of code/styles/templates.
Also, suppose that the dashboard is only used by some users in some business flows, so we want to
lazy load it in order to speed up the loading of the web client in most cases.
So, let us do that!
.. exercise::
#. Modify the manifest to create a new :ref:`bundle <reference/assets_bundle>`
`awesome_tshirt.dashboard`.
#. Add the awesome dashboard code to this bundle. If needed you can create folders and move
files.
#. Remove the code from the `web.assets_backend` bundle so it is not loaded twice.
So far, we removed the dashboard from the main bundle, but it should now be lazily loaded. Right
now, there is no client action registered in the action registry.
.. exercise::
#. Create a new file :file:`dashboard_loader.js`.
#. Copy the code registering `AwesomeDashboard` to the dashboard loader.
#. Register `AwesomeDashboard` as a `LazyComponent`.
#. Modify the code in the dashboard loader to use the lazy component `AwesomeDashboard`.
.. seealso::
- :ref:`Documentation on assets <reference/assets>`
- `Code: LazyComponent <{GITHUB_PATH}/addons/web/static/src/core/assets.js#L255>`_