Pages
Moduł Pages pozwala modułowi udostępniać własne widoki (ekrany UI) w panelu Orbito. Moduł rejestruje gotowe, deklaratywne widoki OVE, a platforma zapisuje je w swojej bazie (per firma) i sama serwuje frontendowi — kontener modułu nie musi wstawać przy każdym wejściu na stronę.
const { Pages } = require('@orbito/api-lib');
Nowy model rejestracji
Widoki rejestruje się teraz z góry przez Pages.registerPages — moduł zgłasza całą treść widoku przy starcie. Wcześniejsze Pages.registerPage(path, handler) (generowanie treści na żądanie) jest wycofywane.
Pages.registerPages
Rejestruje komplet widoków modułu. Widoki bywają długie (nierzadko kilkaset linii), dlatego trzyma się je w osobnych plikach, a w kodzie podaje tylko ścieżkę.
Pages.registerPages(pages)
| Parametr | Typ | Opis |
|---|---|---|
pages | object | Mapa pagePath → definicja widoku |
Kluczem jest pagePath — ścieżka widoku w obrębie modułu (np. /list, /order/:orderId). Pełny URL w panelu powstaje z kodu modułu i tej ścieżki.
Definicja pojedynczego widoku:
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
name | string | ✔ | Przyjazna nazwa strony pokazywana w nawigacji (np. „Lista zamówień") |
view | string | ✔ | Ścieżka do pliku z treścią widoku. Bezwzględna lub względna do katalogu roboczego modułu (process.cwd()). Format wnioskowany z rozszerzenia: .yaml/.yml → YAML, .json → JSON. Plik jest wczytywany przy rejestracji |
moduleDependencies | object | Mapa zależności modułowych, np. { "core/orders": "^1.0.2" } | |
placement | object | Umiejscowienie automatycznego linku do strony w panelu — górny pasek albo menu ustawień (od SDK 3.2.0). Bez tego pola strona działa, ale nie dostaje linku. Patrz Linki do stron w panelu |
Przykład rejestracji w index.js:
const { Pages } = require('@orbito/api-lib');
Pages.registerPages({
'/list': {
name: 'Lista zamówień',
view: 'pages/orders-list.yaml',
moduleDependencies: { 'core/orders': '^1.0.0' },
placement: { location: 'navbar', icon: 'checkup-list', order: 10 }
},
'/order/:orderId': {
name: 'Szczegóły zamówienia',
view: 'pages/order-details.yaml'
}
});
Sugerowana struktura projektu modułu:
my-module/
├── index.js
└── pages/
├── orders-list.yaml
└── order-details.yaml
Plik widoku
Plik zawiera drzewo widoku OVE — deklaratywny opis UI. Treść z ciała żądania i parametry ścieżki są dostępne w szablonie przez scope $page (Handlebars), więc nie potrzebujesz handlera po stronie modułu do wyrenderowania strony.
pages/orders-list.yaml:
type: card
title: Zamówienia
content:
type: datatable
dataSource:
method: listOrders # metoda modułu (Core.registerMethod)
columns:
- { key: number, title: Numer }
- { key: status, title: Status }
Ścieżka z parametrami (/order/:orderId) — wartość parametru czytasz w szablonie ze scope $page:
type: card
title: Zamówienie {{ $page.orderId }}
content:
type: dynamic
dataSource:
method: getOrder
params: { orderId: '{{ $page.orderId }}' }
Pełną składnię widoków opisuje sekcja Widoki.
Linki do stron w panelu (placement)
Sama rejestracja widoku sprawia, że strona istnieje pod swoim adresem — ale nie mówi jeszcze, gdzie użytkownik ma ją znaleźć. Bez pola placement strona nie dostaje żadnego linku w panelu; trafi na nią tylko ten, kto zna adres, przejdzie z innego widoku albo doda zakładkę ręcznie w Ustawienia → Nawigacja.
Pole placement (od SDK 3.2.0) pozwala modułowi zadeklarować link samodzielnie — w górnym pasku nawigacji albo w menu ustawień:
Pages.registerPages({
'/list': {
name: 'Lista zamówień',
view: 'pages/orders-list.yaml',
placement: { location: 'navbar', icon: 'checkup-list', order: 10 }
},
'/statuses': {
name: 'Konfiguracja statusów',
view: 'pages/statuses.yaml',
placement: { location: 'settings', section: 'orders', icon: 'adjustments' }
}
});
Pola placement:
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
location | 'navbar' | 'settings' | ✔ | Gdzie ma się pojawić link: górny pasek nawigacji czy menu ustawień |
section | string | Tylko dla settings — klucz sekcji menu ustawień, do której trafi link (patrz registerSettingsSections). Brak = link na pierwszym poziomie menu | |
icon | string | Nazwa ikony Tabler bez prefiksu ti-, np. 'truck', 'adjustments' | |
order | number | Kolejność linku (rosnąco). Bez order link ląduje na końcu, a linki bez kolejności sortują się alfabetycznie |
Walidacja przy rejestracji
Błędny placement (nieznane location, section przy location: 'navbar', klucz sekcji spoza [a-z0-9_-]) powoduje wyjątek z registerPages — cały zestaw stron nie zostanie zgłoszony. Błąd zobaczysz w logach kontenera od razu przy starcie modułu.
Link w górnym pasku (navbar)
Pages.registerPages({
'/list': {
name: 'Przesyłki',
view: 'pages/shipments.yaml',
placement: { location: 'navbar', icon: 'truck', order: 20 }
}
});
Zakładki modułów doklejane są za zakładkami skonfigurowanymi przez firmę i sortowane po order. Firma zachowuje kontrolę: w Ustawienia → Nawigacja administrator może zakładkę modułu ukryć albo wstawić ją we własnej kolejności — Twoja deklaracja jest propozycją domyślną, nie ustawieniem twardym.
Navbar to miejsce na pracę codzienną
W górnym pasku umieszczaj ekrany, z których użytkownik korzysta na co dzień (lista przesyłek, kolejka zamówień). Ekrany konfiguracyjne kieruj do settings — pasek nawigacji jest wspólny dla wszystkich modułów i szybko się zapełnia.
Link w menu ustawień (settings)
Pages.registerPages({
'/statuses': {
name: 'Mapowanie statusów',
view: 'pages/statuses.yaml',
placement: { location: 'settings', icon: 'adjustments' }
}
});
Strona zostaje osadzona w panelu ustawień (/settings/p/...), więc użytkownik nie traci kontekstu — menu ustawień zostaje na swoim miejscu. Bez pola section link pojawia się na pierwszym poziomie menu; z section trafia do zwijanej sekcji grupującej.
To nie to samo co ekran konfiguracji modułu
Deklaratywny ekran ustawień z formularzami i walidacją dostajesz „za darmo" przez Config.registerConfigBlocks. placement: { location: 'settings' } służy do ekranów, które robią coś więcej niż formularz — mapowania, tabele, kreatory, podgląd stanu integracji.
Pages.registerSettingsSections
Sekcja to zwijana grupa w menu ustawień — pozwala zebrać kilka stron modułu (albo kilku modułów) pod jedną nazwą zamiast rozsypywać je po pierwszym poziomie menu.
Pages.registerSettingsSections(key, name, opts?)
| Parametr | Typ | Wymagane | Opis |
|---|---|---|---|
key | string | ✔ | Klucz (slug) sekcji: [a-z0-9_-], zaczyna się od litery lub cyfry, normalizowany do małych liter. To on jest tożsamością sekcji — strony wskazują go w placement.section |
name | string | object | ✔ | Nazwa wyświetlana: string albo mapa językowa, np. { pl: 'Zamówienia', en: 'Orders' } |
opts.icon | string | Ikona Tabler sekcji (bez prefiksu ti-) | |
opts.order | number | Kolejność sekcji w menu (rosnąco); bez niej sekcja ląduje na końcu, alfabetycznie |
const { Pages } = require('@orbito/api-lib');
await Pages.registerSettingsSections('orders', { pl: 'Zamówienia', en: 'Orders' }, {
icon: 'shopping-cart',
order: 10
});
Pages.registerPages({
'/statuses': {
name: 'Mapowanie statusów',
view: 'pages/statuses.yaml',
placement: { location: 'settings', section: 'orders', icon: 'adjustments' }
},
'/carriers': {
name: 'Przewoźnicy',
view: 'pages/carriers.yaml',
placement: { location: 'settings', section: 'orders', icon: 'truck', order: 20 }
}
});
Efekt w menu ustawień:
Ustawienia
└── Zamówienia (sekcja, ikona shopping-cart)
├── Mapowanie statusów
└── Przewoźnicy
Metoda wywołuje się raz na sekcję; kolejne wywołania dokładają sekcje i re-wysyłają pełny zestaw. Rejestracja jest, tak jak przy stronach, replace-setem — sekcja, której moduł przestał deklarować, znika, a po reconnect zestaw wysyłany jest automatycznie.
Wspólna sekcja kilku modułów
Klucz sekcji jest niezależny od języka i globalny w obrębie firmy — dwa moduły rejestrujące 'orders' trafią do tej samej sekcji menu, a ich strony pojawią się obok siebie. Dzięki temu użytkownik ma jedno miejsce „Zamówienia" zamiast osobnej pozycji per moduł. Nazwy i ikony z wielu rejestracji są scalane (brakujące metadane uzupełnia pierwsza rejestracja, która je podała).
Sytuacje brzegowe, o które nie musisz się martwić:
- sekcja bez stron nie jest renderowana — możesz zarejestrować ją zawczasu;
- strona wskazująca niezarejestrowany klucz nie znika z menu — panel pokaże sekcję zastępczą nazwaną kluczem (np.
orders→ „Orders"). Zawsze warto jednak zarejestrować sekcję, żeby dostać czytelną nazwę i ikonę.
Linki do stron — uwagi praktyczne
Nie nadawaj placement stronom z parametrami w ścieżce
Link do /order/:orderId prowadziłby do dosłownego :orderId — panel nie ma skąd wziąć wartości parametru. Strony parametryczne otwiera się z innego widoku (np. akcją generatePage z listy — patrz Action Handler), a placement rezerwuj dla stron wejściowych.
Dostęp. Link dziedziczy ustawienia dostępu strony — użytkownik spoza whitelisty (allowedUsers, ustawianej przez właściciela firmy) nie zobaczy ani strony, ani jej linku.
Wiele instalacji tego samego modułu. Gdy firma ma więcej niż jedną instancję modułu, panel sam dopisuje do etykiety nazwę instancji (np. „Przesyłki (Sklep PL)"), a link zawiera wskazanie instancji. Ten sam placement w każdej instancji jest więc bezpieczny — nie trzeba różnicować nazw w kodzie.
Wycofanie linku. placement jest częścią zestawu wysyłanego przy każdej rejestracji, więc usunięcie pola w nowej wersji modułu usuwa link przy pierwszym połączeniu po aktualizacji (strona zostaje).
Aktualizacja treści i wycofywanie widoków
Cały zestaw wysyłany jest jednorazowo przy każdym połączeniu modułu, a platforma robi replace-set:
- treść widoków jest nadpisywana — nowa wersja modułu może zmienić dowolny widok, wystarczy zaktualizować plik;
- widoki, których moduł przestał deklarować (np. usunięte w nowej wersji), platforma usuwa;
- rejestracja jest ponawiana automatycznie po każdym reconnect.
Ustawienia dostępu należą do firmy
Nadpisywana jest wyłącznie treść widoku. Whitelista dostępu (allowedUsers), którą właściciel firmy ustawia w panelu, jest własnością firmy i przy aktualizacji modułu pozostaje nietknięta.
Dostęp do stron
Domyślnie widok modułu jest dostępny dla wszystkich użytkowników firmy. Właściciel/administrator firmy może w panelu ograniczyć dostęp do wybranej strony do konkretnych użytkowników — to ustawienie firmy, moduł na nie nie wpływa.
Cykl życia: wyłączenie vs odinstalowanie
| Operacja | Co się dzieje z widokami |
|---|---|
| Wyłączenie modułu (disable) | Widoki pozostają w bazie (podobnie jak konfiguracja). Po ponownym włączeniu i połączeniu modułu treść jest odświeżana, a ustawienia dostępu zachowane |
| Odinstalowanie modułu z firmy | Widoki modułu tej firmy są trwale usuwane |
Pages.registerPage (wycofane)
Metoda wycofana
Pages.registerPage(path, title, controller) należy do starego modelu, w którym platforma pobierała treść strony z żywego modułu na żądanie (getPage). Została zastąpiona przez registerPages i jest utrzymywana wyłącznie dla kompatybilności wstecznej — w nowych modułach jej nie używaj.
Migracja jest prosta — zamiast zwracać template z handlera, przenieś jego treść do pliku widoku i zarejestruj ścieżką:
// PRZED (wycofane) — treść generowana w handlerze
Pages.registerPage('/list', 'Lista zamówień', async (body, params) => ({
type: 'ove',
template: { type: 'card', title: 'Zamówienia', /* ... */ }
}));
// PO — treść w pliku, rejestracja z góry
Pages.registerPages({
'/list': { name: 'Lista zamówień', view: 'pages/orders-list.yaml' }
});
Dane, które handler dobierał do wyrenderowania strony, w nowym modelu dostarczają metody modułu wskazane w widoku przez dataSource (patrz Widoki oraz Core.registerMethod).
