mirror of
https://github.com/odoo/documentation.git
synced 2026-01-03 18:26:27 +07:00
wip
This commit is contained in:
committed by
Simon Genin
parent
4331177bb6
commit
fd28f72c68
@@ -0,0 +1,54 @@
|
||||
|
||||
Action Service
|
||||
==============
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``action_manager``
|
||||
- ``notifications`` , ``rpc`` , ``router`` , ``user``
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The action manager handles every `\ ``ir.actions.actions`` <https://www.odoo.com/documentation/14.0/reference/actions.html>`_ triggered by user interaction.
|
||||
Clicking on a menu item, on a button, or changing of view type are all examples of
|
||||
interactions handled by the action manager.
|
||||
|
||||
The action manager gives priority to the most recent user request, and will drop
|
||||
a request if another one comes after. The second request obviously takes the state
|
||||
of the action manager as it was before the first request. When possible, unnecessary RPC
|
||||
and rendering must be canceled if another request is made by the user.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
The action_manager service exports some methods, which are not all meant to be used by everyone:
|
||||
|
||||
|
||||
*
|
||||
`doAction(action: ActionRequest, options: ActionOptions): Promise<void>;`: probably the one thing to remember and use. It executes the action represented by the ActionRequest descriptor. An `ActionRequest` can be either its full XML id, its postgres id, the tag of the client action, or an object fully describing the action. `ActionOptions` is ....... . The moment when the Promise is resolved is guaranteed only in the following crucial cases:
|
||||
|
||||
|
||||
* ``ir.actions.report`` : when the report is downloaded, or when the report is displayed in the DOM.
|
||||
* ``ir.actions.act_window`` : when the action is visible in the DOM.
|
||||
* ``ir.actions.act_window_close`` : when the dialog has been closed. If there was no dialog, the Promise resolves immediately.
|
||||
For all other actions types, there are no guarantee of that precise moment.
|
||||
|
||||
*
|
||||
``switchView(viewType: viewType): void`` : only applicable when the current visible action is an ``ir.actions.act_window``. It switches the view to the target viewType. In principle, it shouldn't be used outside of frameworky developments.
|
||||
|
||||
*
|
||||
``restore(jsId: string): void;`` : restores the controller with ``jsId`` from the breadcrumbs stack back in the DOM. It shouldn't be used outside of frameworky developments.
|
||||
|
||||
*
|
||||
``loadState(state: Route["hash"], options: ActionOptions): Promise<boolean>;`` : an algorithm that decides what the action manager should do with the data present in the URL's hash. It returns a ``boolean`` wrapped in a Promise. The boolean indicates whether the action manager did handle the URL's state. This method must not be used.
|
||||
|
||||
Technical notes
|
||||
---------------
|
||||
|
||||
The action manager service tells the world that a rendering is necessary by triggering the
|
||||
event ``ACTION_MANAGER:UPDATE`` on the `main bus <./../bus.md>`_.
|
||||
@@ -0,0 +1,70 @@
|
||||
|
||||
Command Service
|
||||
===============
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``command``
|
||||
- ``dialog`` , ``hotkey`` , ``ui``
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``command`` service offers a way to register commands.
|
||||
|
||||
A Command Palette could then be displayed through the hotkey ``Control+K``.
|
||||
|
||||
This palette displays a list including :
|
||||
|
||||
|
||||
* the commands registered in the service
|
||||
* any visible elements in the ``ui.activeElement`` that are accessible through an ``[data-hotkey]`` attribute.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
The ``command`` service provides the following API:
|
||||
|
||||
|
||||
*
|
||||
``type Command = { name: string, action: ()=>void, category?: string, hotkey?: string, }``
|
||||
|
||||
*
|
||||
``registerCommand(command: Command): number``
|
||||
|
||||
*
|
||||
``unregisterCommand(token: number)``
|
||||
|
||||
In addition to that, you have access to some development helpers which are **greatly** recommended:
|
||||
|
||||
|
||||
* ``useCommand(command: Command): void`` :
|
||||
a hook that ensures your registration exist only when your component is mounted.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
useCommand({
|
||||
name: "My Command 1",
|
||||
action: () => {
|
||||
// code when command 1 is executed
|
||||
}
|
||||
});
|
||||
useCommand({
|
||||
name: "My Super Command",
|
||||
hotkey: "shift-home",
|
||||
action: () => {
|
||||
// code when super command is executed
|
||||
// note that the super command can also get executed with the hotkey "shift-home"
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
Company Service
|
||||
===============
|
||||
@@ -0,0 +1,2 @@
|
||||
Cookie Service
|
||||
==============
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
Dialog Service
|
||||
==============
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``dialog_manager``
|
||||
- None
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``dialog manager service`` offers a simple API that allows to open dialogs but with
|
||||
few interactions possible: when possible, it is better to instantiate a
|
||||
dialog by using a Dialog tag in a component template.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
The dialog_manager service exports one method:
|
||||
|
||||
|
||||
* ``open(dialogClass: Type<Component>, props?: object): void`` : the ``dialog class`` given as
|
||||
first parameter is instantiated with the optional props given (or with ``{}`` ).
|
||||
|
||||
By ``dialog class`` , we mean a class extending ``owl.Component`` and having as root node ``Dialog`` :
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class CustomDialog extends owl.Component {
|
||||
static template = owl.tags.xml`
|
||||
<Dialog title="'Custom title'" size="'modal-xl'">
|
||||
...
|
||||
</Dialog
|
||||
`;
|
||||
...
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
Effect Service
|
||||
==============
|
||||
@@ -0,0 +1,71 @@
|
||||
|
||||
Error Service
|
||||
=============
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``crash_manager``
|
||||
- `\ ``dialog_manager`` <dialog_manager.md>`_
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``crash manager service`` responsibility is to display a dialog
|
||||
when an rpc error or a client error occurs. No interaction with the
|
||||
crash manager is possible. If deployed, the crash manager simply listens
|
||||
to some event and opens the appropriate dialogs when needed.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
The crash_manager service does not export anything.
|
||||
|
||||
Channels
|
||||
--------
|
||||
|
||||
The crash manager receives errors throught two channels:
|
||||
|
||||
|
||||
* it listens on ``env.bus`` the event ``RPC_ERROR`` ;
|
||||
* it listens on ``window`` the event ``error`` ;
|
||||
|
||||
RPC_ERROR event handling
|
||||
------------------------
|
||||
|
||||
When an event ``RPC_ERROR`` is triggerd on the bus, the crash manager processes the
|
||||
``RPCError`` in the following way:
|
||||
|
||||
|
||||
*
|
||||
look if the error's ``type`` is ``server`` ;
|
||||
|
||||
*
|
||||
if this is the case, the optional error's ``name`` indicates which `dialog class <./dialog_manager.md#api>`_
|
||||
(from the registry ``errorDialogs`` ) should be used to display the error details.
|
||||
If the error is unnamed or no `dialog class] <./dialog_manager.md#api>`_ corresponds to its name, the class
|
||||
``ErrorDialog`` is used by default.
|
||||
|
||||
*
|
||||
The `dialog class <./dialog_manager.md#api>`_ is instantiated with one prop: the error itself.
|
||||
|
||||
This is how a ``UserError`` , ``AccessError``... or a custom server error is handled.
|
||||
|
||||
ERROR event handlling
|
||||
---------------------
|
||||
|
||||
When an event ``error`` is triggered on window, the crash manager processes the ``ErrorEvent``
|
||||
received in the following way:
|
||||
|
||||
|
||||
*
|
||||
if some information on the file name where the error occurs, the error stack... is available
|
||||
an ``ErrorDialog`` is displayed showing that information.
|
||||
|
||||
*
|
||||
if such information is not available, an ``ErrorDialog`` is also displayed but with a generic message.
|
||||
|
||||
This is how client errors are treated.
|
||||
@@ -0,0 +1,244 @@
|
||||
|
||||
Hotkey Service
|
||||
==============
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``hotkey``
|
||||
- ``ui``
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``hotkey`` service offers an easy way to react to a
|
||||
fine bounded subset of keyboard inputs: `hotkeys <#hotkey-definition>`_.
|
||||
|
||||
It provides some very special features:
|
||||
|
||||
|
||||
*
|
||||
awareness of the UI active element: no need to worry about that from your side.
|
||||
|
||||
*
|
||||
a clean subset of listenable hotkeys:
|
||||
it ensures a consistent experience through different OSes or browsers.
|
||||
|
||||
*
|
||||
a ``useHotkey`` hook: it ensures your JS code executes only
|
||||
when your component is alive and present in the DOM.
|
||||
|
||||
*
|
||||
a ``[data-hotkey]`` attribute: it gives a JS-free way to make
|
||||
any HTML element "clickable" through an hotkey press.
|
||||
|
||||
*
|
||||
a single key to display overlays over all HTML elements having ``[data-hotkey]`` attributes.
|
||||
|
||||
Good To Know - ALT is required
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
By default, to trigger an hotkey, it is required to also press the ``ALT`` key:
|
||||
|
||||
..
|
||||
|
||||
*e.g.* **ALT+\ *C** would trigger the **C** hotkey.
|
||||
|
||||
|
||||
An option is available to make it optional in some cases. See the `API <#api>`_ section.
|
||||
|
||||
Good To Know - MAC users
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To ensure a similar experience to Mac users some keys had to get swapped :
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Standard Key is...
|
||||
- MacOS Corresponding Key is...
|
||||
* - ``alt``
|
||||
- ``control``
|
||||
* - ``control``
|
||||
- ``meta`` (known as *Command* by mac users)
|
||||
|
||||
|
||||
Hotkey Definition
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
An **hotkey** represents as a string a single keyboard
|
||||
input from a *single key* combined or not with *modifiers*.
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Authorized Single Keys
|
||||
* - **a-z**
|
||||
* - **0-9**
|
||||
* - **ArrowUp** , **ArrowLeft** , **ArrowDown** and **ArrowRight**
|
||||
* - **PageUp** , **PageDown** , **Home** and **End**
|
||||
* - **Backspace** , **Enter** and **Escape**
|
||||
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Authorized Modifiers
|
||||
* - **Control**
|
||||
* - **Shift**
|
||||
|
||||
|
||||
Hotkeys **must be** written following these rules:
|
||||
|
||||
|
||||
* they are not case sensitive.
|
||||
* the composition character is the plus sign: "\ **+** ".
|
||||
* each hotkey can have none or any modifier in the authorized subset.
|
||||
* order of their parts is important:
|
||||
|
||||
* modifiers must come first
|
||||
* modifiers must get alphabetically sorted (\ **Control** is always before **Shift** )
|
||||
* single key part must come last
|
||||
|
||||
E.g. following hotkeys are valid:
|
||||
|
||||
|
||||
* ``Control+Shift+5``
|
||||
* ``g``
|
||||
* ``Control+g`` (same as ``Control+G`` )
|
||||
|
||||
E.g. following hotkeys are **NOT** valid:
|
||||
|
||||
|
||||
* ``Alt+o`` : **alt** is neither a valid modifier nor a valid single key
|
||||
* ``o+d`` : combining two or more single keys is not valid
|
||||
* ``Shift-p`` : the composition character must be "+" and not "-"
|
||||
* ``Tab`` : it is not part of the list of valid single keys, nor modifiers
|
||||
|
||||
Hotkey Activation
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Hotkeys are activated through keyboard inputs.
|
||||
|
||||
By default, to activate an hotkey, ``ALT`` key should get pressed simultaneously.
|
||||
It is also possible to register an hotkey that will be fireable, even without pressing ALT key.
|
||||
|
||||
When the service detects an hotkey activation, it will:
|
||||
|
||||
|
||||
* execute **all matching registrations callbacks**.
|
||||
* click on **all visible elements having a matching ``[data-hotkey]`` attribute**.
|
||||
|
||||
The ``hotkey`` service will also **make sure that those
|
||||
registrations and elements belong to the correct UI active element** (see `\ ``ui`` service <ui.md>`_\ ).
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
The ``hotkey`` service provides the following API:
|
||||
|
||||
|
||||
*
|
||||
``registerHotkey(hotkey: string, callback: ()=>void, options: { altIsOptional?: boolean, allowRepeat?: boolean }): number``
|
||||
|
||||
it asks the service to call the given callback when a matching hotkey is pressed.
|
||||
|
||||
``options.altIsOptional`` : default is false.
|
||||
|
||||
``options.allowRepeat`` : default is false.
|
||||
|
||||
This method returns a token you can use to unsubscribe later on.
|
||||
|
||||
*
|
||||
``unregisterHotkey(token: number): void``
|
||||
|
||||
it asks the service to forget about the token matching registration.
|
||||
|
||||
In addition to that, you have access to some development helpers which are **greatly** recommended:
|
||||
|
||||
|
||||
*
|
||||
``useHotkey(hotkey: string, callback: ()=>void, options: { altIsOptional?: boolean, allowRepeat?: boolean }): void``
|
||||
|
||||
a hook that ensures your registration exists only when your component is mounted.
|
||||
|
||||
*
|
||||
``[data-hotkey]``
|
||||
|
||||
an HTML attribute taking an hotkey definition.
|
||||
|
||||
When the defined hotkey is pressed, the element gets clicked.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
``useHotkey`` hook
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
useHotkey("a", this.onAHotkey.bind(this));
|
||||
useHotkey("Home", () => this.onHomeHotkey());
|
||||
}
|
||||
onAHotkey() { ... }
|
||||
onHomeHotkey() { ... }
|
||||
}
|
||||
|
||||
``[data-hotkey]`` attribute
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
this.variableHotkey = "control+j";
|
||||
}
|
||||
onButton1Clicked() {
|
||||
console.log("clicked either with the mouse or with hotkey 'Shift+o'");
|
||||
}
|
||||
onButton2Clicked() {
|
||||
console.log(`clicked either with the mouse or with hotkey '${this.variableHotkey}'`);
|
||||
}
|
||||
}
|
||||
MyComponent.template = xml`
|
||||
<div>
|
||||
|
||||
<button t-on-click="onButton1Clicked" data-hotkey="Shift+o">
|
||||
One!
|
||||
</button>
|
||||
|
||||
<button t-on-click="onButton2Clicked" t-att-data-hotkey="variableHotkey">
|
||||
Two!
|
||||
</button>
|
||||
|
||||
</div>
|
||||
`;
|
||||
|
||||
manual usage of the service
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
this.hotkey = useService("hotkey");
|
||||
}
|
||||
mounted() {
|
||||
this.hotkeyToken1 = this.hotkey.registerHotkey("backspace", () =>
|
||||
console.log("backspace has been pressed")
|
||||
);
|
||||
this.hotkeyToken2 = this.hotkey.registerHotkey("Shift+P", () =>
|
||||
console.log('Someone pressed on "shift+p"!')
|
||||
);
|
||||
}
|
||||
willUnmount() {
|
||||
// You need to manually unregister your registrations when needed!
|
||||
this.hotkey.unregisterHotkey(this.hotkeyToken1);
|
||||
this.hotkey.unregisterHotkey(this.hotkeyToken2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
Http Service
|
||||
============
|
||||
@@ -0,0 +1,2 @@
|
||||
Localization Service
|
||||
====================
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
Menu Service
|
||||
============
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``menus``
|
||||
- ``action_manager`` , ``router``
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``menus`` service is an asynchronous service: once the ``deploy`` method is
|
||||
called, it will call the server (using the ``/web/webclient/load_menus/...`` url) to fetch
|
||||
the data. Once it is done, the service is available and can be used to query
|
||||
informations on the menu items.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
Here is a description of all exported methods:
|
||||
|
||||
|
||||
* ``get(menuId)``
|
||||
* ``apps``
|
||||
* ``getMenusAsTree(...)``
|
||||
@@ -0,0 +1,73 @@
|
||||
|
||||
Notification Service
|
||||
====================
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``notifications``
|
||||
- None
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Like the name suggests, the ``notifications`` service allows the rest of the
|
||||
interface to display notifications (to inform the user of some interesting
|
||||
relevant facts).
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
The ``notifications`` service provides two methods:
|
||||
|
||||
|
||||
*
|
||||
``create(message: string, options?: Options): number``. This method generates a
|
||||
new notification, and returns an ``id`` value.
|
||||
|
||||
Here is a list of the various options:
|
||||
|
||||
|
||||
* ``title (string)`` : if given, this string will be used as a title
|
||||
* ``sticky (boolean)`` : if true, this flag states that the notification should only close
|
||||
with an action of the user (not close itself automatically)
|
||||
* `type (string)`: can be one of the following: ``danger`` , ``warning`` , ``success`` , ``info``.
|
||||
These types will slightly alter the color and the icon that will be used
|
||||
to draw the notification
|
||||
* ``icon (string)`` : if no type is given, this string describes a css class that
|
||||
will be used. It is meant to use a font awesome class. For example, ``fa-cog``
|
||||
* ``className (string)`` : describes a css class that will be added to the
|
||||
notification. It is useful when one needs to add some special style to a
|
||||
notification.
|
||||
* ``messageIsHtml (boolean)`` : if true, the message won't be escaped (false by default)
|
||||
|
||||
*
|
||||
``close(id: string)`` : this method will simply close a notification with a specific ``id`` ,
|
||||
if it was not already closed.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
Here is how one component can simply display a notification:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class MyComponent extends Component {
|
||||
...
|
||||
notifications = useService('notifications');
|
||||
|
||||
...
|
||||
|
||||
someHandler() {
|
||||
this.notifications.create('Look behind you!!!', { sticky: true });
|
||||
}
|
||||
}
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
|
||||
* whenever the list of notifications is updated, a ``NOTIFICATIONS_CHANGE`` event is
|
||||
triggered on the main bus.
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
ORM Service
|
||||
=============
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``model``
|
||||
- ``rpc`` , ``user``
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``model`` service is the standard way to interact with a python model, on the
|
||||
server. Obviously, each such interaction is asynchronous (and will be done by
|
||||
using the ``rpc`` service).
|
||||
|
||||
In short, the ``model`` service provides a simple API to call the most common orm
|
||||
methods, such as ``read`` , ``search_read`` , ``write`` ... It also has a generic ``call``
|
||||
method to call an arbitrary method from the model.
|
||||
|
||||
Another interesting point to mention is that the user context will automatically
|
||||
be added to each model request.
|
||||
|
||||
Here is a short example of a few possible ways to interact with the ``model``
|
||||
service:
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
class MyComponent extends Component {
|
||||
model = useService("model");
|
||||
|
||||
async someMethod() {
|
||||
// return all fields from res.partner 3
|
||||
const result = await this.model("res.partner").read([3]);
|
||||
|
||||
// create a some.model record with a field name set to 'some name' and a
|
||||
// color key set in the context
|
||||
const id = await this.model("some.model").create({ name: "some name" }, { color: "red" });
|
||||
|
||||
// perform a read group with some parameters
|
||||
const groups = await this.model("sale.order").readGroup(
|
||||
[["user_id", "=", 2]],
|
||||
["amount_total:sum"],
|
||||
["date_order"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Because the ``model`` service is a higher level service than ``rpc`` , easier to use,
|
||||
and with some additional features, it should be preferred above ``rpc``.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
The ``model`` service exports a single function with the following signature:
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
function model(modelName: string): Model {
|
||||
...
|
||||
}
|
||||
|
||||
A ``Model`` is here defined as an object linked to the ``modelName`` odoo model (for
|
||||
example ``res.partner`` or ``sale.order`` ) with the following five functions, each
|
||||
of them bound to ``modelName`` :
|
||||
|
||||
|
||||
* ``create(state: object, ctx?: Context): Promise<number>`` : call the ``create`` method
|
||||
for the ``modelName`` model defined above,
|
||||
* ``read(ids: number[], fields: string[], ctx?: Context): Promise<any>`` : read one
|
||||
or more records
|
||||
* ``readGroup(domain: any[], fields: string[], groupby: string[], options?: GroupByOptions, ctx?: Context): Promise<ReadGroupResult>;``
|
||||
* ``searchRead(domain: Domain, fields: string[], options?: SearchReadOptions, ctx?: Context): Promise<SearchReadResult>;``
|
||||
* ``unlink(ids: number[], ctx?: Context): Promise<void>``
|
||||
* ``write(ids: number[], data: object, context?: Context): Promise<boolean>``
|
||||
* ``call(method: string, args?: any[], kwargs?: KWargs): Promise<any>``
|
||||
|
||||
Additional notes
|
||||
----------------
|
||||
|
||||
|
||||
* since it uses the ``rpc`` service, it provides the same optimization when used
|
||||
by a component: an error will be thrown if a destroyed component attempts to
|
||||
initiate a model call, and requests will be left pending if a component is
|
||||
destroyed in the meantime.
|
||||
@@ -0,0 +1,78 @@
|
||||
|
||||
Popover Service
|
||||
===============
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``popover``
|
||||
- None
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``popover`` service offers a simple API that allows to open popovers but with
|
||||
few interactions possible: when possible, it is better to instantiate a
|
||||
popover by using a Popover tag in a component template.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
The ``popover`` service exports one method:
|
||||
|
||||
|
||||
*
|
||||
``add(params: Object): string``
|
||||
Signals the manager to add a popover.
|
||||
|
||||
``params`` can contain any of these options:
|
||||
|
||||
|
||||
* ``Component: Type<Component>`` : A class extending ``owl.Component`` and having
|
||||
as root node ``Popover``.
|
||||
* ``props: Object`` : The props passed to the component.
|
||||
* ``content: string`` : A text which is displayed in the popover.
|
||||
Cannot be used with ``Component``.
|
||||
* ``key: string`` : A key to retrieve the popover and remove it later.
|
||||
If no key is given then one will be generated.
|
||||
* ``onClose: (key: string) => void`` : A callback which is executed when the
|
||||
popover is closed.
|
||||
* ``keepOnClose: boolean = false`` : if true then the manager will keep the
|
||||
popover when it closes otherwise the manager removes the popover.
|
||||
|
||||
Returns the ``key`` given in ``params`` or the generated one.
|
||||
|
||||
*
|
||||
``remove(key: string): void``
|
||||
Signals the manager to remove the popover with key = ``key``.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class CustomPopover extends owl.Component {}
|
||||
CustomPopover.template = owl.tags.xml`
|
||||
<Popover target="props.target" trigger="'none'">
|
||||
<t t-set-slot="content">
|
||||
My popover
|
||||
</t>
|
||||
</Popover>
|
||||
`;
|
||||
|
||||
...
|
||||
|
||||
popoverService.add({
|
||||
key: "my-popover",
|
||||
Component: CustomPopover,
|
||||
props: {
|
||||
target: "#target",
|
||||
},
|
||||
keepOnClose: true,
|
||||
});
|
||||
|
||||
...
|
||||
|
||||
popoverService.remove("my-popover");
|
||||
@@ -0,0 +1,2 @@
|
||||
Profiling Service
|
||||
=================
|
||||
144
content/developer/reference/javascript/services/readme.rst
Normal file
144
content/developer/reference/javascript/services/readme.rst
Normal file
@@ -0,0 +1,144 @@
|
||||
|
||||
Services
|
||||
========
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The Odoo web client is organized in *components*. It is common for a component
|
||||
to have a need to perform tasks or obtain some information outside of itself.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
* performing an RPC
|
||||
* displaying a notification
|
||||
* asking the web client to change the current action/view
|
||||
* ...
|
||||
|
||||
These kind of features are represented in the web client under the name *service*.
|
||||
A service is basically a piece of code that is started with the web client, and
|
||||
available to the interface (and to other services).
|
||||
|
||||
List of all services
|
||||
--------------------
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Service
|
||||
- Purpose
|
||||
* - `\ ``action_manager`` <action_manager.md>`_
|
||||
- perform actions following user interactions
|
||||
* - `\ ``command`` <../commands/command_service.md>`_
|
||||
- manage commands
|
||||
* - `\ ``crash_manager`` <crash_manager.md>`_
|
||||
- listen errors and open error dialogs
|
||||
* - `\ ``dialog_manager`` <dialog_manager.md>`_
|
||||
- open dialogs
|
||||
* - `\ ``hotkey`` <hotkey.md>`_
|
||||
- manage all keyboard shortcuts in a single place
|
||||
* - `\ ``menus`` <menus.md>`_
|
||||
- keep track of all menu items (app and submenus)
|
||||
* - `\ ``model`` <model.md>`_
|
||||
- interact with (python) models
|
||||
* - `\ ``notifications`` <notifications.md>`_
|
||||
- display a notification (or error)
|
||||
* - `\ ``popover`` <popover.md>`_
|
||||
- add/remove popover
|
||||
* - `\ ``router`` <router.md>`_
|
||||
- manage the url
|
||||
* - `\ ``rpc`` <rpc.md>`_
|
||||
- perform a RPC (in other word, call the server)
|
||||
* - `\ ``title`` <title.md>`_
|
||||
- allow to read/modify the document title
|
||||
* - `\ ``ui`` <ui.md>`_
|
||||
- miscellaneous ui features: active element, block/unblock
|
||||
* - `\ ``user`` <user.md>`_
|
||||
- keep track of user main properties (lang, ...) and context
|
||||
* - `\ ``view_manager`` <view_manager.md>`_
|
||||
- load (and keep in cache) views information
|
||||
|
||||
|
||||
Defining a service
|
||||
------------------
|
||||
|
||||
A service needs to follow the following interface:
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
export interface Service<T = any> {
|
||||
dependencies?: string[];
|
||||
deploy: (env: OdooEnv, odoo: Odoo) => Promise<T> | T;
|
||||
}
|
||||
|
||||
It may define some ``dependencies``. In that case, the dependent services will be
|
||||
started first, and ready when the current service is started.
|
||||
|
||||
The ``deploy`` method is the most important: the return value of the ``deploy``
|
||||
method will be the value of the service. This method can be asynchronous,
|
||||
in which case the value of the service will be the result of that promise.
|
||||
|
||||
Some services do not export any value. They may just do their work without a
|
||||
need to be directly called by other code. In that case, their value will be
|
||||
set to ``null`` in ``env.services``.
|
||||
|
||||
Once a service is defined, it needs then to be registered to the ``serviceRegistry`` ,
|
||||
to make sure it is properly deployed when the application is started.
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
serviceRegistry.add(myService.name, myService);
|
||||
|
||||
For example, imagine that we want to provide a service that manage a counter.
|
||||
It could be defined like this:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const counterService = {
|
||||
start(env) {
|
||||
let value = 0;
|
||||
return {
|
||||
getValue() {
|
||||
return value;
|
||||
},
|
||||
increment() {
|
||||
value++;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
serviceRegistry.add("counter", counterService);
|
||||
|
||||
The services listed `above <./#list-of-all-services>`_ are deployed before the web client is mounted but it
|
||||
is allowed to add a service to the ``serviceRegistry`` after that moment. It will be automatically deployed.
|
||||
|
||||
Using a service
|
||||
---------------
|
||||
|
||||
To use a service, a component needs to call the ``useService`` hook. This will
|
||||
return a reference to the service value, that can then be used by the component.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class MyComponent extends Component {
|
||||
rpc = useService('rpc');
|
||||
|
||||
async willStart() {
|
||||
this.someValue = await this.rpc(...);
|
||||
}
|
||||
}
|
||||
|
||||
Note: If the value of the service is a function (for example, like the ``rpc``
|
||||
service), then the ``useService`` hook will bind it to the current component. This
|
||||
means that the code for the service can actually access the component reference.
|
||||
|
||||
A service that depends on other services (and having properly declared its ``dependencies`` )
|
||||
should use the other services by accessing them directly through the environment.
|
||||
For example, the service ``action_manager`` uses the service ``rpc`` in that way:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
action = await env.services.rpc(...);
|
||||
@@ -0,0 +1,105 @@
|
||||
|
||||
Router Service
|
||||
==============
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``router``
|
||||
- None
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``router`` service provides three features:
|
||||
|
||||
|
||||
* information about the current route
|
||||
* provides a way for the application to update the url, depending on its state
|
||||
* listens to every hash change, and notifies the rest of the application
|
||||
|
||||
Current route
|
||||
-------------
|
||||
|
||||
The current route can be accessed with the ``current`` key. It contains the following
|
||||
information:
|
||||
|
||||
|
||||
* ``pathname (string)`` : the path for the current location (most likely ``/web`` )
|
||||
* ``search (object)`` : a dictionary mapping each search keyword from the url to
|
||||
its value. An empty string is the value if no value was explicitely given
|
||||
* ``hash (object)`` : same as above, but for values described in the hash.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
// url = /web?debug=assets#action=123&owl&menu_id=174
|
||||
|
||||
const { pathname, search, hash } = env.services.router.current;
|
||||
console.log(pathname); // /web
|
||||
console.log(search); // { debug="assets" }
|
||||
console.log(hash); // { action:123, owl: "", menu_id: 174 }
|
||||
|
||||
Updating the URL
|
||||
----------------
|
||||
|
||||
URL updates need to use the ``pushState`` method:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
pushState(hash: object, replace?: boolean)
|
||||
|
||||
The ``hash`` argument is an object containing a mapping from some key to some values.
|
||||
If a value is set to an empty string, the key will be simply added to the url
|
||||
without any value at all.
|
||||
|
||||
If true, the ``replace`` argument tells the router that the url hash should be
|
||||
completely replaced. Otherwise, the new values will be added to the current url.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
// url = /web#action_id=123
|
||||
|
||||
env.services.router.pushState({ menu_id: 321 });
|
||||
// url is now /web#action_id=123&menu_id=321
|
||||
|
||||
env.services.router.pushState({ yipyip: "" }, replace: true);
|
||||
// url is now /web#yipyip
|
||||
|
||||
Note that using ``pushState`` does not trigger a ``hashchange`` event, nor a
|
||||
``ROUTE_CHANGE`` in the main bus. This is because this method is intended to be
|
||||
used "from the inside", to update the url so that it matches the actual current
|
||||
displayed state.
|
||||
|
||||
Reacting to hash changes
|
||||
------------------------
|
||||
|
||||
This is mostly useful for the action manager, which needs to act when something
|
||||
in the url changed.
|
||||
|
||||
When created, the router listens to every (external) hash changes, and trigger a
|
||||
``ROUTE_CHANGE`` event on the main bus,
|
||||
|
||||
Redirect URL
|
||||
------------
|
||||
|
||||
The ``redirect`` method will redirect the browser to ``url``. If ``wait`` is true, sleep 1s and wait for the server (e.g. after a restart).
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
redirect(url: string, wait?: boolean)
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
// The complete url is "www.localhost/wowl"
|
||||
env.services.router.redirect("/wowl/tests");
|
||||
|
||||
// The complete url is "www.localhost/wowl/tests"
|
||||
116
content/developer/reference/javascript/services/rpc_service.rst
Normal file
116
content/developer/reference/javascript/services/rpc_service.rst
Normal file
@@ -0,0 +1,116 @@
|
||||
|
||||
RPC service
|
||||
===========
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``rpc``
|
||||
- ``notifications``
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The RPC service has a single purpose: send requests to the server. Its external
|
||||
API is a single function, with the following type:
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
type RPC = (route: string, params?: { [key: string]: any }) => Promise<any>;
|
||||
|
||||
This makes it easy to use. For example, calling a controller ``/some/route`` can
|
||||
be done with the following code:
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
class MyComponent extends Component {
|
||||
rpc = useService("rpc");
|
||||
|
||||
async someMethod() {
|
||||
const result = await this.rpc("/some/route");
|
||||
}
|
||||
}
|
||||
|
||||
Note that the ``rpc`` service is considered a low-level service. It should only be
|
||||
used to interact with Odoo controllers. To work with models (which is by far the
|
||||
most important usecase), one should use the `\ ``model`` <model.md>`_ service instead.
|
||||
|
||||
Calling a controller
|
||||
--------------------
|
||||
|
||||
As explained in the overview, calling a controller is very simple. The route
|
||||
should be the first argument, and optionally, a ``params`` object can be given as
|
||||
a second argument.
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
const result = await this.rpc("/my/route", { some: "value" });
|
||||
|
||||
Technical notes
|
||||
---------------
|
||||
|
||||
|
||||
* The ``rpc`` service communicates with the server by using a ``XMLHTTPRequest`` object,
|
||||
configured to work with ``application/json`` content type.
|
||||
* So clearly the content of the request should be JSON serializable.
|
||||
* Each request done by this service uses the ``POST`` http method
|
||||
* Server errors actually return the response with an http code 200. But the ``rpc``
|
||||
service will treat them as error (see below)
|
||||
|
||||
Error Handling
|
||||
--------------
|
||||
|
||||
An rpc can fail for two main reasons:
|
||||
|
||||
|
||||
* either the odoo server returns an error (so, we call this a ``server`` error).
|
||||
In that case the http request will return with am http code 200 BUT with a
|
||||
response object containing an ``error`` key.
|
||||
* or there is some other kind of network error
|
||||
|
||||
When a rpc fails, then:
|
||||
|
||||
|
||||
* the promise representing the rpc is rejected, so the calling code will crash,
|
||||
unless it handles the situation
|
||||
*
|
||||
an event ``RPC_ERROR`` is triggered on the main application bus. The event payload
|
||||
contains a description of the cause of the error:
|
||||
|
||||
If it is a server error (the server code threw an exception). In that case
|
||||
the event payload will be an object with the following keys:
|
||||
|
||||
|
||||
* ``type = 'server'``
|
||||
* ``message(string)``
|
||||
*
|
||||
``code(number)``
|
||||
|
||||
*
|
||||
``name(string)`` (optional, used by the crash manager to look for an appropriate
|
||||
dialog to use when handling the error)
|
||||
|
||||
* ``subType(string)`` (optional, often used to determine the dialog title)
|
||||
* ``data(object)`` (optional object that can contain various keys among which
|
||||
``debug`` : the main debug information, with the call stack)
|
||||
|
||||
If it is a network error, then the error description is simply an object
|
||||
``{type: 'network'}``.
|
||||
When a network error occurs, a notification is displayed and the server is regularly
|
||||
contacted until it responds. The notification is closed as soon as the server responds.
|
||||
|
||||
Specialized behaviour for components
|
||||
------------------------------------
|
||||
|
||||
The ``rpc`` service has a specific optimization to make using it with component safer. It
|
||||
does two things:
|
||||
|
||||
|
||||
* if a component is destroyed at the moment an rpc is initiated, an error will
|
||||
be thrown. This is considered an error, a destroyed component should be inert.
|
||||
* if a component is destroyed when a rpc is completed, which is a normal situation
|
||||
in an application, then the promise is simply left pending, to prevent any
|
||||
followup code to execute.
|
||||
@@ -0,0 +1,2 @@
|
||||
Scroller Service
|
||||
================
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
Title Service
|
||||
=============
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``title``
|
||||
- None
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``title service`` offers a simple API that allows to read/modify the document title.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
The ``title service`` exports two methods and a value:
|
||||
|
||||
|
||||
* ``current (string)`` ,
|
||||
* ``getParts(): Parts`` ,
|
||||
* ``setParts(parts: Parts): void`` ,
|
||||
|
||||
where the type ``Parts`` is:
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
interface Parts {
|
||||
[key: string]: string | null;
|
||||
}
|
||||
|
||||
The ``getParts`` method returns a copy of an object ``titleParts`` maintained by the tilte service.
|
||||
|
||||
The value ``current`` is structured in the following way: ``value_1 - ... - value_n`` where
|
||||
``value_1,...,value_n`` are the values (all not null) found in the object ``titleParts``.
|
||||
|
||||
The ``setParts`` method allow to add/replace/delete several parts of the title. Delete a part (a value) is done
|
||||
by setting the associated key value to null;
|
||||
|
||||
Example:
|
||||
|
||||
If the title is composed of the following parts:
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
{
|
||||
odoo: "Odoo",
|
||||
action: "Import",
|
||||
}
|
||||
|
||||
with ``current`` value being ``Odoo - Import`` ,
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
setParts({
|
||||
odoo: "Open ERP",
|
||||
action: null,
|
||||
chat: "Sauron"
|
||||
});
|
||||
|
||||
will give the title ``Open ERP - Sauron`` and ``getParts`` will return
|
||||
|
||||
.. code-block:: ts
|
||||
|
||||
{
|
||||
odoo: "Open ERP",
|
||||
chat: "Sauron",
|
||||
}
|
||||
193
content/developer/reference/javascript/services/ui_service.rst
Normal file
193
content/developer/reference/javascript/services/ui_service.rst
Normal file
@@ -0,0 +1,193 @@
|
||||
|
||||
UI service
|
||||
==========
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``ui``
|
||||
- None
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``ui`` service offers miscellaneous UI features:
|
||||
|
||||
|
||||
* active element management.
|
||||
The default UI active element is the ``document`` element, but the ``ui`` service
|
||||
lets anyone become the UI active element. It is useful e.g. for dialogs.
|
||||
* block or unblock the UI.
|
||||
When the ui will be blocked, a loading screen blocking any action will cover the UI.
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
The ``ui`` service provides the following API:
|
||||
|
||||
|
||||
*
|
||||
``bus: EventBus`` : a bus, on which are triggered
|
||||
|
||||
|
||||
* ``active-element-changed (activeElement: DOMElement)`` when the UI active element has changed.
|
||||
|
||||
*
|
||||
``block(): void`` : this method will activate the loading screen to block the ui.
|
||||
|
||||
*
|
||||
``unblock(): void`` : This method will disable the loading screen in order to unblock the ui.
|
||||
if it was not already disable.
|
||||
|
||||
*
|
||||
``ìsBlocked (boolean)`` : informs on the UI blocked state
|
||||
|
||||
*
|
||||
``activateElement(activateElement: DOMElement): void`` : applies an UI active element.
|
||||
|
||||
*
|
||||
``activeElement: DOMElement`` : gives the actual UI active element
|
||||
|
||||
*
|
||||
``getVisibleElements(selector: string)`` : returns all elements matching the given selector that are displayed somewhere on the active element.
|
||||
|
||||
In addition to that, you have access to some development helpers which are **greatly** recommended:
|
||||
|
||||
|
||||
* ``useActiveElement(refName?:string)`` : a hook that ensures the UI active element will
|
||||
take place/get released each time your component gets mounted/unmounted.
|
||||
By default, the element that will be the UI active element is the component root's.
|
||||
It can be delegated to another element through the usage of a ``t-ref`` directive,
|
||||
providing its value to this hook. In that case, **it is mandatory** that the referenced
|
||||
element is fixed and not dynamically attached in/detached from the DOM (e.g. with t-if directive).
|
||||
|
||||
Good to know: UI blocking
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If the ``block()`` method is called several times simultaneously, the same number of times the ``unblock()`` function must be used to unblock the UI.
|
||||
|
||||
Good to know: UI Active Element
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Due to the way components are mounted by the Owl engine (from the bottom to the top), you should be aware that if nested components try to all become the UI active element, only the topmost of them will be.
|
||||
|
||||
E.g.:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class A extends Component {
|
||||
setup() {
|
||||
useActiveElement();
|
||||
}
|
||||
}
|
||||
A.components = { B };
|
||||
A.template = xml`<div id="a"><B/></div>`;
|
||||
|
||||
class B extends Component {
|
||||
setup() {
|
||||
useActiveElement();
|
||||
}
|
||||
}
|
||||
B.template = xml`<div id="b"/>`;
|
||||
|
||||
// When A will get mounted, all its children components will get mounted first
|
||||
// So B will get mounted first and div#b will become the active element.
|
||||
// Finally A will get mounted and div#a will become the active element.
|
||||
|
||||
Example: active element management
|
||||
----------------------------------
|
||||
|
||||
Listen to active element changes
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
const ui = useService("ui");
|
||||
this.myActiveElement = ui.activeElement;
|
||||
useBus(ui.bus, "active-element-changed", (activeElement) => {
|
||||
if (activeElement !== this.myActiveElement) {
|
||||
// do some stuff, like changing my state or keeping myActiveElement in sync...
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
With ``useActiveElement`` hook
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Here is how one component could change the active element of the UI
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
useActiveElement();
|
||||
}
|
||||
}
|
||||
|
||||
With ``useActiveElement`` hook: ref delegation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Here is how one component could change the active element of the UI
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
useActiveElement("delegatedRef");
|
||||
}
|
||||
}
|
||||
MyComponent.template = owl.tags.xml`
|
||||
<div>
|
||||
<h1>My Component</h1>
|
||||
<div t-ref="delegatedRef"/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
Manually
|
||||
^^^^^^^^
|
||||
|
||||
Here is how one component could change the active element of the UI
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
this.uiService = useService("ui");
|
||||
}
|
||||
mounted() {
|
||||
const activateElement = this.el;
|
||||
this.uiService.activateElement(activateElement);
|
||||
}
|
||||
willUnmount() {
|
||||
this.uiService.deactivateElement(activateElement);
|
||||
}
|
||||
}
|
||||
|
||||
Example: block/unblock
|
||||
----------------------
|
||||
|
||||
Here is how one component can block and unblock the UI:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
class MyComponent extends Component {
|
||||
...
|
||||
ui = useService('ui');
|
||||
|
||||
...
|
||||
|
||||
someHandlerBlock() {
|
||||
// The loading screen will be displayed and block the UI.
|
||||
this.ui.block();
|
||||
}
|
||||
|
||||
someHandlerUnblock() {
|
||||
// The loading screen is no longer displayed and the UI is unblocked.
|
||||
this.ui.unblock();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
User Service
|
||||
============
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``user``
|
||||
- None
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``user`` service is a very simple service, that aims to just keep track of a
|
||||
few important values related to the current user. It simply provides an object
|
||||
with a few keys:
|
||||
|
||||
|
||||
* ``allowed_companies ({[id: number] : {id: number, name: string} })`` : the list of companies that can be
|
||||
accessed by the user. Each element is a pair ``id, name``
|
||||
* ``context (object)`` : the user main context (see below for a description)
|
||||
* ``current_company ({id: number, name: string})`` : the currently active company. It is a
|
||||
pair ``[id, name]``.
|
||||
* ``dateFormat`` : preferred format when formatting "dates"
|
||||
* ``decimalPoint`` : decimal separator
|
||||
* ``direction`` : "rtl" ("right to left") or "lrt" ("left to right")
|
||||
* ``grouping`` : ?
|
||||
* ``isAdmin (boolean)`` : if true, the user is an administrator of the current
|
||||
odoo database
|
||||
* ``lang (string)`` : a short description of the user language (such as ``en_us`` )
|
||||
* ``multiLang`` : if true, this means that several languages are installed on the database
|
||||
* ``partnerId (number)`` : the id for the partner (\ ``res.partner`` record) associated to the user
|
||||
* ``thousandsSep`` : thousands separator
|
||||
* ``timeFormat`` : preferred format when formatting "hours"
|
||||
* ``tz (string)`` : the user configured timezone (such as ``Europe/Brussels`` )
|
||||
* ``userId (number)`` : the user id (for the ``res.user`` model)
|
||||
* ``userName (string)`` : the user name (string that can be displayed)
|
||||
|
||||
User Context
|
||||
------------
|
||||
|
||||
The user context is an object that tracks a few important value. This context is
|
||||
mostly useful when talking to the server (it is added to every request).
|
||||
|
||||
Here is complete description of its content:
|
||||
|
||||
|
||||
* ``allowed_company_ids (number[])`` : the list of all ids for all available
|
||||
companies
|
||||
* ``lang (string)`` : a short description of the user language (same as above)
|
||||
* ``tz (string)`` : the user configured timezone (same as above)
|
||||
* ``uid (number)`` : the current user id (as a ``res.partner`` record). Same as the
|
||||
``userId`` value above
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
View Service
|
||||
============
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Technical name
|
||||
- Dependencies
|
||||
* - ``view_manager``
|
||||
- ``model``
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``view_manager`` service is a low level service that helps with loading view
|
||||
informations (such as the arch, the ``id`` and other view informations).
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
The ``view_manager`` service provide a single method:
|
||||
|
||||
|
||||
* ``loadView(model: string, type: ViewType, viewId?: number | false): Promise<ViewDefinition>``
|
||||
This method loads from the server the description for a view.
|
||||
|
||||
A ``ViewDefinition`` object contains the following information:
|
||||
|
||||
.. code-block::
|
||||
|
||||
- `arch (string)`
|
||||
- `type (ViewType)`
|
||||
- `viewId (number)`
|
||||
Reference in New Issue
Block a user