Orbito - Dokumentacja modułówOrbito - Dokumentacja modułów
Wprowadzenie
Pierwsze kroki
API
Komunikacja
Widoki
Wdrożenie
Społeczność
For AI agents
Wprowadzenie
Pierwsze kroki
API
Komunikacja
Widoki
Wdrożenie
Społeczność
For AI agents
  • OrbitoViewEngine

    • Wprowadzenie
    • BaseView – Klasa bazowa
    • Zmienne (VarStore)
    • Listy i notacja .$
    • Szablony Handlebars
    • Akcje (ActionHandler)
    • Tabele danych
    • Edycja danych
    • Kontrolki wartości
    • Warianty stylistyczne
    • Komponenty i sloty
    • Pliki, kamera i schemat z serwera
  • Widoki

    • AvatarView
    • BadgeView
    • ButtonView
    • CameraView
    • CardView
    • CheckboxGroupView
    • CheckboxView
    • ComponentView
    • CssBoxView
    • DataTableView
    • DropdownView
    • DynamicListView
    • DynamicView
    • FilePickerView
    • FilePreviewView
    • FlexView
    • GridView
    • HtmlView
    • InlineEditView
    • InputView
    • ListView
    • ModalView
    • PopoverView
    • RadioGroupView
    • RowView
    • SelectView
    • SliderView
    • SlotView
    • StepperView
    • TabsView
    • TextInputView
    • TextView

Dostępne Akcje (ActionHandler)

Źródło: ActionHandler.js

Akcje definiują zachowanie widoków obsługujących zdarzenia użytkownika (np. onClick w ButtonView, TextView, BadgeView). Wszystkie akcje są wykonywane przez wspólny ActionHandler, dzięki czemu interfejs jest spójny w całym silniku.

Schemat akcji

Akcja to obiekt przypisywany do pola onClick (lub innego pola zdarzeniowego) w schemacie widoku:

action: nazwaAkcji
parametry: ...

Pole zdarzeniowe może też zawierać tablicę akcji — wykonają się po kolei.

Kiedy rozwiązywane są templatki

Konfiguracja akcji jest rozwiązywana w chwili wykonania, nie podczas budowania widoku. Templatka {{ $page.orderId }} w onClick widzi więc wartość aktualną w momencie kliknięcia, a {{ $response.id }} w onSuccess — dopiero odpowiedź serwera.

Akcje zagnieżdżone (onSuccess, onError, then, onYes, onNo, onClick toasta) czekają ze swoim rozwiązaniem do momentu, w którym faktycznie się uruchomią.

Zakres zmiennych akcji

Poza wartościami ze VarStore ($page, $global oraz dane widoków pod ich id) akcja dostaje zakres zależny od źródła wywołania:

ZmiennaDostępna w
$responseonSuccess / onError akcji callMethod
$erroronError akcji callMethod — { message, status, data }
$valueonChange kontrolki wartości
$eventonEvent, onVarChange, onKey
$argsakcja uruchomiona przez action: run
$propsakcja wewnątrz szablonu komponentu

Typowane referencje (valueFrom)

Templatki {{ }} służą do składania tekstu — Handlebars zawsze zwraca string. Tam, gdzie potrzebna jest surowa wartość z zachowanym typem (liczba, boolean, tablica, obiekt odpowiedzi), używa się referencji valueFrom:

# pole akcji
action: setVar
scope: page
key: lastResponse
valueFrom: $response.data        # cały obiekt, bez stringifikacji

# dowolna wartość w drzewie konfiguracji
params:
  orderId: { valueFrom: $page.orderId }   # liczba pozostaje liczbą
  limit: 50

Ścieżka jest zapisana w dot-notation i może zawierać placeholder indeksu .$ (valueFrom: products.$.packedQty). Gdy ścieżka nie istnieje, użyte zostaje value — pełni więc rolę wartości domyślnej.

Te same referencje działają jako operandy warunków (renderIf, condition):

renderIf:
  packedQty:
    $gte: { valueFrom: requiredQty }

openModal

Otwiera okno modalne o podanym ID.

PoleWymaganyOpis
actionTak"openModal"
targetTakID modala do otwarcia
action: openModal
target: addOrderModal

closeModal

Zamyka okno modalne o podanym ID.

PoleWymaganyOpis
actionTak"closeModal"
targetTakID modala do zamknięcia
action: closeModal
target: addOrderModal

openPopover

Otwiera popover przy elemencie wywołującym.

PoleWymaganyOpis
actionTak"openPopover"
targetTakID widoku popover do otwarcia
widthNieSzerokość popovera (np. "300px")
placementNiePozycja względem elementu wywołującego (domyślnie: "bottom")
action: openPopover
target: filterPopover
placement: bottom-start
width: 320px

closePopover

Zamyka popover o podanym ID.

PoleWymaganyOpis
actionTak"closePopover"
targetTakID widoku popover do zamknięcia
action: closePopover
target: filterPopover

emit

Emituje niestandardowe zdarzenie na magistrali zdarzeń.

PoleWymaganyOpis
actionTak"emit"
eventNieNazwa zdarzenia (domyślnie action:<viewId>)
dataNieDodatkowe dane przekazane ze zdarzeniem
action: emit
event: customEvent
data:
  key: value

Nawigacja do strony modułu:

action: emit
event: generatePage
data:
  module: core/orders
  page: details/52949

Renderowanie inline w kontenerze:

action: emit
event: generatePage
data:
  module: core/orders
  page: summary
  target: orderContainer

reload

Przeładowuje dane jednego lub wielu widoków.

PoleWymaganyOpis
actionTak"reload"
targetTakID widoku albo tablica ID
action: reload
target: ordersTable
action: reload
target: [orderDetail, shpList]

callMethod

Wywołuje metodę API modułu. Podczas wywołania emituje zdarzenia cyklu życia:

  • callMethod:preCall:<viewId> – przed wywołaniem (np. ButtonView pokazuje spinner)
  • callMethod:success:<viewId> – po sukcesie
  • callMethod:error:<viewId> – po błędzie
  • callMethod:afterCall:<viewId> – zawsze po zakończeniu (np. ButtonView chowa spinner)
PoleWymaganyOpis
actionTak"callMethod"
moduleTakŚcieżka modułu, np. "core/orders"
methodTakNazwa metody, np. "create"
paramsNieParametry metody; wspierają {{ }} oraz referencje { valueFrom }
withDataNieDane pobierane ze VarStore — lista kluczy albo wpisy { from, as }
refreshNieID widoku (lub ich tablica) do przeładowania po sukcesie
onSuccessNieAkcja (lub tablica akcji) wykonywana po sukcesie
onErrorNieAkcja (lub tablica akcji) wykonywana po błędzie
thenNieDeprecated – alias onSuccess (kompatybilność wsteczna)
action: callMethod
module: core/orders
method: update
params:
  _id: '{{ orderId }}'
  name: "Zamowienie z formularza"
withData:
  - statusInput001
  - "$page.somePageVar"
onSuccess:
  action: closeModal
  target: editOrderModal
onError:
  - action: toast
    type: alert
    content: Mamy błąd {{ $response.error }}

refresh — odświeżenie widoków po zapisie

Skrót na najczęstszą reakcję po udanym wywołaniu API. Zastępuje pisanie onSuccess z listą akcji reload:

action: callMethod
module: core/orders
method: product.update
refresh: [orderDetail, shpList]
onSuccess:
  action: closeModal
  target: editProductModal

refresh wykonuje się wyłącznie po sukcesie i przed onSuccess, więc widoki zaczynają pobierać nowe dane od razu. Nie zastępuje ogólnego onSuccess — obu można używać równocześnie.

withData — aliasowanie danych

Wpis może być zwykłym kluczem (wtedy nazwa parametru API jest równa ścieżce) albo obiektem { from, as }, który oddziela id widoku od nazwy parametru. Kropka w as buduje strukturę zagnieżdżoną:

withData:
  - statusInput001                                  # { statusInput001: ... }
  - { from: customerNameInput, as: customer.name }  # { customer: { name: ... } }
  - { from: $page.orderId, as: orderId }            # { orderId: ... }

Odpowiedź serwera w akcjach reakcji ($response / $error)

Akcje uruchamiane jako onSuccess / onError otrzymują dodatkowy zakres zmiennych dostępny w templatkach {{ }} oraz w polu valueFrom (patrz setPageVar/setGlobalVar):

ZmiennaDostępnośćZawartość
$responsesukcesbody odpowiedzi serwera
$responsebłądbody błędu z serwera (error.response.data)
$errorbłąd{ message, status, data }

Wyświetlenie treści błędu w toaście:

onError:
  - action: toast
    type: alert
    title: Błąd ({{ $error.status }})
    content: Mamy błąd {{ $response.error }}

Zapis odpowiedzi do zmiennej strony – value zwraca string (renderowany z {{ }}), a valueFrom zapisuje surową, niezstringifikowaną wartość (np. cały obiekt):

onSuccess:
  - action: setPageVar
    key: createdId
    value: '{{ $response.id }}'        # string
  - action: setPageVar
    key: lastResponse
    valueFrom: '$response'             # cały obiekt odpowiedzi

confirm

Wyświetla okno dialogowe potwierdzenia (ConfirmDialog) przed wykonaniem właściwej akcji.

PoleWymaganyOpis
actionTak"confirm"
typeNieStyl okna: alert, success, neutral (domyślnie: neutral)
titleNieTytuł okna
descriptionNieOpis (obsługuje HTML)
yesLabelNieTekst przycisku potwierdzenia (domyślnie: Tak)
noLabelNieTekst przycisku anulowania (domyślnie: Nie)
onYesNieAkcja wykonywana po kliknięciu Tak
onNoNieAkcja wykonywana po kliknięciu Nie / Escape / X
action: confirm
type: alert
title: Usunąć zamówienie?
description: Operacja jest nieodwracalna.
yesLabel: Usuń
noLabel: Anuluj
onYes:
  action: callMethod
  module: core/orders
  method: delete
  params:
    _id: '{{ orderId }}'

toast

Wyświetla niemodalne powiadomienie Toast (Tabler / Bootstrap 5) w prawym dolnym rogu ekranu.

PoleWymaganyOpis
actionTak"toast"
typeNieWariant kolorystyczny: neutral (domyślnie), success, alert
titleNieTytuł toasta
contentNieTreść toasta (obsługuje HTML)
buttonLabelNieEtykieta opcjonalnego przycisku akcji
onClickNieAkcja wykonywana po kliknięciu przycisku (wymagane buttonLabel)
delayNieCzas autohide w ms (domyślnie 5000; 0 = bez autohide)

Prosty toast informacyjny:

action: toast
title: Info
content: Operacja zakończona.

Toast z wariantem success:

action: toast
type: success
title: Zapisano
content: Dane zostały zapisane.

Toast z wariantem alert:

action: toast
type: alert
title: Błąd
content: Coś poszło nie tak.

Toast z przyciskiem akcji:

action: toast
type: success
title: Zamówienie utworzone
content: Zamówienie #1234 zostało dodane.
buttonLabel: Zobacz
onClick:
  action: emit
  event: generatePage
  data:
    module: core/orders
    page: details/{{ orderId }}

setVar

Ustawia zmienną w wybranym zakresie VarStore. Jedna akcja dla wszystkich trzech zakresów.

PoleWymaganyOpis
actionTak"setVar"
scopeNieview / page / global (domyślnie page)
keyTakKlucz zmiennej
valueNie*Wartość do zapisania (wspiera {{ }})
valueFromNie*Ścieżka do surowej wartości — zachowuje typ (patrz „Typowane referencje")

* wymagane jest podanie value albo valueFrom.

ZakresTrwałośćZdarzenie
viewdo zmiany strony (bez localStorage)viewVar:changed:<key>
pagelocalStorage pod kluczem stronypageVar:changed:<key>
globallocalStorage, wspólny dla stronglobalVar:changed:<key>

Zakres view jest właściwym miejscem na stan UI — tryb edycji, rozwinięty panel, zaznaczony wiersz. Taki stan nie powinien przeżywać przeładowania strony, więc nie należy trzymać go w page. Zmienna jest widoczna w templatkach pod swoim kluczem ({{ editingCustomer }}), tak samo jak dane widoku — dlatego klucz nie może kolidować z id istniejącego widoku.

action: setVar
scope: view
key: editingCustomer
value: true

Nasłuch zmiany:

onVarChange:
  - scope: view
    key: editingCustomer
    action: { action: reload, target: customerCard }

arrayPush / arrayRemove / arraySet

Edycja kolekcji trzymanej w zmiennej — pozycji dokumentu, listy załączników, koszyka. Adres kolekcji podaje się tak samo jak w setVar (scope + key), a jeśli tablica leży wewnątrz zmiennej — dodatkowo path:

action: arrayPush
scope: view       # view | page | global (domyślnie page)
key: docItems     # zmienna
path: lines.items # opcjonalnie — tablica wewnątrz zmiennej

Wszystkie trzy akcje zapisują kopię (nowa tablica, nowy obiekt elementu), więc widoki i porównania widzą zmianę, a dane z poprzedniego stanu nie zostają po cichu zmutowane. Błąd (brak key, nieznany scope, zmienna nie jest tablicą, indeks poza zakresem) kończy się komunikatem w konsoli i niewykonaniem akcji.

arrayPush

PoleWymaganyOpis
actionTak"arrayPush"
scope / key / path—Adres kolekcji (jak wyżej)
valueNie*Dodawany element (wspiera {{ }}, może być obiektem)
valueFromNie*Ścieżka do surowej wartości — zachowuje typ
atNiePozycja wstawienia (domyślnie koniec)

* wymagane jest podanie value albo valueFrom.

action: arrayPush
scope: view
key: docItems
value:
  name: ''
  qty: 1
  vat: '23'

arrayRemove

PoleWymaganyOpis
actionTak"arrayRemove"
scope / key / path—Adres kolekcji
indexTakIndeks usuwanej pozycji
action: arrayRemove
scope: view
key: docItems
index: '{{ $ }}'     # indeks bieżącego wiersza listy

arraySet

PoleWymaganyOpis
actionTak"arraySet"
scope / key / path—Adres kolekcji
indexTakIndeks zmienianej pozycji
fieldNiePole pozycji (z kropką: customer.name). Bez niego podmieniany jest cały element
valueNie*Nowa wartość (wspiera {{ }})
valueFromNie*Ścieżka do surowej wartości — zachowuje typ
rerenderNietrue wymusza pełne przeładowanie listy (domyślnie false)

* wymagane jest podanie value albo valueFrom.

index przyjmuje liczbę albo string liczbowy — w wierszu listy pisze się index: '{{ $ }}', a Handlebars zawsze zwraca tekst.

Zdarzenia: dlaczego arraySet zapisuje „cicho”

AkcjaZdarzenieKto reaguje
arrayPush, arrayRemove<zakres>Var:changed:<key>wszyscy — listvar, datatable, text, warunki
arraySet (domyślnie)<zakres>Var:itemChanged:<key>wyłącznie widoki text
arraySet z rerender: true<zakres>Var:changed:<key>wszyscy

Dodanie i usunięcie pozycji zmienia liczbę wierszy, więc lista musi się przebudować. Zmiana wartości pozycji — nie: przebudowa listy niszczy element DOM inputa, w którym użytkownik właśnie pisze (razem z fokusem i pozycją kursora). Dlatego arraySet emituje osobne zdarzenie itemChanged, które listvar i datatable ignorują, a widoki text — nie, więc kwoty i sumy przeliczają się na bieżąco.

Konsekwencja dla autora schematu: po arraySet bez rerender: true wiersze listy nie przeliczą niczego poza widokami text. Jeśli wiersz ma zmienić wygląd, użyj classIf (przelicza się z warunków), a nie renderIf czy variantIf zależnych od edytowanej kolekcji — te przebudowują zawartość i zabierają fokus.

Przykład: edytowalna lista pozycji

type: flex
onLoad:
  action: setVar
  scope: view
  key: docItems
  value:
    - { name: 'Usługa', qty: 1, price: 100 }
childs:
  - type: listvar
    id: docItemsList
    varPath: docItems
    template:
      type: flex
      childs:
        - type: input
          id: docQty.$
          inputType: number
          value: '{{ docItems.$.qty }}'
          debounce: 200
          onChange:
            action: arraySet
            scope: view
            key: docItems
            index: '{{ $ }}'
            field: qty
            valueFrom: $value
        - type: text
          content: '{{ money (mul docItems.$.qty docItems.$.price) }}'
        - type: button
          label: Usuń
          onClick:
            action: arrayRemove
            scope: view
            key: docItems
            index: '{{ $ }}'
  - type: button
    label: Dodaj pozycję
    onClick:
      action: arrayPush
      scope: view
      key: docItems
      value: { name: '', qty: 1, price: 0 }
  - type: text
    content: 'Razem: {{ money (sum docItems "price") }}'

setPageVar / setGlobalVar

Aliasy kompatybilności wstecznej — działają dokładnie jak setVar z scope: page oraz scope: global. W nowych schematach używaj setVar.

action: setPageVar
key: activeTab
value: orders

setValue

Ustawia wartość kontrolki przez jej publiczne API (setValue z ValueView), bez sięgania do wewnętrznego DOM-u widoku. Zastępuje ukryte inputy-proxy, przez które schemat przemycał wartości do formularza.

PoleWymaganyOpis
actionTak"setValue"
targetTakid kontrolki wartości
valueNie*Wartość do ustawienia (wspiera {{ }})
valueFromNie*Ścieżka do surowej wartości — zachowuje typ
emitChangeNieCzy uruchomić onChange kontrolki (domyślnie false)

* wymagane jest podanie value albo valueFrom.

Wartość trafia równocześnie do kontrolki i do VarStore. Wartość spoza dozwolonego zbioru (nieistniejąca opcja, poza zakresem suwaka) jest odrzucana — kontrolka wraca do stanu, który potrafi zaprezentować.

action: setValue
target: customerName
valueFrom: $response.customer.name
emitChange: false

run i actionDefinitions

Uruchamia nazwaną akcję zadeklarowaną w actionDefinitions. Pozwala zdefiniować akcję raz i wywołać ją z wielu miejsc — zamiast kopiować konfigurację albo klikać ukryty przycisk przez JS.

PoleWymaganyOpis
actionTak"run"
nameTakNazwa akcji z actionDefinitions
argsNieArgumenty widoczne w definicji jako $args

actionDefinitions deklaruje się w schemacie strony, w dowolnym widoku-kontenerze albo w definicji komponentu. Wyszukiwanie idzie od widoku wywołującego w górę drzewa — najbliższy komponent przesłania definicję strony.

args są rozwiązywane w kontekście widoku wywołującego (widzą .$ bieżącego wiersza listy oraz $props), a wewnątrz definicji dostępne są jako $args.

actionDefinitions:
  saveProduct:
    action: callMethod
    module: core/orders
    method: product.update
    params:
      productIndex: { valueFrom: $args.productIndex }
    onSuccess:
      action: reload
      target: productsList

type: listvar
varPath: products
template:
  type: button
  label: Zapisz
  onClick:
    action: run
    name: saveProduct
    args:
      productIndex: '{{ $ }}'

Nazwana akcja może wywołać kolejną. Cykl (a → b → a) oraz przekroczenie maksymalnego zagnieżdżenia są przerywane z błędem w konsoli, a nie zapętlają aplikacji. Nieznana nazwa również kończy się czytelnym błędem.


navigate

Przechodzi do strony modułu. Zastępuje techniczne action: emit, event: generatePage — schemat opisuje dokąd chce przejść, a host silnika decyduje jak (router aplikacji, render w miejscu).

PoleWymaganyOpis
actionTak"navigate"
moduleTakKod modułu, np. "core/orders", albo "core" dla strony rdzenia
pageTakŚcieżka strony w module, np. "details/123"; dla module: core ścieżka routera rdzenia
paramsNieParametry zapytania
targetNieID widoku — strona renderuje się w nim zamiast zmieniać adres
action: navigate
module: core/orders
page: details/{{ ordersTable.$._id }}

Aplikacja hosta może podpiąć własny router zamiast domyślnego zdarzenia:

import { setNavigationHandler } from '@/viewengine';

setNavigationHandler(({ module, page, params }) => router.push(buildUrl(module, page, params)));

Strona rdzenia (module: core)

Z module: core akcja prowadzi na stronę rdzenia, a nie modułu: page jest wtedy ścieżką routera frontu (np. settings/automation-runs), a params trafiają do query adresu. Poniższy przycisk otwiera historię biegów automatyzacji dotyczących zamówienia:

- type: button
  icon: settings-automation
  variant: secondary
  outline: true
  title: Automatyzacje
  onClick:
    - action: navigate
      module: core
      page: settings/automation-runs
      params:
        eventValue: '{{ $page.urlParams.orderId }}'

redirect

Przekierowuje bieżącą kartę na zewnętrzny adres, typowo na stronę zgody OAuth dostawcy, której adres buduje metoda modułu (zob. OAuth).

PoleWymaganyOpis
actionTak"redirect"
urlTakBezwzględny adres http:// albo https:// (templatka albo { valueFrom })
action: callMethod
method: oauth.begin
onSuccess:
  action: redirect
  url: { valueFrom: $response.0.url }

Adres spoza http(s) (javascript:, data:, ścieżka względna) jest odrzucany z błędem w konsoli. Templatka {{ }} escapuje & i =, więc adres z parametrami zapytania podaje się referencją valueFrom. Do nawigacji między stronami Orbito służy navigate.


focus / selectText

Ustawia fokus na kontrolce albo zaznacza jej treść — przez publiczne API widoku, bez sięgania do jego wewnętrznego DOM-u. Potrzebne przy edycji inline: po włączeniu trybu edycji kursor ma od razu stać w polu.

PoleWymaganyOpis
actionTak"focus" albo "selectText"
targetNieID widoku; bez niego akcja działa na widoku wywołującym
onClick:
  - action: setVar
    scope: view
    key: editingCustomer
    value: true
  - action: focus
    target: customerNameInput

copyToClipboard

Kopiuje wartość do schowka.

PoleWymaganyOpis
actionTak"copyToClipboard"
valueNie*Wartość do skopiowania (wspiera {{ }})
valueFromNie*Ścieżka do surowej wartości — zachowuje typ
feedbackNietoast (domyślnie), icon albo none
successMessageNieTreść potwierdzenia (domyślnie „Skopiowano do schowka")
errorMessageNieTreść komunikatu błędu

* wymagane jest podanie value albo valueFrom.

feedback: icon zamienia ikonę widoku wywołującego na „ptaszek" i przywraca ją po chwili; gdy widok nie ma ikony, akcja wraca do potwierdzenia toastem.

type: button
icon: copy
onClick:
  action: copyToClipboard
  valueFrom: $page.orderNumber
  feedback: icon

Schowek bywa niedostępny — przeglądarka udostępnia go wyłącznie pod HTTPS (lub na localhost), a użytkownik może odmówić uprawnienia. Akcja nie przerywa wtedy działania strony: pokazuje komunikat błędu i zapisuje powód w konsoli.


downloadFile / openFile

Pobiera plik na dysk albo otwiera go w nowej karcie.

PoleWymaganyOpis
actionTak"downloadFile" albo "openFile"
contentBase64Nie*Treść pliku w base64 (typowo z odpowiedzi API)
contentNie*Treść tekstowa (CSV, JSON, HTML)
urlNie*Gotowy adres pliku
value / valueFromNie*Skrót — źródło wskazuje pole source
sourceNiebase64 (domyślnie), text albo url — dotyczy value/valueFrom
filenameNieNazwa zapisywanego pliku (downloadFile)
mimeTypeNieTyp MIME, np. application/pdf

* wymagane jest wskazanie dokładnie jednego źródła pliku.

action: callMethod
module: core/orders
method: invoice.render
withData: [orderId]
onSuccess:
  action: downloadFile
  valueFrom: $response.pdfBase64
  filename: 'faktura-{{ $page.orderNumber }}.pdf'
  mimeType: application/pdf

Tymczasowy adres pliku jest zwalniany automatycznie. openFile otwiera kartę bez dostępu do okna źródłowego, a adresy o wykonywalnym schemacie (javascript:) są odrzucane — url bywa budowany z danych zwróconych przez backend.

Ostatnio zaktualizowano:: 6.10.2026, 10:19
Contributors: Wiktor Koźmiński, Claude Fable 5.1
Prev
Szablony Handlebars
Next
Tabele danych