Keretrendszer Áttekintés¶
Bevezetés¶
Az Odoo Javascript keretrendszer a web/ kiegészítő által biztosított funkciók/építőelemek halmaza, amelyek segítenek az odoo alkalmazások böngészőben történő futtatásában. Ugyanakkor az Odoo Javascript keretrendszer egy egyoldalas alkalmazás, amelyet általában web kliens néven ismernek (elérhető a /web URL-en).
A web kliens egy egyedi osztály- és widgetrendszerrel készült alkalmazásként indult, de most áttér a natív javascript osztályok használatára, és az Owl-t használja komponensrendszerként. Ez magyarázza, miért van mindkét rendszer jelenleg használatban a kódbázisban.
Magas szintű nézőpontból a web kliens egy egyoldalas alkalmazás: nem szükséges minden alkalommal teljes oldalt kérnie a szervertől, amikor a felhasználó végrehajt egy műveletet. Ehelyett csak azt kéri, amire szüksége van, majd ennek megfelelően cseréli/frissíti az aktuális képernyőt. Emellett kezeli az URL-t, hogy szinkronban tartsa az aktuális állapottal.
A javascript keretrendszert (teljesen vagy részben) más helyzetekben is használják, például az Odoo weboldalon vagy az értékesítési ponton. Ez a referencia főként a web kliensre összpontosít.
Megjegyzés
Az Odoo ökoszisztémában gyakori, hogy a frontend és backend szavakat az odoo weboldal (nyilvános) és a web kliens szinonimájaként használják. Ez a terminológia nem összetévesztendő a böngésző-kód (frontend) és a szerver (backend) általánosabb használatával.
Megjegyzés
Ebben a dokumentációban a komponens szó mindig az új Owl komponensekre utal, míg a widget az régi Odoo widgetekre.
Megjegyzés
Minden új fejlesztést lehetőség szerint Owl-ban kell végezni!
Kódstruktúra¶
A web/static/src mappa tartalmazza az összes web/ javascript (és css és sablon) kódbázist. Itt található a legfontosabb mappák listája:
core/a legtöbb alacsony szintű funkciófields/az összes mező komponensviews/az összes javascript nézet komponens (form,list, …)search/vezérlőpult, keresősáv, keresőpanel, …webclient/a web kliens specifikus kódja: navigációs sáv, felhasználói menü, akció szolgáltatás, …
A web/static/src a gyökér mappa. Minden benne lévő egyszerűen importálható a @web előtag használatával. Például, itt van, hogyan lehet importálni a memoize függvényt, amely a web/static/src/core/utils/functions helyen található:
import { memoize } from "@web/core/utils/functions";
WebClient Architektúra¶
Ahogy fentebb említettük, a web kliens egy owl alkalmazás. Itt van egy kissé egyszerűsített változata a sablonjának:
<t t-name="web.WebClient">
<body class="o_web_client">
<NavBar/>
<ActionContainer/>
<MainComponentsContainer/>
</body>
</t>
Amint láthatjuk, alapvetően egy burkoló a navigációs sávhoz, az aktuális akcióhoz és néhány további komponenshez. Az ActionContainer egy magasabb rendű komponens, amely megjeleníti az aktuális akció vezérlőt (tehát egy kliens akciót, vagy egy specifikus nézetet az act_window típusú akciók esetében). Az akciók kezelése a munkájának nagy részét képezi: az akció szolgáltatás memóriában tartja az összes aktív akció halmazát (amely a kenyérmorzsákban van ábrázolva), és koordinálja az egyes változásokat.
Egy másik érdekes megjegyzés a MainComponentsContainer: ez egyszerűen egy komponens, amely megjeleníti az összes komponenst, amely a main_components regisztrációban van. Így tudják a rendszer más részei kiterjeszteni a web klienst.
Környezet¶
Mint egy Owl alkalmazás, az Odoo web kliens meghatározza a saját környezetét (a komponensek hozzáférhetnek ehhez a this.env használatával). Itt található egy leírás arról, hogy mit ad hozzá az Odoo a megosztott env objektumhoz:
Kulcs |
Érték |
|---|---|
|
szükséges az Owl által (tartalmazza az összes sablont) |
|
fő busz, amelyet néhány általános esemény koordinálására használnak |
|
minden telepített szolgáltatás (általában a |
|
karakterlánc. Ha nem üres, a web kliens debug mód-ban van |
|
fordítási funkció |
|
boolean. Ha igaz, a web kliens jelenleg mobil módban van (képernyő szélesség <= 767px) |
Tehát például egy szöveg fordításához egy komponensben (megjegyzés: a sablonok automatikusan lefordítódnak, így ebben az esetben nincs szükség külön intézkedésre), ezt tehetjük:
const someString = this.env._t('some text');
Megjegyzés
A környezetre való hivatkozás meglehetősen erőteljes, mert hozzáférést biztosít minden szolgáltatáshoz. Ez sok esetben hasznos: például a felhasználói menüelemek többnyire szövegként vannak meghatározva, és egy függvényként, amely az env-et veszi egyedi argumentumként. Ez elegendő az összes felhasználói menü igény kifejezésére.
Építőelemek¶
A web kliens nagy része néhány absztrakció típusból épül fel: regiszterek, szolgáltatások, komponensek és horgok.
Regiszterek¶
Regiszterek alapvetően egy egyszerű kulcs/érték párosítás, amely bizonyos típusú objektumokat tárol. Fontos részei a felhasználói felület kiterjeszthetőségének: ha egy objektum regisztrálva van, a web kliens többi része használhatja azt. Például a mező regiszter tartalmazza az összes mező komponenst (vagy widgetet), amelyeket nézetekben lehet használni.
import { Component } from "@odoo/owl";
import { registry } from "./core/registry";
class MyFieldChar extends Component {
// some code
}
registry.category("fields").add("my_field_char", MyFieldChar);
Megjegyzendő, hogy importáljuk a fő regisztert a @web/core/registry-ből, majd megnyitjuk a fields alregisztert.
Szolgáltatások¶
Szolgáltatások hosszú élettartamú kódrészek, amelyek egy funkciót biztosítanak. Komponensek (useService-el) vagy más szolgáltatások importálhatják őket. Továbbá, megadhatnak egy függőségi halmazt. Ebben az értelemben a szolgáltatások alapvetően egy DI (függőség injektálás) rendszert alkotnak. Például a notification szolgáltatás lehetőséget biztosít egy értesítés megjelenítésére, vagy az rpc szolgáltatás a megfelelő módja egy kérés végrehajtásának az Odoo szerver felé.
A következő példa egy egyszerű szolgáltatást regisztrál, amely 5 másodpercenként megjelenít egy értesítést:
import { registry } from "./core/registry";
const serviceRegistry = registry.category("services");
const myService = {
dependencies: ["notification"],
start(env, { notification }) {
let counter = 1;
setInterval(() => {
notification.add(`Tick Tock ${counter++}`);
}, 5000);
}
};
serviceRegistry.add("myService", myService);
Komponensek és Horgok¶
Komponensek és horgok az Owl komponens rendszer ötleteiből származnak. Az Odoo komponensek egyszerűen owl komponensek, amelyek a web kliens részét képezik.
Horgok egy módja a kód faktorizálásának, még akkor is, ha az életciklustól függ. Ez egy összetett/funkcionális módja egy funkció beillesztésének egy komponensbe. Ezek egyfajta mixinként is tekinthetők.
function useCurrentTime() {
const state = useState({ now: new Date() });
const update = () => state.now = new Date();
let timer;
onWillStart(() => timer = setInterval(update, 1000));
onWillUnmount(() => clearInterval(timer));
return state;
}
Környezet¶
Az Odoo javascript fontos fogalma a környezet: lehetőséget biztosít a kód számára, hogy több kontextust adjon egy függvényhíváshoz vagy egy rpc-hez, így a rendszer más részei megfelelően reagálhatnak erre az információra. Valamilyen módon ez olyan, mint egy információs csomag, amely mindenhová eljut. Hasznos bizonyos helyzetekben, például amikor az Odoo szervernek tudnia kell, hogy egy modell rpc egy adott űrlap nézetből származik, vagy egyes funkciók aktiválása/letiltása egy komponensben.
Az Odoo web kliensben két különböző környezet létezik: a felhasználói környezet és az akció környezet (tehát óvatosnak kell lennünk, amikor a környezet szót használjuk: a helyzettől függően mást jelenthet).
Megjegyzés
A környezet objektum sok esetben hasznos lehet, de óvatosnak kell lenni, hogy ne használjuk túl! Sok probléma megoldható szabványos módon a környezet módosítása nélkül.
Felhasználói kontextus¶
A felhasználói kontextus egy kis objektum, amely különféle információkat tartalmaz az aktuális felhasználóval kapcsolatban. Elérhető a user szolgáltatáson keresztül:
class MyComponent extends Component {
setup() {
const user = useService("user");
console.log(user.context);
}
}
A következő információkat tartalmazza:
Név |
Típus |
Leírás |
|---|---|---|
|
|
a felhasználó aktív vállalati azonosítóinak listája |
|
|
the user language code (such as „en_us”) |
|
|
the user current timezone (for example „Europe/Brussels”) |
Gyakorlatban az orm szolgáltatás automatikusan hozzáadja a felhasználói kontextust minden kéréséhez. Ezért általában nem szükséges közvetlenül importálni a legtöbb esetben.
Megjegyzés
Az allowed_company_ids első eleme a felhasználó fő cége.
Műveleti Kontextus¶
A ir.actions.act_window és ir.actions.client támogat egy opcionális context mezőt. Ez a mező egy char, amely egy objektumot képvisel. Amikor a megfelelő művelet betöltődik a web kliensben, ez a kontextus mező objektumként lesz kiértékelve, és átadva annak a komponensnek, amely a művelethez tartozik.
<field name="context">{'search_default_customer': 1}</field>
Sokféleképpen használható. Például a nézetek hozzáadják a műveleti kontextust minden szerverhez intézett kéréshez. Egy másik fontos felhasználás az, hogy alapértelmezés szerint aktiváljunk néhány keresési szűrőt (lásd a fenti példát).
Néha, amikor új műveleteket hajtunk végre manuálisan (tehát programozottan, javascriptben), hasznos lehet a műveleti kontextus kiterjesztése. Ezt az additional_context argumentummal lehet megtenni.
// in setup
let actionService = useService("action");
// in some event handler
actionService.doAction("addon_name.something", {
additional_context:{
default_period_id: defaultPeriodId
}
});
Ebben a példában az addon_name.something xml_id-val rendelkező művelet lesz betöltve, és annak kontextusa ki lesz terjesztve a default_period_id értékkel. Ez egy nagyon fontos felhasználási eset, amely lehetővé teszi a fejlesztők számára, hogy műveleteket kombináljanak azáltal, hogy némi információt adnak a következő művelethez.
Python Értelmező¶
Az Odoo keretrendszer egy beépített kis python értelmezőt tartalmaz. Ennek célja, hogy kis python kifejezéseket értékeljen ki. Ez fontos, mert az Odoo nézeteiben a módosítók pythonban vannak írva, de a böngészőnek kell azokat kiértékelnie.
Példa:
import { evaluateExpr } from "@web/core/py_js/py";
evaluateExpr("1 + 2*{'a': 1}.get('b', 54) + v", { v: 33 }); // returns 142
A py javascript kód 5 függvényt exportál:
- tokenize(expr)¶
- Argumentum
expr (
string()) – a tokenizálandó kifejezés
- Visszatérési érték
Token[] egy token lista
- parse(tokens)¶
- Argumentum
tokens (
Token[]()) – egy token lista
- Visszatérési érték
AST egy absztrakt szintaxisfa struktúra, amely a kifejezést reprezentálja
- parseExpr(expr)¶
- Argumentum
expr (
string()) – egy érvényes python kifejezést reprezentáló karakterlánc
- Visszatérési érték
AST egy absztrakt szintaxisfa struktúra, amely a kifejezést reprezentálja
- evaluate(ast[, context])¶
- Argumentum
ast (
AST()) – egy AST struktúra, amely egy kifejezést reprezentálcontext (
Object()) – egy objektum, amely további értékelési kontextust biztosít
- Visszatérési érték
bármilyen a kifejezés eredményértéke, a kontextus figyelembevételével
- evaluateExpr(expr[, context])¶
- Argumentum
expr (
string()) – egy érvényes python kifejezést reprezentáló karakterlánccontext (
Object()) – egy objektum, amely további értékelési kontextust biztosít
- Visszatérési érték
bármilyen a kifejezés eredményértéke, a kontextus figyelembevételével
Domainek¶
Általánosságban elmondható, hogy az Odoo-ban a domainek olyan rekordok halmazát képviselik, amelyek megfelelnek bizonyos megadott feltételeknek. Javascriptben általában vagy feltételek listájaként (vagy operátorok: |, & vagy ! prefix notációban), vagy karakterlánc kifejezésekként vannak ábrázolva. Nem szükséges, hogy normalizáltak legyenek (a & operátor szükség esetén implicit). Például:
// list of conditions
[]
[["a", "=", 3]]
[["a", "=", 1], ["b", "=", 2], ["c", "=", 3]]
["&", "&", ["a", "=", 1], ["b", "=", 2], ["c", "=", 3]]
["&", "!", ["a", "=", 1], "|", ["a", "=", 2], ["a", "=", 3]]
// string expressions
"[('some_file', '>', a)]"
"[('date','>=', (context_today() - datetime.timedelta(days=30)).strftime('%Y-%m-%d'))]"
"[('date', '!=', False)]"
A karakterlánc kifejezések erősebbek, mint a lista kifejezések: tartalmazhatnak python kifejezéseket és kiértékeletlen értékeket, amelyek egy értékelési kontextustól függenek. Azonban a karakterlánc kifejezések kezelése nehezebb.
Mivel a domainek meglehetősen fontosak a web kliensben, az Odoo biztosít egy Domain osztályt:
new Domain([["a", "=", 3]]).contains({ a: 3 }) // true
const domain = new Domain(["&", "&", ["a", "=", 1], ["b", "=", 2], ["c", "=", 3]]);
domain.contains({ a: 1, b: 2, c: 3 }); // true
domain.contains({ a: -1, b: 2, c: 3 }); // false
// next expression returns ["|", ("a", "=", 1), ("b", "<=", 3)]
Domain.or([[["a", "=", 1]], "[('b', '<=', 3)]"]).toString();
Itt található a Domain osztály leírása:
- class Domain([descr])¶
- Argumentum
descr (
string | any[] | Domain()) – egy domain leírás
- Domain.contains(record)¶
- Argumentum
record (
Object()) – egy rekord objektum
- Visszatérési érték
logikai
Igaz értéket ad vissza, ha a rekord megfelel a domain által meghatározott összes feltételnek
- Domain.toString()¶
- Visszatérési érték
karakterlánc
Visszaad egy karakterlánc leírást a domainhez
- Domain.toList([context])¶
- Argumentum
context (
Object()) – értékelési kontextus
- Visszatérési érték
bármilyen[]
Visszaad egy listaleírást a tartományhoz. Vegye figyelembe, hogy ez a metódus egy opcionális
contextobjektumot is elfogad, amelyet az összes szabad változó helyettesítésére használnak.new Domain(`[('a', '>', b)]`).toList({ b:3 }); // [['a', '>', 3]]
A Domain osztály 4 hasznos statikus metódust is biztosít a tartományok kombinálására:
// ["&", ("a", "=", 1), ("uid", "<=", uid)]
Domain.and([[["a", "=", 1]], "[('uid', '<=', uid)]"]).toString();
// ["|", ("a", "=", 1), ("uid", "<=", uid)]
Domain.or([[["a", "=", 1]], "[('uid', '<=', uid)]"]).toString();
// ["!", ("a", "=", 1)]
Domain.not([["a", "=", 1]]).toString();
// ["&", ("a", "=", 1), ("uid", "<=", uid)]
Domain.combine([[["a", "=", 1]], "[('uid', '<=', uid)]"], "AND").toString();
- static Domain.and(domains)¶
- Paraméterek
domains (string[] | any[][] | Domain[]) – tartományábrázolások listája
- Visszatérési érték
Tartomány
Visszaad egy tartományt, amely az összes tartomány metszetét képviseli.
- static Domain.or(domains)¶
- Paraméterek
domains (string[] | any[][] | Domain[]) – tartományábrázolások listája
- Visszatérési érték
Tartomány
Visszaad egy tartományt, amely az összes tartomány unióját képviseli.
- static Domain.not(domain)¶
- Paraméterek
domain (string | any[] | Domain) – egy tartományábrázolás
- Visszatérési érték
Tartomány
Visszaad egy tartományt, amely a tartomány argumentum negációját képviseli
- static Domain.combine(domains, operator)¶
- Paraméterek
domains (string[] | any[][] | Domain[]) – tartományábrázolások listája
operator ('AND' or 'OR') – egy operátor
- Visszatérési érték
Tartomány
Visszaad egy domaint, amely vagy az összes domain metszetét, vagy unióját képviseli, az operátor argumentum értékétől függően.
Busz¶
A web kliens environment objektum tartalmaz egy esemény buszt, amelynek neve bus. Célja, hogy a rendszer különböző részei megfelelően koordinálják magukat, anélkül, hogy összekapcsolódnának. Az env.bus egy owl EventBus, amelyet a globális érdeklődésre számot tartó eseményekhez kell használni.
// for example, in some service code:
env.bus.on("WEB_CLIENT_READY", null, doSomething);
Itt található az események listája, amelyek ezen a buszon kiválthatók:
Üzenet |
Adatcsomag |
Kiváltó |
|---|---|---|
|
egy mód, amely jelzi, hogy a felhasználói felület mely része frissült («current», «new» vagy «fullscreen») |
az akció menedzsernek kért akció megjelenítése megtörtént |
|
következő renderelési információ |
az akciókezelő befejezte a következő felület kiszámítását |
|
nincs |
a menüszolgáltatás aktuális alkalmazása megváltozott |
|
nincs |
az url hash megváltozott |
|
rpc azonosító |
egy rpc kérés éppen elindult |
|
rpc azonosító |
egy rpc kérés befejeződött |
|
nincs |
a web kliens fel lett szerelve |
|
nincs |
a fő nézetnek fókuszálnia kell magát |
|
nincs |
minden belső gyorsítótárat törölni kell |
|
függvények listája |
minden nézet, amely nem elkötelezett változtatásokat tartalmaz, törölje azokat, és helyezzen egy visszahívást a listába |
Böngésző Objektum¶
A javascript keretrendszer egy speciális browser objektumot is biztosít, amely hozzáférést nyújt számos böngésző API-hoz, mint például a location, localStorage vagy setTimeout. Például, így lehet használni a browser.setTimeout függvényt:
import { browser } from "@web/core/browser/browser";
// somewhere in code
browser.setTimeout(someFunction, 1000);
Ez elsősorban tesztelési célokra érdekes: minden kód, amely a böngésző objektumot használja, könnyen tesztelhető azáltal, hogy a teszt időtartamára a releváns függvényeket szimuláljuk.
A következő tartalmat tartalmazza:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Hibakeresési mód¶
Az Odoo néha egy speciális módban működhet, amelyet debug módnak neveznek. Két fő célra használják:
további információk/mezők megjelenítése bizonyos képernyőkön,
néhány további eszköz biztosítása a fejlesztők számára az Odoo felület hibakeresésének segítésére.
A debug módot egy karakterlánc írja le. Egy üres karakterlánc azt jelenti, hogy a debug mód nincs aktív állapotban. Ellenkező esetben aktív. Ha a karakterlánc tartalmazza az assets vagy tests szavakat, akkor a megfelelő specifikus al-módok aktiválódnak (lásd alább). Mindkét mód egyszerre is aktív lehet, például az assets,tests karakterlánccal.
A debug mód aktuális értéke olvasható a környezet: env.debug.
Javaslat
Ahhoz, hogy a menük, mezők vagy nézeti elemek csak hibakeresési módban jelenjenek meg, a base.group_no_one csoportot kell megcélozni:
<field name="fname" groups="base.group_no_one"/>
Lásd még
Eszközök mód¶
A debug=assets al-mód hasznos a javascript kód hibakereséséhez: aktiválás után a eszközök csomagok már nincsenek tömörítve, és forrás-térképek is generálódnak. Ez hasznos mindenféle javascript kód hibakereséséhez.
Teszt mód¶
Van egy másik al-mód, amelynek neve tests: ha engedélyezve van, a szerver a web.assets_tests csomagot injektálja az oldalba. Ez a csomag főként teszt túrákat tartalmaz (olyan túrákat, amelyek célja egy funkció tesztelése, nem pedig valami érdekes bemutatása a felhasználóknak). A tests mód így hasznos ezen túrák futtatásához.
Lásd még