# Eximee Low-Code Platform

> **Eximee Low-Code Platform** to platforma typu low-code klasy **enterprise** zaprojektowana z myślą o specyfice sektora bankowego.

### **Cel i idea platformy**

Świat bankowości rozwija się w tempie, którego klasyczne procesy IT często nie są w stanie dotrzymać. Tworzenie nowych produktów, wdrażanie zmian regulacyjnych czy dostosowanie doświadczeń klienta do kanałów cyfrowych wymaga coraz większej elastyczności.\
**Eximee Low-Code Platform** powstała właśnie po to - by skrócić czas dostarczania rozwiązań, zredukować zależność od zespołów programistycznych i zapewnić pełną kontrolę nad cyklem życia aplikacji biznesowych.

Platforma udostępnia narzędzia, dzięki którym zespoły produktowe, analitycy i low-code developerzy mogą samodzielnie tworzyć, rozwijać i utrzymywać aplikacje - w sposób graficzny i bez pisania kodu.

{% embed url="<https://youtu.be/4F__Tdyvrtc?si=alp5_xanaO1YhyUl>" %}

### **Dlaczego low-code dla bankowości**

Rozwiązania tworzone na Eximee spełniają wszystkie wymogi środowisk bankowych:

* są zgodne z wymogami bezpieczeństwa i audytu,
* wspierają architekturę omnichannel - jeden proces może działać w bankowości internetowej, mobilnej i w oddziale,
* integrują się z istniejącymi systemami banku poprzez komponenty integracyjne i API,
* uwzględniają standardy dostępności WCAG oraz wymogi regulacyjne.

Dzięki temu Eximee pozwala bankom dostarczać **spójne i zgodne z regulacjami usługi cyfrowe**, bez konieczności budowania ich od podstaw.

### **Jakie problemy rozwiązuje Eximee**

Platforma powstała jako odpowiedź na najczęstsze wyzwania projektów bankowych:

* długie cykle wytwarzania i testowania oprogramowania,
* rozproszenie procesów w różnych kanałach,
* wysokie koszty utrzymania wielu równoległych aplikacji,
* brak narzędzi umożliwiających szybkie reagowanie na potrzeby biznesu.

Dzięki elastycznej architekturze, wspólnym komponentom i graficznym edytorom procesów Eximee pozwala **zredukować czas wdrożenia nowych rozwiązań nawet o kilkadziesiąt procent**.

### Obszary zastosowania

Platforma Eximee znajduje zastosowanie przede wszystkim w sektorze bankowym, wspierając różnorodne procesy biznesowe zarówno od strony klienta (*front-office*), jak i wewnątrz organizacji (*back-office*). Główne obszary, w których Eximee Low-Code Platform jest obecnie wykorzystywana w bankach:

* Cyfrowy onboarding i KYC,
* Sprzedaż produktów bankowych,
* Bankowość samoobsługowa i obsługa posprzedażowa,
* Procesy wewnętrzne i zgodność z regulacjami (back-office),
* Narzędzia wspierające pracę pracowników banku,
* Ankiety i badania satysfakcji (NPS, CES, CSAT),
* Projekty specjalne i integracja międzyinstytucjonalna.

Więcej na ten temat znajduje się w rozdziale [Obszary zastosowania Eximee Low-Code Platform.](/wprowadzenie/obszary-zastosowania)


# Wprowadzenie

##


# Architektura platformy

> Eximee Low-Code Platform opiera się na trzech wzajemnie uzupełniających się filarach:\
> **modułach wykonawczych**, **modułach integracyjnych** oraz **narzędziach low-code**.\
> Razem tworzą środowisko do tworzenia, uruchamiania i rozwijania aplikacji biznesowych w instytucjach finansowych.

<figure><img src="/files/XputqB3vbRcIpXUOig98" alt=""><figcaption></figcaption></figure>

## Moduły wykonawcze (Executive modules)

Moduły wykonawcze stanowią środowisko uruchomieniowe dla aplikacji budowanych w Eximee. To one odpowiadają za działanie formularzy, procesów, ekranów użytkownika i obsługę zdarzeń w czasie rzeczywistym.

**Zakres odpowiedzialności:**

* wyświetlanie formularzy i ekranów (w kanałach: web, mobile, oddział),
* uruchamianie procesów BPMN (workflow klienta lub pracownika),
* zarządzanie zadaniami użytkowników (np. poprzez Eximee Dashboard),
* obsługa dokumentów, generowanie i prezentacja wydruków,
* autoryzacja, kontrola dostępu i audyt działań użytkowników,
* wysyłanie powiadomień (e-mail, SMS),
* zapewnienie dostępności zgodnie ze standardem WCAG.

**Cechy wyróżniające:**

* możliwość osadzenia formularzy w różnych kanałach bez potrzeby ich dublowania,
* spójność wizualna z aplikacjami bankowymi (dostosowanie brandingowe),
* pełna obsługa kontekstu użytkownika i jego sesji,
* gotowość do pracy w środowisku wysokiej dostępności (HA).

***

## Moduły integracyjne

Ten filar odpowiada za komunikację aplikacji Eximee z systemami bankowymi i zewnętrznymi usługami. Umożliwia łatwą integrację z rejestrami publicznymi, usługami scoringowymi, archiwami dokumentów i wieloma innymi źródłami danych.

**Zakres integracji:**

* wywoływanie usług REST/SOAP,
* odczyt i zapis danych w systemach zewnętrznych (np. CRM, ESB, core banking),
* zasilanie formularzy danymi z rejestrów (np. CEIDG, PESEL, BIK),
* obsługa podpisu elektronicznego, archiwizacji, kolejek komunikatów,
* wysyłka powiadomień przez zewnętrznych brokerów.

**Sposób działania:**

* integracje realizowane w trybie synchronicznym i asynchronicznym,
* konfiguracja konektorów i aliasów w trybie low-code,
* możliwość reużycia raz zdefiniowanych integracji w wielu aplikacjach,
* zarządzanie dostępem do zasobów z poziomu narzędzi projektowych.

**Korzyści:**

* brak potrzeby tworzenia dedykowanych mikrousług do każdego połączenia,
* skrócenie czasu integracji z tygodni do dni,
* ustandaryzowany sposób definiowania i testowania usług.

## Narzędzia low-code (Eximee Designer)

Sercem pracy na platformie jest Eximee Designer – graficzne środowisko służące do projektowania aplikacji biznesowych. Umożliwia tworzenie formularzy, procesów, modelu danych i integracji bez konieczności pisania kodu.

**Funkcje Eximee Designer:**

* budowanie formularzy metodą „przeciągnij i upuść” (drag & drop),
* modelowanie procesów w notacji BPMN 2.0,
* definiowanie modelu danych i słowników,
* tworzenie skryptów (walidatorów, obliczeń, automatyzacji),
* konfiguracja usług i providerów danych,
* podgląd, testowanie i wersjonowanie aplikacji.

**Cechy środowiska:**

* pełna integracja z mechanizmami uruchomieniowymi i integracyjnymi,
* wersjonowanie aplikacji i changelog,
* testowanie w wielu kontekstach (web, mobile),
* obsługa ról: analityk, low-code developer, tester, administrator.

**Dla kogo:**

* dla zespołów projektowych, które chcą samodzielnie tworzyć i rozwijać rozwiązania,
* dla analityków biznesowych, którzy mogą konfigurować logikę bez pisania kodu,
* dla zespołów IT, które zachowują kontrolę nad standardami i bezpieczeństwem.

## Podsumowanie

Trzy filary platformy – **moduły wykonawcze, integracyjne i narzędzia low-code** – zapewniają kompletną infrastrukturę do budowy i utrzymania aplikacji biznesowych w bankowości.

Dzięki ich ścisłej współpracy:

* aplikacje mogą być uruchamiane we wszystkich kanałach kontaktu z klientem,
* dane są synchronizowane z systemami bankowymi,
* procesy tworzone są szybciej i w bardziej kontrolowany sposób.

Każdy z filarów opisany jest szczegółowo w dalszych rozdziałach dokumentacji.


# Moduły Wykonawcze

**Moduły Wykonawcze** stanowią rdzeń środowiska **Eximee Platform** — odpowiadają za uruchamianie, realizację i obsługę procesów biznesowych w kanałach bankowych.\
Tworzą wspólną warstwę wykonawczą, w której definiowane aplikacje low-code są przetwarzane, wizualizowane i udostępniane użytkownikom końcowym oraz systemom zewnętrznym.

Każdy z modułów pełni określoną rolę w cyklu życia procesu — od interfejsu użytkownika i silnika procesów, przez obsługę spraw i dokumentów, aż po integracje i API.

## Zakres

Moduły wykonawcze obejmują:

* **Eximee Core** – podstawową infrastrukturę i komponenty runtime.
* **Eximee Forms** – warstwę prezentacyjną i formularze użytkownika.
* **Eximee Case Management** – obsługę zadań, spraw i historii działań.
* **Eximee Dashboard** – interfejs użytkownika dla pracowników i partnerów.
* **Eximee API** – zunifikowaną warstwę integracyjną dla procesów i danych.

## Rola w architekturze

Wspólnie tworzą **spójną architekturę mikrousługową**, w której:

* procesy są wykonywane przez **BPMS** i udostępniane przez **API**,
* dane są przechowywane i zarządzane w **Core** i **Model Runtime**,
* interakcje użytkowników realizowane są przez **Forms**, **Dashboard** i **Case Management**.

Moduły wykonawcze stanowią podstawę działania całej platformy Eximee - od aplikacji low-code po bankowe kanały obsługi klienta.


# Moduły Eximee Core

**Eximee Core** stanowi fundament technologiczny Platformy Eximee.\
Zawiera komponenty odpowiedzialne za trwałość danych, wykonywanie procesów, generowanie dokumentów, centralne zarządzanie konfiguracją oraz repozytoryjne przechowywanie artefaktów aplikacji.\
Moduły te są współdzielone przez wszystkie aplikacje low-code zbudowane w środowisku Eximee.

## Eximee FormStore

### **Opis ogólny**

`Eximee FormStore` to wysokowydajne repozytorium dokumentów oraz struktur danych powstających podczas realizacji procesów biznesowych (wniosków, dyspozycji, umów).\
Jest kluczowym elementem zapewniającym **trwałość danych** w Eximee Platform oraz integrację z systemami zewnętrznymi w zakresie przechowywania i udostępniania dokumentów.

### **Funkcjonalność**

* Przechowywanie:
  * plików generowanych przez użytkowników lub automaty (np. PDF, XML, CSV),
  * struktur danych (np. JSON) tworzonych w procesach low-code,
  * metadanych i wersjonowania obiektów.
* Udostępnianie danych poprzez zunifikowane API.
* Integracja z Eximee Document Generator, Eximee BPMS i Eximee Case Management.
* Możliwość składowania dokumentów:
  * lokalnie (wewnętrzne repozytorium),
  * w systemach zewnętrznych ECM/DMS (np. repozytorium bankowe),
  * w nośnikach trwałych (zgodnych z wymogami KNF).

### **Cechy techniczne**

* Optymalizacja pod kątem wydajności i skalowalności (przechowywanie binarne + cache metadanych).
* Możliwość konfiguracji przestrzeni nazw i separacji danych środowiskowych.
* API REST zapewniające dostęp kontrolowany przez uprawnienia domenowe.

## Eximee Document Generator

### **Opis ogólny**

`Eximee Document Generator` to komponent odpowiedzialny za automatyczne tworzenie dokumentów PDF na podstawie szablonów przygotowanych w `Document Generator Tools`.\
Jego zadaniem jest **spójne i powtarzalne generowanie dokumentów** w procesach klienta – od wniosków, przez umowy, po potwierdzenia i raporty.

### **Funkcjonalność**

* Generowanie dokumentów w trzech kontekstach:
  * **na końcu formularza** (np. podsumowanie wniosku),
  * **w trakcie procesu** (np. projekt umowy),
  * **w ramach zadania automatycznego** w BPMS.
* Wykorzystanie dynamicznych szablonów (z warunkową widocznością sekcji).
* Obsługa kodów kreskowych i QR.
* Możliwość podpisania dokumentu (pieczęć bankowa, podpis kwalifikowany).
* Zapis dokumentów w:
  * Eximee FormStore,
  * zewnętrznym ECM,
  * systemie trwałego nośnika.

### **Integracje**

* Z `Eximee Model Runtime` (pobieranie danych modelu aplikacji),
* Z `Eximee Configuration Server` (pobieranie parametrów środowiska, branding),
* Z systemami zewnętrznymi przez API (np. wysyłka dokumentów e-mail, Contact Center).

## EximeeBPMS

### **Opis ogólny**

`EximeeBPMS` (Business Process Management System) to silnik procesów biznesowych oparty o notację **BPMN 2.0**, umożliwiający modelowanie, wykonywanie i monitorowanie procesów biznesowych.\
Został rozszerzony o komponenty wspierające **Case Management**, integrację z Eximee Forms oraz zarządzanie cyklem życia spraw i zadań.

### **Funkcjonalność**

* Uruchamianie procesów BPMN (silnik wywodzący się z *Camunda 7* lub alternatywny).
* Definiowanie user tasków i service tasków z poziomu Process Designer.
* Integracja z:
  * Eximee Forms – jako interfejs użytkownika procesu,
  * Eximee Model Runtime – jako źródło danych biznesowych,
  * Eximee Document Generator – jako usługa generująca dokumenty w toku procesu.
* Agregacja danych procesowych i historii do celów Case Management.
* Obsługa eventów systemowych (Event-Based Architecture).

### **Cechy techniczne**

* Modularna architektura z możliwością podmiany silnika procesowego (BPMN 2.0 compliant).
* Przechowywanie minimalnego zakresu danych w silniku (lightweight BPMS).
* Integracja z zewnętrznymi brokerami zdarzeń (Kafka, RabbitMQ).

## Eximee Data Model Runtime

### **Opis ogólny**

`Eximee Data Model Runtime` stanowi centralny komponent przechowujący dane aplikacji tworzonych w modelu low-code.\
Pozwala na dostęp do danych zarówno z poziomu formularzy, procesów, jak i serwisów aplikacyjnych.

### **Funkcjonalność**

* Przechowywanie danych zgodnie ze strukturą zaprojektowaną w *Data Model Designer*.
* Obsługa relacji, walidacji i reguł TTL.
* API dla komponentów formularzy, procesów i handlerów.
* Obsługa aktualizacji danych w czasie rzeczywistym.
* Zarządzanie danymi dynamicznymi i tymczasowymi (cache, in-memory).

### **Cechy techniczne**

* Struktura danych niezależna od silnika BPMS.
* Mechanizmy bezpieczeństwa danych (maskowanie, kontrola dostępu).
* Możliwość wykorzystania jako warstwy integracyjnej z bazami zewnętrznymi.

## Eximee Configuration Server

### **Opis ogólny**

`Eximee Configuration Server` to scentralizowany serwis dostarczający parametry konfiguracyjne dla aplikacji Eximee.\
Pozwala definiować wartości globalne, środowiskowe i tajne (sekrety).

### **Funkcjonalność**

* Przechowywanie i udostępnianie konfiguracji:
  * domyślnych (aplikacyjnych),
  * środowiskowych (np. test, prod),
  * tajnych (przez integrację z Vault).
* Obsługa dynamicznej zmiany konfiguracji (hot reload).
* GUI do zarządzania konfiguracją (moduł `Eximee Dashboard`).
* Walidacja poprawności struktur konfiguracyjnych.

### **Cechy techniczne**

* Zgodność ze strukturą konfiguracji aplikacji low-code.
* Możliwość wersjonowania zestawów konfiguracyjnych.
* REST API dla aplikacji klienckich.

## Eximee Repository

### **Opis ogólny**

`Eximee Repository` to bezpieczne repozytorium artefaktów platformy, przechowujące wszystkie definicje tworzonych aplikacji Eximee (formularze, procesy, szablony, modele danych, konfiguracje).\
Zapewnia kontrolę wersji, migracje między środowiskami oraz publikację artefaktów dla systemów klienckich.

### **Funkcjonalność**

* Przechowywanie artefaktów aplikacyjnych z pełnym wersjonowaniem.
* Budowanie złożonych artefaktów z komponentów składowych (kompozycja).
* Migracja aplikacji między środowiskami (eksport/import z kontrolą zależności).
* Kontrola dostępu i uprawnień do artefaktów.
* Publikowanie definicji dla klientów zewnętrznych (np. Eximee Forms).

### **Cechy techniczne**

* Wsparcie dla integracji z AD/LDAP w zakresie autoryzacji użytkowników.
* Logowanie zmian i historia wersji.
* API do automatyzacji migracji CI/CD.


# Eximee Forms

**Eximee Forms** to moduł odpowiedzialny za obsługę interfejsu użytkownika w aplikacjach Eximee.\
Umożliwia projektowanie, uruchamianie i przetwarzanie formularzy low-code w różnych kontekstach biznesowych i technologicznych – od portali publicznych po systemy wewnętrzne banku.\
Moduł ten stanowi wspólną warstwę prezentacyjną platformy i zapewnia spójne środowisko interakcji użytkownika z procesami Eximee.

## Architektura modułu

`Eximee Forms` jest wspólną implementacją komponentu formularzy, współdzieloną przez wszystkie konteksty wykorzystania.\
Dostarcza zunifikowany mechanizm renderowania, walidacji, obsługi zdarzeń i komunikacji z procesami EximeeBPMS oraz z Eximee Data Model Runtime.

### **Konteksty wykorzystania (instancje modułu)**

Każdy **kontekst wykorzystania Eximee Forms** – rozumiany jako **kanał technologiczny**, sposób **osadzenia w odpowiedniej aplikacji** (np. portal, bankowość elektroniczna, aplikacja mobilna) lub **udostępnienie danej grupie użytkowników** (klienci, pracownicy, partnerzy) – może stanowić **niezależną instancję wdrożeniową** modułu.

W zależności od architektury i wymagań klienta, instancje te mogą być:

* **rozdzielone** – dla celów separacji środowisk, integracji, bezpieczeństwa lub skalowalności,
* **wspólne** – gdy jeden moduł Eximee Forms obsługuje wiele kontekstów użytkowych w ramach jednej aplikacji lub infrastruktury.

Do typowych kontekstów wykorzystania należą:

* **Eximee Forms for Portals**
* **Eximee Forms for Electronic Banking**
* **Eximee Forms for Mobile Banking**
* **Eximee Forms for FrontOffice**
* **Eximee Forms for BackOffice**
* **Eximee Forms for Partners**

Każdy z tych kontekstów opiera się na wspólnym jądrze (Eximee Forms), korzystając z tych samych bibliotek komponentów i mechanizmów logiki formularzy.

## Opis ogólny

`Eximee Forms` to silnik renderowania i logiki formularzy Eximee.\
Umożliwia bezkodowe uruchamianie dynamicznych formularzy zaprojektowanych w **Form Designerze**, komunikujących się z procesami Eximee BPMS oraz z Eximee Data Model Runtime.

## **Funkcjonalność**

* Renderowanie formularzy na podstawie metadanych aplikacji low-code.
* Obsługa komponentów interaktywnych (biblioteka komponentów prostych i złożonych).
* Walidacja pól, reguły widoczności, zależności dynamiczne.
* Zbieranie danych i przekazywanie ich do procesów Eximee BPMS.
* Obsługa akcji systemowych: zapis, wysyłka, podpis, generowanie podsumowań.
* Obsługa trybów:
  * tworzenie nowej sprawy (formularz startowy),
  * realizacja zadania użytkownika (formularz w toku procesu),
  * przegląd danych (tryb readonly).

## **Cechy techniczne**

* Oparty na architekturze Web Components.
* Integracja z BPMS poprzez zdarzenia i parametry komponentu.
* Dwukierunkowa komunikacja z aplikacją nadrzędną (postMessage, API JS).
* Zgodność z WCAG 2.1.
* Obsługa wielu języków i trybów RWD.
* Możliwość rozszerzenia o komponenty niestandardowe.

## **Bezpieczeństwo**

* Maskowanie danych wrażliwych.
* Walidacja danych po stronie klienta i serwera.
* Skanowanie antywirusowe załączników.
* Izolacja kontekstów sesyjnych i autoryzacyjnych.

## Funkcjonalności wspólne

| Obszar                     | Opis                                                                             |
| -------------------------- | -------------------------------------------------------------------------------- |
| **Formularze low-code**    | Uruchamianie formularzy zaprojektowanych w Eximee Form Designer.                 |
| **Integracja z procesami** | Formularze są interfejsem użytkownika dla procesów BPMN (user task, start form). |
| **RWD i UX/UI**            | Formularze w pełni responsywne, zgodne z Design Style Guide klienta.             |
| **WCAG**                   | Pełna zgodność z WCAG 2.1.                                                       |
| **Monitoring biznesowy**   | Zbieranie danych o wykorzystaniu formularzy, metrykach konwersji i porzuceniach. |
| **Kopie robocze**          | Mechanizm zapisu lokalnego lub zdalnego częściowo wypełnionych formularzy.       |
| **Design Style Guide**     | Obsługa wielu szat graficznych i stylów UI w zależności od wdrożenia.            |
|                            |                                                                                  |

## Cechy wspólne i parametry wdrożeniowe

* **Elastyczność wdrożeniowa:** każdy kontekst może być osobną instancją lub współdzielić środowisko z innymi.
* **Skalowalność:** architektura mikrousługowa, z możliwością niezależnego skalowania instancji.
* **Reużywalność:** wspólne biblioteki komponentów i logiki formularzy.
* **Bezpieczeństwo:** zgodność z wymogami KNF i WCAG, kontrola dostępu i audyt zdarzeń.
* **Personalizacja:** możliwość dostosowania stylu i zachowania do konkretnego wdrożenia klienta.


# Konteksty wykorzystania Eximee Forms

Każdy kontekst wykorzystania rozszerza funkcjonalność `Eximee Forms`, poprzez osadzenia odpowiednim systemie bankowym lub aplikacji dla danej grupy użytkowników.

## **Eximee Forms for Portals**

Obsługa klientów niezalogowanych w kanałach publicznych (np. portal bankowy, kampania produktowa).\
Działa jako samodzielna strona lub Web Component osadzony w portalu.

**Funkcje specyficzne:**

* Integracja z portalem przez parametry we/wy i zdarzenia komponentu.
* Obsługa przekierowań (np. do logowania).
* Wsparcie wielu języków.
* Analiza porzuceń wniosków i konwersji.
* Integracja z systemami analitycznymi (Google Analytics, Tag Manager).

## **Eximee Forms for Electronic Banking**

Moduł dla klientów zalogowanych w systemie bankowości elektronicznej (desktop/web).

**Funkcje specyficzne:**

* Obsługa sesji i tokenów OAuth.
* Autoryzacja formularzy (np. kod SMS, push).
* Integracja z back-endem bankowości elektronicznej.
* Zgodność UX z Design Guide systemu bankowego.
* Obsługa różnych kanałów autoryzacji i kontroli sesji.

## **Eximee Forms for Mobile Banking**

Formularze osadzane w natywnej aplikacji mobilnej banku.

**Funkcje specyficzne:**

* Uruchamianie w WebView.
* Integracja z aplikacją natywną przez *URL schema* lub *JS API*.
* Dostęp do natywnych funkcji urządzenia (aparat, mapa, książka kontaktów, kalendarz).
* Tryb offline i buforowanie danych.
* Natywna obsługa błędów (np. brak Internetu).

## **Eximee Forms for FrontOffice**

Moduł dla doradców obsługujących klientów w oddziałach lub contact center.

**Funkcje specyficzne:**

* Integracja z aplikacją oddziałową lub CRM.
* Kontrola ról i uprawnień (role domenowe).
* UX zoptymalizowany do prezentacji klientowi.
* Obsługa wielu rozdzielczości i urządzeń.

## **Eximee Forms for BackOffice**

Formularze do obsługi procesów wewnętrznych banku (np. weryfikacja, akceptacja).

**Funkcje specyficzne:**

* Integracja z Eximee Dashboard i Case Management.
* Autoryzacja i kontrola dostępu według ról domenowych.
* Powiązanie formularzy z kontekstem sprawy (BPMS).
* Interfejs zoptymalizowany dla pracy operacyjnej.

## **Eximee Forms for Partners**

Moduł dla partnerów zewnętrznych (np. pośredników lub agentów).

**Funkcje specyficzne:**

* Uruchamianie formularzy jako Web Component w aplikacjach partnerów.
* Integracja z zewnętrznymi systemami autoryzacji (OAuth, SSO).
* Dedykowany branding i Design Guide.
* Walidacja danych i uprawnień po stronie banku.


# Osadzanie Eximee Forms jako webcomponent

Moduł prezentacji Formularzy platformy Eximee może być uruchomiony w wariancie:

* samodzielnej aplikacji single page application hostowanej jako dedykowana strona WWW, osadzona w ramach webview lub iframe,
* biblioteki webcomponentu do osadzenia w dowolnej istniejącej stronie lub aplikacji [WWW](http://WWW).

Aplikacja formularzy funkcjonalnie odpowiada za:

* prezentację i obsługę formularzy zdefiniowanych za pomocą lowcode w platformie Eximee,
* każdy formularz ma dynamiczną strukturę składającą się z komponentów oraz jednej lub więcej stron definiowanych za pomocą lowcode,
* formularze Eximee zarządzają stanem formularza, obsługują interakcje użytkownika oraz nawigację w zakresie prezentowanego formularza,
* aplikacja może wykorzystywać nawigację przez URL przeglądarki, wykorzystując na wyłączność część za #, lub nawigację in-memory niewpływającą na stan URL przeglądarki.

Poniższa dokumentacja opisuje sposób osadzania i integracji formularzy Eximee za pomocą biblioteki webcomponentu.

## Ogólne założenia

W celu uruchomienia formularza:

* należy dołączyć pliki JavaScript dostarczające implementacje komponentu do strony WWW,
  * zasoby komponentu są serwowane przez platformę Eximee w wersji zgodnej z serwerem platformy,
  * konkretne nazwy i adresy zasobów wynikają z metryczki hostowanej razem z innymi plikami statycznymi platformy,
* zapewnić dostęp do API REST platformy Eximee z domeny aplikacji hosta,
* zapewnić poprawność nagłówków CORS i CSP,
* stworzyć element DOM komponentu z HTML lub, programowo, z JavaScript,
* zainicjować ładowanie formularza za pomocą programowego API z JavaScript.

## Stosowane technologie

Aplikacja jest stworzona z użyciem Angular w wersji 20.x.x (podlega regularnym aktualizacjom).

Oraz eksponuje webcomponent zgodnie ze specyfikacją webcomponent w zakresie:

* custom elements,
* shadow dom.

Webcomponent może być osadzany wewnątrz Shadow DOM w trybie open, jednak konieczne jest uwzględnienie tego podczas osadzania w DOM styli z metryczki bundleStats.json (opisane niżej).

## Wpływ na globalny kontekst wykonania aplikacji przez zone.js

Aplikacja polega na dostępności globalnie załadowanej biblioteki zone.js w wersji zgodnej z wersją Angular (i dostarczaną razem z Angular/Angular CLI).

Biblioteka zone.js jest podstawą działania frameworku Angular i jest powszechnie stosowana w aplikacjach w nim stworzonych.

Działanie biblioteki polega na monkey patchowaniu asynchronicznych API interakcji użytkownika ze stroną w celu obsługi detekcji zmian UI w ramach interakcji użytkownika.

Aplikacja formularzy Eximee nie jest obecnie dostosowana do pracy w trybie zoneless, a ew. adaptacja wymagałaby dedykowanych prac po stronie platformy Eximee.

Dotychczasowe doświadczenia pokazują jednak, że w przypadku:

* stosowania webcomponentu wewnątrz aplikacji hosta używającej zgodnej wersji zone.js (np. napisanej w Angular),
* stosowania webcomponentu wewnątrz aplikacji hosta nieużywającej zone.js (np. napisanej w vue czy react).

Nie obserwowaliśmy konfliktów ani problemów z działaniem z żadnej z tych aplikacji (hosta, Eximee). Należy jednak mieć na uwadze konieczność weryfikacji kompatybilności bibliotek osadzonych w działającej aplikacji.

## Wpływ na globalny kontekst wykonania aplikacji przez polyfills

Biblioteka webcomponentu polega na dostępności (oraz dołącza, jeśli nie są dostępne) polyfills:

* core-js/shim z core-js,
* @webcomponents/webcomponentsjs/custom-elements-es5-adapter.js z @webcomponents/webcomponentsjs,
* web-components/webcomponents-loader z polymer.

Wszystkie zależności polyfills są zgodne ze standardami dostarczania polyfilii, tj.

* nie nadpisują natywnych rozwiązań dostępnych w przeglądarce,
* ładują się, tylko jeżeli dostarczają funkcjonalność niedostępną natywnie i niedostarczoną innymi metodami (np. przez aplikację hosta),
* są dostarczane przez powszechnie stosowane biblioteki open source.

W praktyce wskazane polyfills nie powinny zmieniać zachowania w przypadku:

* stosowania nowoczesnych przeglądarek,
* stosowania w aplikacji hosta używającej nowoczesnych frameworków web (jak np. Angular).

## Metryczka zasobów i cykl wydań

Zasoby biblioteki webcomponentu są zależne od aktualnej wersji platformy Eximee osadzonej na konkretnym środowisku.

W celu łatwego zarządzania zależnościami platforma hostuje plik metryczki opisujący zasoby wymagane do dołączenia do strony w celu uruchomienia webcomponentu.

Metryczka jest w formacie JSON i przykładowo wygląda:

```json
{
  "format": 3,
  "scripts": [
    "polyfills.125595b8f8d58bce.js",
    "main.922b3d09b697675a.js"
  ],
  "globalStyles": [
    "global-styles.a9c4b7e18d2f03ab.css"
  ],
  "styles": [
    "styles.6e50ddf23fe0e270.css"
  ]
}
```

Metryczka zawiera trzy rodzaje zasobów, które należy załadować w różny sposób:

* scripts – skrypty JavaScript; należy je osadzić w `<head>` strony hostującej webcomponent (w tagach `<script>`),
* globalStyles – globalne arkusze stylów; należy je osadzić w `<head>` strony hostującej webcomponent (w tagach `<link>`). Zawierają wyłącznie zasoby niezwiązane z layoutem czy wyglądem elementów DOM, takie jak definicje fontów (`@font-face`). Nie wpłyną na stylowanie elementów istniejącej aplikacji hosta,
* styles – arkusze stylów specyficzne dla komponentu; należy je dołączyć bezpośrednio do elementu DOM komponentu (lub jego shadowRoot, jeśli webcomponent jest osadzony w Shadow DOM).

Wszystkie nazwy zasobów zawierają hashe na podstawie treści plików. Dzięki temu możliwe jest równocześnie:

* zapewnienie ładowania odpowiedniego pliku zgodne z konkretną wersją systemu,
* reużywanie plików z cache, jeżeli pomiędzy wersjami ich treść się nie zmienia.

Osadzenie zasobów może być realizowane:

* dynamicznie przez frontend aplikacji przed uruchomieniem formularza,
* w ramach server side renderingu strony hostującej aplikację hosta (zalecany sposób).

Uwaga, w przypadku osadzenia webcomponentu formularza w ramach węzłów za shadow dom (open) konieczne jest osadzanie linków do styli wewnątrz odpowiedniego shadowRoot. Style osadzone w head całego dokumentu nie będą mogły standardowo ostylować komponentu wewnątrz shadow dom.

## Tworzenie instancji formularza

### Osadzanie komponentu i uruchamianie formularza

Komponent można osadzić w DOM za pomocą tagu HTML komponentu lub programowo za pomocą API JavaScript:

```typescript
var form = document.createElement("ex-forms-form");
document.body.appendChild(form)
```

Komponent formularza może być osadzony w dowolnym miejscu w strukturze DOM aplikacji.

Po osadzeniu i otrzymaniu referencji na element możliwe jest uruchomienie formularza metodą loadForm zgodnie z przykładem:

```typescript
container.loadForm({
  formId: 'demoFormularzJakoWebcomponent', /* identyfikator formularza */
  baseHref: '/api',  /* path, po którym dostępne jest REST API Eximee udostępnione przez proxy-pass */
  onError: function () {
    alert('Wystąpił błąd podczas procesowania wniosku');
  }
});
```

Istnieje możliwość przekazania dodatkowych parametrów do metody load form, co zostanie opisane w kolejnych sekcjach dokumentacji oraz podane w referencyjnym API na końcu dokumentu.

Jednym z takich parametrów jest możliwość przekazania biznesowych parametrów uruchomienia konkretnego formularza, przykładowo:

```typescript
container.loadForm({
  formId: 'demoFormularzJakoWebcomponent', /* identyfikator formularza */
  baseHref: '/api',  /* path po którym dostępne jest REST API Eximee udostępnione przez proxy-pass */
  data: JSON.stringify({'param1': 'value1'}), /* Dodatkowe parametry biznesowe zasilające formularz w postaci serializowanego do JSON string obiektu klucz-wartość  */
  onError: function () {
    alert('Wystąpił błąd podczas procesowania wniosku');
  }
});
```

### Rozszerzanie nagłówków komunikacji REST (w tym nagłówki auth dla API Gateway)

W wielu wdrożeniach zachodzi konieczność rozszerzenia nagłówków żądań REST API, w szczególności w aplikacjach obsługujących uwierzytelnianie użytkownika i polegających na kontroli uprawnień na poziomie API Gateway (np. tokenami OIDC).

W tym celu możliwe jest wskazanie funkcji tworzącej nagłówki, które zostaną dołączone do każdego żądania REST:

```typescript
form.loadForm({
    formId: 'demoFormularzJakoWebcomponent',
    additionalRequestHeaders: () => ({
        'X-Custom-Header': 'value'
    })
})
```

Metoda tworząca nagłówki jest wywoływana za każdym razem, bezpośrednio przed wykonanie żądania do REST API. Nagłówki nie są przechowywane pomiędzy wołaniami, co jest szczególnie istotne np. dla nagłówków Oauth, które mogą się zmienić w wyniku odświeżania tokenu w trakcie obsługi formularza.

### Zachowywanie stanu formularza pomiędzy odświeżeniami strony / nawigacją aplikacji hosta

Kompletny stan formularza i danych wprowadzonych przez użytkownika jest przechowywane po stronie serwera platformy Eximee w ramach sesji użytkownika.

Oznacza to, że istnieje możliwość odtworzenia/wznowienia aktywnego formularza użytkownika nawet po nawigacji w aplikacji hosta lub całkowitym odświeżeniu strony w przeglądarce.

Formularz użytkownika po stronie serwera jest rozróżniany na podstawie:

* identyfikatora sesji w Cookie,
* identyfikatora instancji formularza w sesji na podstawie numeru instancji formularza (formInstanceNumber).

Zakładając, że obsługa Cookie jest zagwarantowana oraz Cookie nie zostanie usunięte (poza sytuacją, gdy wymagania funkcjonalne wymagają takiego usunięcia) to do odtworzenia formularza konieczne jest przechowanie jego numer instancji.

Numer formularza można przekazać do metody load form oraz pobrać z instancji po jego uruchomieniu. Zakładając, że aplikacja hosta posiada jednoznaczny sposób przechowania tej wartości (np. w query strony, serwerowo itp.), możliwe jest napisanie:

```typescript
let formInstanceNumber: string | undefined = restoreFormInstanceNumber();
form.loadForm({
    formId: 'demoFormularzJakoWebcomponent',
    formInstanceNumber: formInstanceNumber,
    onLoaded: (result, config) => storeFormInstanceNumber(result.data.formModel.formNumber),
});

```

## Dostęp do infrastruktury REST platformy Eximee

Komponent prezentujące formularze wymaga dostępu do REST API serwowanego przez instancję platformy Eximee. Wszystkie endpointy REST API są już hostowane i eksponowane na potrzeby instancji samodzielnej webforms (np. na potrzeby aplikacji www, osadzania webview czy iframe).

Endpointy do komunikacji muszą być dostępne przez proxy w domenie aplikacji hosta przekazująca ruch do infrastruktury Eximee. Komunikacja między różnymi domenami aplikacji i Eximee nie jest możliwa ze względu na ograniczenia zarządzania 3rd party cookies w przeglądarkach oraz brak międzymodułowej obsługi webworkerów.

Możliwe jest również wypracowanie innego mechanizmu komunikacji, w szczególności takiego, w którym aplikacja hosta pośredniczy w każdym wywołaniu REST. Jednak wymaga to analizy i wypracowania konkretnego dla danego wdrożenia rozwiązania i wiąże się z zaplanowanie dodatkowych prac rozwojowych w platformie.

## Cookie aplikacji formularza

Aplikacja wykorzystuje cookie opisujące:

* sesję użytkownika,
* parametry session affinity dla loadbalancerów.

Cookie są tworzone automatycznie przez serwer i infrastrukturę (loadbalancery) i są skonfigurowane zgodnie z parametrami konkretnego środowiska.

## Usunięcie komponentu

W celu bezpiecznego usunięcia komponentu należy przed usunięciem go z DOM wywołać eksponowaną na elemencie DOM webcomponentu asynchroniczną metodę `destroy`.

## Znane ograniczenia funkcjonalne

* Biblioteka zakłada, że na jednym ekranie równocześnie prezentowany jest tylko jeden formularz i próba wyświetlenia dwóch równolegle działających instancji formularzy może powodować błędy.
* Zmiana parametrów zainicjowanego formularza wymaga jego ponownej inicjalizacji i oznacza przygotowanie nowej instancji (bez dotychczas wprowadzonych przez użytkownika danych).

## Interfejs komponentu

```typescript
export interface FormWebcomponentApi {
    loadForm(config: LoadFormConfig): void;
    hasActiveForm(): boolean;
 
    cancelCurrentForm(): void;
    handleAction(action: ExAction): void;
    proceedCurrentForm(): void;
    backCurrentForm(): void;
    isLastVisiblePage(): boolean;
    isFirstVisiblePage(): boolean;
    shouldShowForwardButton(): boolean;
    shouldShowBackwardButton(): boolean;
    getForwardButtonLabel(): string;
    onShowSpinner(callback: () => void): void;
    onHideSpinner(callback: () => void): void;
    getTranslation(key: string): string;
    destroy(): Promise<void>;
}
 
export interface LoadFormConfig extends LoadConfig {
    formId: string;
}
 
export interface LoadConfig {
    formInstanceNumber?: string;
    processId?: string;
    baseHref?: string;
    accessToken?: string;
    tokenType?: string;
    readonly?: boolean;
    data?: string;
    shadowRoot?: ShadowRoot;
    scrollOnErrorOffset?: number;
    additionalRequestHeaders?: () => { [header: string]: string };
    onLoaded?: (result: unknown, config: LoadConfig) => void;
    onActionDispatched?: (result: unknown, config: LoadConfig) => void;
    onCancelled?: (config: LoadConfig) => void;
    onSaved?: (result, config: LoadConfig) => void;
    onDraftSaved?: (result, config: LoadConfig) => void;
    onPageChanged?: (result, config: LoadConfig) => void;
    onModelChanged?: (result, config: LoadConfig) => void;
    onPageValidationErrors?: (result, config: LoadConfig) => void;
    onError?: (error, config: LoadConfig) => void;
    onAppEvent?: (event, config: LoadConfig) => void;
    onComponentValueChanged?: (result: unknown, config: LoadConfig) => void;
    onShowSpinner?: (immediate: boolean ) => void;
    onHideSpinner?: () => void;
    onClosed?: (config: LoadConfig) => void;
}
 
export interface ExAction {
    sourceId: string;
    event: ExActionEvent | string;
    detail?: object | string | number | boolean;
}
 
export enum ExActionEvent {
    SAVE = 'SAVE',
    CLOSE = 'CLOSE',
    NEXT = 'NEXT',
    EDIT = 'EDIT',
    CLICK_MORE_INFO = 'CLICK_MORE_INFO',
    CALL = 'CALL',
    CHECK = 'CHECK',
    UNCHECK = 'UNCHECK',
    CLICK = 'CLICK',
    ON_EXIT = 'ON_EXIT',
    TOOLTIP_CLICKED = 'TOOLTIP_CLICKED',
    AUTOCOMPLETE_NO_MATCH_BUTTON_CLICKED = 'AUTOCOMPLETE_NO_MATCH_BUTTON_CLICKED',
    EXPAND_STATEMENT = 'EXPAND_STATEMENT',
    ON_PAGE_ENTER = 'ON_PAGE_ENTER',
    POI_SELECTED = 'POI_SELECTED',
    HIDDEN = 'HIDDEN',
    CLOSE_POPUP = 'CLOSE_POPUP',
    RETRY = 'RETRY',
    SAVE_DRAFT = 'SAVE_DRAFT',
    VALUE_CHANGED = 'VALUE_CHANGED',
    FORWARD_PAGE = 'FORWARD_PAGE',
    BACKWARD_PAGE = 'BACKWARD_PAGE',
    PARK_FORM_WITH_PROVIDED_HASH = 'PARK_FORM_WITH_PROVIDED_HASH',
    SHOW_POPUP = 'SHOW_POPUP',
    SAVE_POPUP = 'SAVE_POPUP',
    TOGGLE = 'TOGGLE',
    CLEAR_UPLOAD_FILE = 'CLEAR_UPLOAD_FILE',
    REDIRECT_TO_RETURN_URL = 'REDIRECT_TO_RETURN_URL',
    REDIRECT = 'REDIRECT',
    CHECK_FED_STATEMENT = 'CHECK_FED_STATEMENT',
    POPUP_SAVED = 'POPUP_SAVED',
    POPUP_HIDDEN = 'POPUP_HIDDEN',
    START_PROCESS = 'START_PROCESS',
    COMPLETE_USER_TASK = 'COMPLETE_USER_TASK',
    TILE_CLICKED = 'TILE_CLICKED',
    START_APPLICATION = 'START_APPLICATION',
    EXIT_CONFIRMED = 'EXIT_CONFIRMED'
}
```

## Przykłady użycia

Platforma wdrażana na środowiskach testowych hostuje przykładowy HTML osadzający formularz za pomocą webcomponentu:

* bezpośrednio w DOM strony,
* opakowany w Shadow Root.

Znając adres platformy Eximee, oba przykłady można obejrzeć pod adresem https\://\[adres-srodowiska]/webcomponent/\[szata-wdrozenia]-webcomponent.html

Przykład HTMLa:

```html
<html>
<head>
    <script>
        /*  Metoda uruchamiająca wniosek bezpośrednio w drzewie DOM. */
        function initFormPlain() {
            // Przygotowanie komponentu drzewie DOM
            const formWrapper = document.getElementById('form-wrapper');
            const formWebcomponent = document.createElement("ex-forms-form");
            formWrapper.appendChild(formWebcomponent);
 
            // Uruchomienie instancji formularza
            formWebcomponent.loadForm({
                formId: 'demoFormularzJakoWebcomponent',
                baseHref: '/api',
                onError: function () {
                    alert('Wystąpił błąd podczas procesowania wniosku');
                }
            });
        }
    </script>
</head>
<body>
    <div id="form-wrapper"></div>
    <script src="polyfills.5310c9e539f37fb1.js" type="module"></script>
    <script src="main.71e5244a2a4d4f3d.js" type="module"></script>
</body>
</html>
```


# Eximee Case Management

**Eximee Case Management** to moduł platformy Eximee odpowiedzialny za zarządzanie sprawami, zadaniami i kontekstem pracy użytkowników.\
Umożliwia pełną obsługę cyklu życia sprawy – od jej rozpoczęcia, poprzez realizację i monitorowanie postępu, aż po archiwizację historii działań.\
Moduł ten integruje dane pochodzące z procesów EximeeBPMS, modeli danych oraz aplikacji zewnętrznych, tworząc centralne miejsce zarządzania przypadkami biznesowymi.

## Rola i architektura modułu

### **Opis ogólny**

`Eximee Case Management` pełni funkcję warstwy pośredniej między procesami biznesowymi (EximeeBPMS), formularzami użytkownika (Eximee Forms) a aplikacjami operacyjnymi (np. Eximee Dashboard, BackOffice).\
Dostarcza zestaw narzędzi do prezentowania i wykonywania zadań, przeglądania spraw oraz interakcji z kontekstem użytkownika.

### **Cele modułu**

* Konsolidacja danych o sprawach i zadaniach z wielu źródeł.
* Zapewnienie użytkownikom ujednoliconego interfejsu do realizacji zadań.
* Odciążenie silnika procesowego BPMS od przechowywania i prezentowania danych operacyjnych.
* Wsparcie modelu *Case-Oriented Processing* – skupionego na kontekście klienta lub sprawy, a nie na samym procesie.

### **Architektura logiczna**

Moduł składa się z następujących warstw:

1. **Warstwa prezentacji** – interfejs użytkownika (zazwyczaj osadzany w Eximee Dashboard).
2. **Warstwa aplikacyjna** – logika Case Management (obsługa zadań, list, akcji biznesowych).
3. **Warstwa integracyjna** – komunikacja z EximeeBPMS, Data Model Runtime i Forms.
4. **Warstwa danych** – repozytorium stanów spraw i historii zdarzeń (niezależne od BPMS).

## Funkcjonalność

### **Obsługa zadań użytkownika**

* Lista zadań przypisanych do użytkownika lub zespołu.
* Filtrowanie, sortowanie i wyszukiwanie zadań.
* Konfigurowalne kolumny i układy list.
* Obsługa priorytetów, terminów (deadline) i statusów.
* Wykonywanie kolejnych zadań w trybie sekwencyjnym (*Next Best Task*).
* Grupowa obsługa zadań (batch operations).
* Możliwość wykonywania zadań automatycznych w tle (silnik automatyzacji).
* Integracja z formularzami **Eximee Forms** w roli interfejsu użytkownika.

### **Obsługa spraw (Case View)**

* Przegląd spraw i ich statusów.
* Filtrowanie i sortowanie listy spraw według kontekstu biznesowego (np. klient, produkt, proces).
* Widok szczegółowy sprawy z informacjami o:
  * historii działań i decyzji,
  * załączonych dokumentach,
  * powiązanych zadaniach,
  * danych kontekstowych (z modelu danych).
* Możliwość uruchamiania formularzy i mikroaplikacji w kontekście danej sprawy.
* Tworzenie nowych spraw przez użytkownika (np. w FrontOffice lub BackOffice).

### **Obsługa historii i zdarzeń**

* Rejestracja historii spraw niezależnie od silnika workflow (EximeeBPMS).
* Wykorzystanie zdarzeń z procesów i aplikacji biznesowych (Event-Based Architecture).
* Zapis działań użytkowników i zmian statusów.
* Wsparcie dla audytu zgodnego z wymogami compliance (np. KNF).

### **Akcje biznesowe**

* Definiowalne akcje dostępne dla użytkownika w kontekście sprawy lub zadania (np. „Zatwierdź”, „Odrzuć”, „Przekaż”).
* Parametryzacja dostępnych akcji na poziomie aplikacji low-code.
* Obsługa akcji systemowych i niestandardowych (custom handlers).

### **Obsługa kontekstu klienta**

* Prezentacja danych klienta powiązanych ze sprawą.
* Integracja z systemami CRM, KYC, scoringowymi itp.
* Dynamiczne ładowanie danych kontekstowych.

## Integracje

### **Integracja z EximeeBPMS**

* Pasywne wykorzystanie silnika BPMS – Case Management nie wykonuje procesów, ale je monitoruje.
* Subskrypcja zdarzeń procesowych (task created, task completed, incident occurred).
* Odczyt danych procesowych przez API BPMS.

### **Integracja z Eximee Forms**

* Formularze stanowią interfejs użytkownika dla zadań w Case Management.
* Każde zadanie może uruchamiać przypisany formularz low-code.
* Współdzielony kontekst danych (sprawa ↔ formularz ↔ proces).

### **Integracja z Eximee Model Runtime**

* Pobieranie danych kontekstowych sprawy i klienta.
* Aktualizacja danych w toku realizacji zadań.

### **Integracja z Eximee Dashboard**

* Case Management jest jednym z kluczowych modułów Eximee Dashboard.
* Udostępnia ekrany list spraw, zadań i historii.
* Umożliwia osadzanie mikroaplikacji wspomagających pracę (np. notatki, kalendarz, lista dokumentów).

## Cechy techniczne

* Architektura mikrofrontendowa z możliwością rozbudowy o aplikacje rozszerzające.
* Wbudowane mechanizmy filtrowania, sortowania i paginacji.
* Skalowalność i separacja kontekstów użytkowników.

## Przykładowe scenariusze użycia

### **FrontOffice / BackOffice**

* Doradca otwiera sprawę klienta i widzi listę wszystkich powiązanych zadań.
* Wykonuje kolejne kroki procesu (np. „Weryfikacja danych”, „Zatwierdzenie umowy”) przez uruchomienie formularza.
* Historia sprawy jest automatycznie aktualizowana na podstawie zdarzeń BPMS.

### **Manager operacyjny**

* Przegląda listę zadań zespołu i priorytetyzuje je.
* Wykonuje operacje grupowe, np. przypisanie zadań lub zmianę statusów.
* Analizuje obciążenie pracowników na podstawie metryk z Case Management.

### **Partner zewnętrzny**

* Otrzymuje widok swoich spraw i zadań w ramach współdzielonego kanału partnera.
* Obsługuje wybrane etapy procesu, np. weryfikację dokumentów klienta.

## Cechy wspólne i parametry wdrożeniowe

* **Elastyczność konfiguracji:** widoki list, szczegółów i akcji definiowane low-code w Case Management Designer.
* **Reużywalność:** jeden komponent Case Management może obsługiwać wiele aplikacji.
* **Bezpieczeństwo:** pełna kontrola dostępu do danych i operacji w oparciu o role domenowe.
* **Personalizacja:** możliwość dostosowania layoutu, filtrów i akcji do specyfiki wdrożenia.
* **Skalowalność:** rozdzielenie logiki prezentacji od danych procesowych umożliwia niezależne skalowanie.


# Eximee Dashboard

**Eximee Dashboard** to moduł aplikacyjny platformy Eximee, stanowiący centralny interfejs pracy użytkowników wewnętrznych, pośredników i partnerów banku.\
Pełni funkcję **kontenera aplikacyjnego** (ang. *application shell*), integrującego w jednym środowisku różne mikroaplikacje Eximee – takie jak **Case Management**, **Forms**, **Document Viewer** czy dedykowane rozszerzenia operacyjne.

Dzięki modularnej architekturze i wsparciu dla mikrofrontendów, Eximee Dashboard umożliwia elastyczne komponowanie środowiska pracy użytkownika, dopasowane do jego roli, kompetencji i procesów realizowanych w danym wdrożeniu.

## Rola i architektura modułu

### **Opis ogólny**

`Eximee Dashboard` to aplikacja przeglądarkowa, która stanowi główny punkt wejścia do środowiska Eximee dla pracowników banku, pośredników i partnerów.\
Jego podstawowym zadaniem jest integracja modułów Eximee oraz prezentacja danych i zadań w spójnym, konfigurowalnym interfejsie.

### **Cele modułu**

* Zapewnienie użytkownikowi jednolitego punktu dostępu do wszystkich aplikacji i procesów Eximee.
* Umożliwienie pracy w wielu kontekstach (zadania, sprawy, dokumenty, formularze).
* Integracja z systemami tożsamości, uprawnień i kompetencji (AD, LDAP).
* Elastyczna rozbudowa o mikroaplikacje i komponenty low-code.
* Zwiększenie ergonomii i produktywności użytkowników dzięki konsolidacji narzędzi.

## Architektura systemowa

`Eximee Dashboard` oparty jest na architekturze **mikrofrontendowej**, w której poszczególne moduły (np. Case Management, Forms, Notatki, Kalendarz) działają jako samodzielne komponenty, ładowane dynamicznie w kontekście głównego kontenera.

### **Warstwy architektury**

1. **Warstwa prezentacji** – interfejs użytkownika (SPA – Single Page Application).
2. **Warstwa mikrofrontendów** – dynamicznie dołączane aplikacje (np. listy zadań, historia sprawy, widok formularzy).
3. **Warstwa integracji** – komunikacja z modułami Eximee (BPMS, Model Runtime, Repository).
4. **Warstwa bezpieczeństwa** – integracja z systemami uwierzytelniania i autoryzacji (LDAP, SSO, OAuth).

## Funkcjonalność

### **Zarządzanie mikroaplikacjami**

* Dodawanie i konfigurowanie mikroaplikacji w ramach Dashboardu (np. notatki, planowanie spotkań, dokumenty).
* Uruchamianie mikroaplikacji zdefiniowanych low-code w Eximee Repository.
* Wsparcie dla mikrofrontendów pisanych w różnych technologiach (React, Angular, Vue).
* Izolacja kontekstów mikroaplikacji (sesja, dane, uprawnienia).
* Komunikacja pomiędzy mikrofrontendami za pomocą eventów i kontekstu aplikacji.

### **Integracja z Eximee Case Management**​

* Wbudowane listy zadań i spraw.
* Prezentacja szczegółów sprawy i historii działań.
* Uruchamianie formularzy Eximee Forms w kontekście zadania lub sprawy.
* Konfigurowalne akcje biznesowe i skróty operacyjne.

### **Integracja z Eximee Forms**

* Możliwość uruchamiania formularzy low-code w oknach modalnych lub zakładkach Dashboardu.
* Przekazywanie parametrów kontekstowych (np. ID sprawy, dane klienta).
* Obsługa wielu sesji formularzy równolegle (np. kilka otwartych wniosków).

### **Zarządzanie użytkownikami i rolami**

* Integracja z Active Directory lub LDAP w celu autentykacji i autoryzacji.
* Mapowanie ról biznesowych (np. Doradca, Analityk, Manager).
* Obsługa uprawnień domenowych w ramach mikroaplikacji.
* Wsparcie dla regionalizacji i przypisania kompetencji.

### **Obsługa kontekstu pracy**

* Dynamiczne przełączanie kontekstu użytkownika (np. „tryb pracownika”, „tryb menedżera”).
* Prezentacja danych z różnych modułów w jednym widoku (np. dane klienta, historia sprawy, załączniki).
* Zapamiętywanie stanu interfejsu użytkownika (układ, filtry, otwarte karty).

### **Dodatkowe funkcjonalności**

* Możliwość integracji z systemami zewnętrznymi banku (CRM, DMS, Contact Center).
* Personalizacja wyglądu interfejsu (Design Guide banku).
* Wsparcie dla wielu języków.
* Pełna zgodność z WCAG 2.1.
* Logowanie zdarzeń użytkowych (activity log).

## Integracje

### **Eximee Case Management**

* Wyświetlanie list zadań i spraw w kontekście użytkownika.
* Obsługa akcji biznesowych bezpośrednio z poziomu Dashboardu.
* Współdzielenie kontekstu klienta i sprawy pomiędzy mikroaplikacjami.

### **Eximee Forms**

* Uruchamianie formularzy w ramach Dashboardu (tryb zintegrowany).
* Synchronizacja stanu formularza z kontekstem zadania.
* Możliwość kontynuacji przerwanych wniosków (kopia robocza).

### **Eximee Repository**

* Pobieranie definicji mikroaplikacji, layoutów i konfiguracji ekranów.
* Migracja konfiguracji między środowiskami (DEV, UAT, PROD).

### **Eximee Model Runtime**

* Odczyt danych kontekstowych do prezentacji w mikroaplikacjach.
* Aktualizacja danych w toku realizacji zadań użytkownika.

### **Systemy zewnętrzne banku**

* Integracja z CRM, systemami analitycznymi, DMS i narzędziami komunikacji wewnętrznej.

## Cechy techniczne

* Architektura oparta o SPA (Single Page Application) i mikrofrontendy.
* Modularna budowa umożliwiająca łatwe dodawanie nowych komponentów.
* API komunikacyjne pomiędzy mikroaplikacjami (inter-component messaging).
* Obsługa autoryzacji federacyjnej (OAuth 2.0, SAML, OpenID Connect).
* Możliwość wdrożenia jako aplikacja samodzielna lub osadzona (np. w intranecie banku).
* Wsparcie dla cache sesyjnego i przechowywania ustawień użytkownika w przeglądarce.
* Skalowalność horyzontalna (moduł stateless).

## Przykładowe scenariusze użycia

### **Pracownik BackOffice**

* Loguje się do Eximee Dashboard przez AD.
* Na ekranie głównym widzi listę swoich zadań z Case Management.
* Otwiera formularz Eximee Forms przypisany do zadania.
* Po zakończeniu zadania widzi automatycznie odświeżony stan listy.

### **Manager zespołu**

* Korzysta z mikroaplikacji „Zadania zespołu” i „Statystyki”.
* Może przypisywać zadania, filtrować sprawy, analizować obciążenie pracowników.

### **Partner zewnętrzny**

* Otwiera Dashboard w trybie partnerskim (autoryzacja OAuth).
* Ma dostęp tylko do mikroaplikacji przypisanych do jego roli.
* Realizuje własne zadania i przekazuje dane do systemu bankowego.

## Cechy wspólne i parametry wdrożeniowe

* **Elastyczność wdrożeniowa:** może obsługiwać różne grupy użytkowników w ramach jednej instancji.
* **Reużywalność:** mikrofrontendy współdzielone pomiędzy aplikacjami.
* **Bezpieczeństwo:** integracja z systemami tożsamości i kontrolą dostępu.
* **Personalizacja:** konfigurowalne layouty, mikroaplikacje, kolory i branding.
* **Skalowalność:** obsługa dużej liczby użytkowników i mikroaplikacji w jednym środowisku.
* **Dostępność:** pełna zgodność z WCAG 2.1 i obsługa wielu języków.


# Moduły Low-Code

**Moduły Low-Code** stanowią zestaw narzędzi deweloperskich i administracyjnych umożliwiających projektowanie, konfigurację i publikację aplikacji Eximee bez konieczności pisania kodu programistycznego.\
Pozwalają one analitykom, projektantom procesów i administratorom tworzyć kompletne rozwiązania biznesowe w oparciu o wizualne edytory, predefiniowane komponenty oraz centralne repozytorium artefaktów.

Dzięki tym narzędziom Eximee realizuje ideę **citizen development** – umożliwiając tworzenie aplikacji biznesowych przez zespoły merytoryczne, z zachowaniem standardów bezpieczeństwa, jakości i integracji z infrastrukturą banku.<br>

## Architektura i rola modułów

### **Opis ogólny**

Moduły Low-Code tworzą spójne środowisko projektowo-konfiguracyjne, które obejmuje:

* projektowanie logiki procesowej i interfejsów użytkownika,
* definiowanie modeli danych,
* konfigurację dokumentów, akcji, uprawnień i integracji,
* zarządzanie wersjami i migracjami aplikacji.

Każdy z modułów odpowiada za inny aspekt cyklu życia aplikacji:

| Obszar                 | Narzędzie                    | Cel                                           |
| ---------------------- | ---------------------------- | --------------------------------------------- |
| Modelowanie aplikacji  | **Application Designer**     | Tworzenie i organizacja aplikacji low-code    |
| Dane                   | **Data Model Designer**      | Definiowanie struktury danych                 |
| Formularze             | **Form Designer**            | Tworzenie formularzy i ekranów                |
| Logika                 | **Script Code Tools**        | Edycja logiki biznesowej (skrypty)            |
| Dokumenty              | **Document Generator Tools** | Projektowanie szablonów PDF                   |
| Procesy                | **Process Designer**         | Modelowanie procesów BPMN                     |
| Case’y i ekrany        | **Case Management Designer** | Konfiguracja ekranów i list spraw             |
| Konfiguracja aplikacji | **Configuration**            | Centralne zarządzanie parametrami biznesowymi |

## Application Designer

### **Opis**

`Application Designer` to centralny edytor low-code służący do tworzenia i zarządzania aplikacjami Eximee.\
Umożliwia grupowanie wszystkich artefaktów aplikacyjnych (formularzy, procesów, modeli danych, dokumentów itp.) w logiczne jednostki aplikacyjne.

### **Funkcjonalność**

* Tworzenie nowych aplikacji low-code.
* Wersjonowanie i publikowanie aplikacji.
* Powiązanie aplikacji z konfiguracjami środowiskowymi.
* Autentykacja użytkowników projektowych poprzez AD lub LDAP.
* Migracja aplikacji pomiędzy środowiskami (DEV, UAT, PROD).
* Integracja z Eximee Repository w zakresie wersjonowania i kontroli zależności.

### **Zastosowanie**

To główne narzędzie pracy analityków i administratorów aplikacji, będące punktem wyjścia do edycji wszystkich pozostałych komponentów (formularzy, procesów, modeli danych itd.).<br>

## Data Model Designer

### **Opis**

`Data Model Designer` służy do definiowania modelu danych dla aplikacji low-code.\
Umożliwia tworzenie struktur obiektowych, powiązań i reguł walidacyjnych w formie wizualnej.

### **Funkcjonalność**

* Definiowanie pól danych i ich typów.
* Modelowanie relacji między obiektami.
* Określanie źródeł danych (wewnętrznych i zewnętrznych).
* Integracja z Eximee Model Runtime, który wykonuje model danych w środowisku runtime.

### **Cechy techniczne**

* Walidacja poprawności modelu przed publikacją.
* Wsparcie dla wersjonowania struktur danych.
* Automatyczne generowanie struktur JSON na podstawie zmian w GUI<br>

## Form Designer

### **Opis**

`Form Designer` to edytor graficzny umożliwiający projektowanie formularzy elektronicznych Eximee w trybie **drag & drop**.\
Umożliwia tworzenie interfejsów użytkownika bez konieczności programowania.

### **Funkcjonalność**

* Tworzenie formularzy z komponentów prostych i złożonych.
* Podgląd w docelowej szacie graficznej (Design Style Guide).
* Definiowanie stron, kroków i progresu wypełniania formularza.
* Zarządzanie widocznością pól, logiką biznesową i źródłami danych.
* Integracja z procesami (start i user task).
* Obsługa wielojęzyczności i WCAG.
* Parametryzacja akcji wykonywanych po zapisaniu lub wysłaniu formularza.

### **Zastosowanie**

Projektanci UX i analitycy mogą tworzyć kompletne formularze, które później są uruchamiane w Eximee Forms w różnych kontekstach (Portal, eBankowość, BackOffice).<br>

## Script Code Tools

### **Opis**

`Script Code Tools` to edytor logiki biznesowej w postaci skryptów (JavaScript).\
Pozwala definiować zachowania formularzy, operacje na danych oraz logikę kroków w procesach.

### **Funkcjonalność**

* Edycja skryptów w przeglądarce z podpowiadaniem składni.
* Testowanie logiki biznesowej z poziomu narzędzia.
* Tworzenie i wersjonowanie fragmentów logiki (re-use).
* Definiowanie reguł walidacyjnych, automatycznych kalkulacji i transformacji danych.
* Integracja z Process Designerem i Form Designerem.

### **Cechy techniczne**

* Mechanizm sandboxowania (izolacja skryptów).
* Walidacja składni.
* Testy jednostkowe.<br>

## Document Generator Tools

### **Opis**

`Document Generator Tools` służy do definiowania szablonów dokumentów PDF generowanych przez moduł **Eximee Document Generator**.\
Umożliwia tworzenie dynamicznych dokumentów zgodnych z wymogami banku.

### **Funkcjonalność**

* Projektowanie szablonów dokumentów (umowy, potwierdzenia, raporty).
* Obsługa dynamicznych sekcji, tabel i warunków widoczności.
* Wstawianie kodów kreskowych i QR.
* Podgląd gotowego dokumentu z danymi testowymi.
* Pełna zgodność z projektem graficznym i brandingiem banku.

### **Integracje**

* Z Eximee Model Runtime – w celu pobierania danych do wypełnienia dokumentu.
* Z Eximee Configuration Server – dla parametrów środowiskowych (logo, podpisy, pieczęcie).<br>

## Process Designer

### **Opis**

`Process Designer` to przeglądarkowy edytor procesów workflow zgodnych z notacją **BPMN 2.0**.\
Pozwala na projektowanie i dokumentowanie procesów biznesowych, które są następnie wykonywane w module **Eximee BPMS**.

### **Funkcjonalność**

* Graficzne modelowanie procesów (start, taski, gateway, eventy).
* Podpinanie formularzy Eximee Forms jako user tasków.
* Definiowanie skryptów i akcji automatycznych (ScriptCode).
* Dokumentowanie procesów (notatki, opisy, reguły).
* Walidacja poprawności modelu BPMN.

### **Zastosowanie**

Umożliwia tworzenie kompletnych procesów biznesowych (np. wnioski, dyspozycje, reklamacje) bez potrzeby kodowania po stronie backendu.<br>

## Case Management Designer

### **Opis**

`Case Management Designer` służy do konfigurowania ekranów aplikacji Case Management – w tym list zadań, list spraw, widoków szczegółowych oraz układów kafelkowych.\
Pozwala w pełni dostosować warstwę prezentacyjną pracy użytkownika operacyjnego.

### **Funkcjonalność**

* Definiowanie widoków list zadań i spraw (kolumny, filtry, sortowanie).
* Tworzenie layoutów ekranów i rozmieszczenia mikroaplikacji.
* Wskazywanie mikrofrontendów uruchamianych w odpowiednich kontekstach.
* Projektowanie kafelków wizualnych (tiles) i dashboardów menedżerskich.
* Integracja z Eximee Repository dla publikacji i migracji konfiguracji.<br>

## Configuration

### **Opis**

`Configuration` to moduł służący do centralnego zarządzania konfiguracją biznesową aplikacji low-code.\
Pozwala definiować wartości konfiguracyjne, które mogą być wykorzystywane przez inne komponenty aplikacji.

### **Funkcjonalność**

* Definiowanie wartości prostych, list, obiektów.
* Wersjonowanie i migracja konfiguracji między środowiskami.
* Kontrola uprawnień i dostępów do parametrów konfiguracyjnych.
* Integracja z Eximee Configuration Server dla dynamicznego ładowania konfiguracji w runtime.<br>

## Cechy wspólne i parametry wdrożeniowe

* **Spójność środowiska:** wszystkie narzędzia współdzielą Eximee Repository i jednolity model autoryzacji.
* **Low-Code by Design:** każdy element aplikacji tworzony jest wizualnie, z możliwością rozszerzenia o skrypty.
* **Bezpieczeństwo:** pełna autoryzacja użytkowników projektowych (AD/LDAP), kontrola wersji i audyt zmian.
* **Reużywalność:** komponenty (formularze, modele, procesy) mogą być współdzielone między aplikacjami.
* **Wersjonowanie i migracje:** wsparcie dla cyklu życia aplikacji w środowiskach DEV–UAT–PROD.
* **Personalizacja:** możliwość dostosowania layoutu narzędzi do potrzeb zespołów projektowych.


# Eximee API

**Eximee API** to zunifikowana warstwa integracyjna platformy Eximee, która dzieli się na:

1. **EximeeBPMS API** – obsługa procesów, zadań i historii w ujęciu BPMN 2.0.
2. **Eximee API** – dostęp do statusów spraw, generatora dokumentów, modelu danych, konfiguracji oraz powiadamiania o zdarzeniach.

## EximeeBPMS API

### Rola i architektura

Interfejs do uruchamiania i nadzoru instancji procesów, zarządzania zadaniami użytkownika i automatycznymi, komunikacji zdarzeniowej oraz przeglądu historii spraw. Zaprojektowany do współpracy z EximeeBPMS oraz innymi silnikami implementującymi BPMN 2.0.

### Zakres funkcjonalny

* **Instancje procesów**\
  • start instancji procesu (z separacją danych biznesowych i procesowych),\
  • pobranie szczegółów instancji (w tym zmienne procesowe i biznesowe).
* **Zmienne procesowe**\
  • zmiana wartości zmiennej procesowej.
* **Zadania użytkownika (User Tasks)**\
  • pobranie danych procesowych i biznesowych,\
  • zmiana stanu,\
  • zatwierdzenie wraz z przesłaniem zmiennych,\
  • zarządzanie przypisanym użytkownikiem.
* **Zadania automatyczne (Service Tasks)**\
  • asynchroniczna obsługa service tasków.
* **Komunikacja zdarzeniowa**\
  • wysyłka wiadomości (message) do procesu.
* **Incydenty**\
  • pobranie informacji o incydencie,\
  • ponawianie zadania, na którym wystąpił incydent.
* **Listy i historia**\
  • lista zadań, lista procesów, historia sprawy.

### Integracje

* **Eximee Forms** – formularze jako interfejs do user tasków.
* **Eximee Case Management** – prezentacja list zadań/spraw i historii.
* **Eximee Data Model Runtime** – odczyt/zapis danych biznesowych w toku procesu.
* **Eximee Dashboard** – warstwa UI dla użytkowników operacyjnych.

### Bezpieczeństwo i zgodność

* OAuth 2.0 / OIDC (JWT), role domenowe, audyt operacji.
* TLS 1.2+; rate limiting i zasada „least privilege”.

### Przykładowe scenariusze

* Start procesu z CRM i śledzenie statusu instancji.
* Zatwierdzenie user tasku z przekazaniem zmiennych.
* Ponowienie incydentu service tasku.

## Eximee API

### Rola i architektura

Interfejsy ogólne platformy niezwiązane bezpośrednio z wykonaniem procesu: status sprawy, generator dokumentów, model danych, konfiguracja oraz powiadamianie o zdarzeniach.

### Zakres funkcjonalny (tylko metody z dokumentu)

* **Status sprawy**\
  • utworzenie statusu,\
  • aktualizacja statusu,\
  • pobranie statusu.
* **Generator dokumentów**\
  • zlecenie generowania dokumentów na podstawie dostarczonych danych (z opcją użycia modelu danych).
* **Model danych aplikacji**\
  • dostęp do **struktury** modelu,\
  • dostęp do **danych** (odczyt).
* **Konfiguracja aplikacji**\
  • **read-only** dostęp do konfiguracji.
* **Powiadomienia o zdarzeniach z domen zewnętrznych**\
  • powiadamianie platformy o zdarzeniach w zewnętrznych domenach obsługujących procesy.

### Integracje

* **Eximee Document Generator** – realizacja zleceń generacji dokumentów.
* **Eximee Model Runtime** – udostępnianie struktury/danych aplikacji.
* **Eximee Configuration Server** – read-only konfiguracja.
* **Systemy zewnętrzne** – zgłaszanie zdarzeń domenowych.

### Bezpieczeństwo i zgodność

* OAuth 2.0 / OIDC (JWT), role domenowe, audyt dostępu.
* TLS 1.2+; rate limiting; wersjonowanie API (np. `/v1/...`).

### Przykładowe scenariusze​

* CRM odczytuje strukturę i dane z modelu oraz aktualny status sprawy.
* System scoringowy zgłasza zdarzenie, które uruchamia dalsze kroki po stronie Eximee.


# Rozszerzenia platformy


# Eximee Customer Panel

**Eximee Customer Panel** jest kanałem zdalnego dostępu do procesów bankowych realizowanych na platformie Eximee.\
Umożliwia bezpieczne uczestnictwo w procesach osobom, które:

* nie są jeszcze klientami banku,
* są klientami banku, lecz w danym procesie uczestniczą bez logowania do bankowości elektronicznej.

Dzięki temu stanowi elastyczne rozszerzenie architektury Eximee o scenariusze obsługi klientów zewnętrznych, współwnioskodawców i osób trzecich.

## Problem biznesowy i potrzeba rozwiązania

W wielu procesach bankowych (np. kredytowych, ubezpieczeniowych czy wspólnych wnioskach) konieczne jest zaangażowanie więcej niż jednej osoby: współmałżonka, wspólnika, współkredytobiorcy.\
Każdy z uczestników musi wykonać określone czynności, takie jak:

* załączenie dokumentów,
* wyrażenie zgód i złożenie oświadczeń,
* wypełnienie ankiet,
* autoryzacja czynności,
* potwierdzenie tożsamości,
* złożenie podpisu.

**Eximee Customer Panel** umożliwia im dostęp wyłącznie do własnego zakresu sprawy - tylko do tych dokumentów, formularzy i działań, które są im przypisane.\
Panel pozwala na równoległą i bezpieczną realizację zadań przez wielu uczestników jednego procesu.

## Przykład zastosowania

### Proces kredytowy z wieloma wnioskodawcami

1. Główny kredytobiorca inicjuje sprawę, wprowadza dane, dołącza dokumenty i wskazuje współkredytobiorców (numery telefonów, PESEL).
2. Silnik procesu określa, jakie czynności mają wykonać poszczególni uczestnicy.
3. Każdy z nich otrzymuje wiadomość SMS z linkiem i kodem OTP do zalogowania się do **Eximee Customer Panel**.
4. Współkredytobiorcy logują się, podając:
   * numer sprawy,
   * fragment numeru PESEL,
   * kod OTP z wiadomości.
5. W panelu widzą:
   * status sprawy,
   * dokumenty, które ich dotyczą,
   * listę czynności do wykonania.
6. Wykonują przypisane zadania: potwierdzają tożsamość, przesyłają dokumenty, zatwierdzają wniosek.

> Przykładowy ekran widoczny po zalogowaniu użytkownika

<figure><img src="/files/d5kehCBMFmog78slZKOa" alt=""><figcaption></figcaption></figure>

## Zalety rozwiązania

* Obsługa procesów z udziałem **wielu osób jednocześnie**, przy zachowaniu pełnej kontroli logicznej procesu.
* **Dostęp bez logowania** do bankowości elektronicznej.
* **Bezpieczeństwo** (OTP, PESEL, numer sprawy).
* Możliwość pracy **równoległej i asynchronicznej** uczestników.
* Izolacja danych – każdy uczestnik widzi tylko swoją część sprawy.

## Integracja z podejściem Omnichannel

Customer Panel jest integralną częścią strategii **Omnichannel** platformy Eximee.\
Sprawa może zostać rozpoczęta w dowolnym kanale (np. w placówce, bankowości internetowej, przez call center), a następnie kontynuowana w Customer Panelu.\
Wszystkie kanały wykorzystują ten sam model danych i mechanizmy procesowe, co zapewnia pełną spójność doświadczenia klienta.

## Logowanie i bezpieczeństwo

Logowanie do Customer Panel odbywa się „do sprawy”, a nie do konta.\
Użytkownik podaje:

* numer sprawy,
* fragment numeru PESEL (np. 4 ostatnie cyfry),
* jednorazowy kod OTP z wiadomości SMS.

Po zalogowaniu użytkownik ma dostęp do:

* bieżącego statusu sprawy,
* dokumentów i instrukcji,
* informacji o kolejnych krokach,
* danych z Bazy Wiedzy / FAQ,
* informacji o działaniach banku i innych uczestników.

W przypadku zadań wymagających akcji użytkownik może natychmiast przejść do odpowiedniego formularza.

## Finalizacja sprawy

Dostęp do Panelu może być utrzymany również po zakończeniu procesu, np.:

* do momentu założenia produktów,
* do wygaśnięcia sprawy po decyzji negatywnej,
* do czasu archiwizacji wniosku.

Bank konfiguruje:

* czas dostępności danych po zamknięciu sprawy,
* zakres informacji i dokumentów widocznych po finalizacji.

## Tworzenie i utrzymanie zawartości

**Eximee Customer Panel** jest rozwiązaniem **generycznym i low-code**, w pełni zgodnym z bankowym **Design Systemem** i standardami **WCAG**.\
Ekrany są projektowane w **Eximee Designer** - tak samo jak formularze Eximee Forms, co oznacza:

* wspólną ścieżkę wdrożeniową i proces publikacji,
* wykorzystanie istniejących komponentów i logiki,
* możliwość szybkich zmian on-demand.

Panel jest **responsywny (RWD)**, dzięki czemu działa identycznie na desktopie i urządzeniach mobilnych.

## Kluczowe cechy Eximee Customer Panel

* Dostęp dla klientów niezalogowanych.
* Prezentacja statusu biznesowego procesu wraz z dodatkowymi informacjami o etapach i opcjach.
* Lista wymaganych dokumentów i załączników.
* Możliwość wykonywania zadań użytkownika w procesie (np. wyrażenie zgody, przesłanie plików).
* Pełna zgodność UX/UI z Design Guide banku.
* Obsługa urządzeń mobilnych (RWD).
* Wsparcie dostępności (WCAG).
* Konfigurowalność i personalizacja per typ sprawy - realizowana low-code’em w Eximee Designerze.

## Podsumowanie

**Eximee Customer Panel** to rozszerzenie platformy Eximee umożliwiające realizację procesów bankowych z udziałem klientów niezalogowanych i osób trzecich.\
Łączy **bezpieczeństwo**, **wygodę** i **elastyczność low-code**, oferując bankowi szybkie wdrożenia i pełną kontrolę nad doświadczeniem użytkownika.\
Stanowi kluczowy komponent w realizacji podejścia **Omnichannel** w bankowości opartej na Eximee.


# Customer Service Zone

**Eximee Customer Service Zone** to komponent obsługowy platformy Eximee, zaprojektowany do integracji aplikacji procesowych w istniejących systemach bankowych — zarówno w kanałach samoobsługowych (self-service), jak i wspieranych przez pracowników (assisted channels).\
Jego celem jest zapewnienie klientom i pracownikom banku **spójnego, jednolitego doświadczenia** w zakresie obsługi spraw, niezależnie od używanego kanału dostępu.

## Przeznaczenie i rola komponentu

Customer Service Zone pełni rolę **warstwy prezentacyjno-nawigacyjnej**, która łączy różne aplikacje procesowe w jeden, intuicyjny ekosystem obsługi spraw klienta.\
Umożliwia:

* uruchamianie procesów w różnych systemach bankowych,
* przekierowanie użytkownika do właściwych formularzy, funkcji lub ekranów w systemach docelowych z zachowaniem kontekstu,
* spójne grupowanie procesów i nawigację,
* dostęp do spraw w zależności od uprawnień użytkownika (klient lub pracownik).

## Uniwersalny dostęp w wielu kanałach

Strefa Obsługi Klienta może być uruchamiana w różnych kontekstach, dostosowując się do potrzeb i uprawnień użytkownika.\
Dzięki temu wspiera pełną integrację z istniejącą infrastrukturą bankową oraz strategię **Omnichannel**.

### Dostępne konteksty

* **Portal publiczny** – dostęp dla użytkowników niezalogowanych (np. rozpoczęcie wniosku lub procesu onboardingu).
* **Bankowość internetowa i mobilna** – pełna funkcjonalność dla klientów zalogowanych z uwzględnieniem kontekstu klienta i jego produktów.

<figure><img src="/files/yZ17jnMaRrAMVI4KA0GV" alt=""><figcaption></figcaption></figure>

* **Kanały wspierane przez pracowników (assisted channels)** – dostęp z poziomu aplikacji pracowniczych, uwzględniający uprawnienia operatora oraz kontekst reprezentowanego klienta.

<figure><img src="/files/rw15XGIHDzNxC4ycJEUZ" alt=""><figcaption></figcaption></figure>

Dzięki konfiguracji startowej (Starter Configuration), Customer Service Zone automatycznie rozpoznaje kontekst, w którym użytkownik działa, i przekierowuje go do odpowiedniego procesu, formularza lub systemu bankowego.

## Intuicyjna organizacja i nawigacja

Komponent oferuje użytkownikom szybki dostęp do procesów możliwych do realizacji w danym kanale.

### Główne elementy

* **Grupowanie procesów** – organizacja w logiczne kategorie odpowiadające:
  * obszarom biznesowym lub tematycznym (np. Kredyty, Transakcje, Karty),
  * typom produktów lub spraw (np. Kredyt hipoteczny, Reklamacja karty, Konto firmowe).\
    Grupy te wykorzystywane są przy budowie ekranów i nawigacji w obrębie Strefy Obsługi.
* **Panel szybkiego dostępu** – zestaw najważniejszych procesów lub funkcji zawsze dostępnych „pod ręką”, np. rozpoczęcie wniosku, przegląd statusów czy kontakt z doradcą.

<figure><img src="/files/JU9lXGZXkYldXNmgPBEi" alt=""><figcaption></figcaption></figure>

## Uruchamianie procesów w wielu systemach

**Eximee Customer Service Zone** umożliwia wywoływanie procesów realizowanych w różnych systemach bankowych, zarówno w platformie Eximee, jak i poza nią.\
Dzięki mechanizmowi **kontekstowego przekierowania**, użytkownik przenoszony jest bezpośrednio do właściwego miejsca realizacji procesu – np. formularza w Eximee, funkcji w systemie CRM czy dedykowanego ekranu w bankowości elektronicznej.\
Przy tym zachowywany jest:

* kontekst klienta,
* kontekst produktu lub oferty,
* kontekst sprawy (ID, status, parametry przekazania).

## Wyszukiwanie i filtrowanie procesów

Customer Service Zone zawiera **zaawansowaną wyszukiwarkę procesów**, która umożliwia szybkie odnalezienie potrzebnej funkcji lub sprawy.\
Cechy:

* wyszukiwanie w czasie rzeczywistym podczas wpisywania,
* dopasowanie po nazwach, opisach i grupach procesów,
* tolerancja na literówki i brak znaków diakrytycznych,
* obsługa słów kluczowych (tagów) – np. „kredyt”, „konto firmowe”, „reklamacja”.

## Spójność wizualna i branding

Wygląd i styl komponentu są w pełni dostosowywane do identyfikacji wizualnej banku.\
Stylizacja jest opracowywana wspólnie z zespołem **UI/UX banku** i zgodna z jego **Design Systemem**, dzięki czemu Customer Service Zone pozostaje wizualnie spójna z innymi kanałami, aplikacjami i systemami frontowymi.

## Kluczowe cechy Eximee Customer Service Zone

* Integracja z istniejącymi systemami bankowymi (portale, bankowość, CRM).
* Możliwość pracy w różnych kanałach – publicznym, zalogowanym i pracowniczym.
* Grupowanie i filtrowanie procesów według typu, obszaru i produktu.
* Panel szybkiego dostępu do najczęściej wykorzystywanych funkcji.
* Wsparcie dla kontekstowego uruchamiania procesów w wielu systemach.
* Stylizacja zgodna z Design Systemem banku.
* Responsywność (RWD) i dostępność (WCAG).
* Elastyczna konfiguracja i rozszerzalność bez potrzeby zmian kodu.

## Podsumowanie

**Eximee Customer Service Zone** stanowi centralny punkt kontaktu klienta i pracownika z procesami biznesowymi banku.\
Łączy elastyczność low-code z integracją systemową, zapewniając szybki dostęp do procesów, dokumentów i spraw niezależnie od kanału dostępu.\
Dzięki temu staje się fundamentem nowoczesnej architektury obsługi klienta w podejściu **Omnichannel**, gwarantując spójne doświadczenie użytkownika w całym ekosystemie banku.


# Eximee Case Repository

**Eximee Case Repository** to centralne repozytorium spraw klientów banku, stanowiące wspólny punkt odniesienia dla wszystkich kanałów i aplikacji obsługujących procesy klienta.\
Jego głównym zadaniem jest **przechowywanie, udostępnianie i śledzenie historii kontaktów oraz statusów spraw** niezależnie od tego, w jakim systemie zostały zainicjowane lub realizowane.

## Rola i przeznaczenie

Eximee Case Repository pełni funkcję **warstwy integracyjnej i archiwizującej**, umożliwiającej spójny wgląd w statusy i dane spraw z wielu źródeł.\
Repozytorium gromadzi dane o wszystkich interakcjach klienta z bankiem — zarówno tych obsługiwanych automatycznie przez systemy, jak i realizowanych przez pracowników.\
Dzięki temu możliwe jest:

* zachowanie pełnej historii spraw klienta,
* budowa konsolidowanego widoku „360°” klienta,
* prezentacja aktualnych statusów i aktywności niezależnie od kanału obsługi.

## Zakres funkcjonalny

### Główne funkcje Case Repository

* **Przechowywanie spraw klientów** – utrwalanie danych o sprawach pochodzących z różnych aplikacji bankowych, niezależnie od technologii i kanału.
* **Rejestr historii działań** – zapis wszystkich akcji wykonanych przez użytkowników i systemy w kontekście konkretnej sprawy.
* **Agregacja danych** – łączenie informacji z procesów Eximee BPMS, formularzy, API oraz systemów zewnętrznych.
* **Ujednolicony model danych** – każdy obiekt sprawy jest zgodny ze wspólnym schematem danych (data model) stosowanym w całej platformie Eximee.
* **Publikacja danych o sprawach** – wystawianie informacji o sprawach do wyświetlenia w różnych kanałach, np. CRM, bankowości elektronicznej czy aplikacjach back-office.

## Zasady działania i integracja danych

Dowolne aplikacje obsługujące procesy klienta — zarówno tworzone w **Eximee Low-Code Platform**, jak i systemy niezależne banku — mogą zasilać **Case Repository** danymi.\
Aby to zrobić, muszą:

1. utworzyć obiekt zgodny ze wspólnym modelem danych,
2. opublikować go w repozytorium za pomocą mechanizmu zdarzeniowego (np. **Apache Kafka**).

Repozytorium działa w oparciu o **architekturę event-driven**, dzięki czemu aktualizacje statusów i zdarzeń są przetwarzane w czasie rzeczywistym i propagowane do wszystkich zainteresowanych systemów.

## Prezentacja i wykorzystanie danych

Lista spraw klienta, wraz z ich statusami biznesowymi, może być:

* wyświetlana jako **mikrofrontend** w aplikacjach klienckich (np. bankowość internetowa, mobilna),
* wbudowana w aplikacje pracowników banku (np. CRM, Contact Center, Back-Office),
* udostępniana zewnętrznym systemom za pośrednictwem Eximee API.

Takie podejście zapewnia jednolite doświadczenie użytkownika i centralny dostęp do informacji o wszystkich procesach klienta.

## Architektura i przepływ informacji

**Eximee Case Repository** stanowi centralny element architektury informacyjnej platformy.\
Dane o sprawach:

1. **powstają** w różnych komponentach (BPMS, Forms, API, Customer Panel, Service Zone),
2. **są agregowane** i publikowane w Case Repository,
3. **udostępniane** są do innych modułów oraz systemów zewnętrznych w formie ustrukturyzowanego obiektu „Case”.

Repozytorium może być wykorzystywane zarówno w trybie **online** (prezentacja aktywnych spraw), jak i **archiwalnym** (historia spraw zakończonych).

## Model danych

Każdy rekord w **Eximee Case Repository** posiada ujednolicony model danych zawierający m.in.:

* identyfikator sprawy (Case ID),
* dane klienta i kontekst produktu,
* status i etap procesu,
* metadane (daty utworzenia, aktualizacji, zamknięcia),
* listę zdarzeń i działań,
* powiązania z dokumentami i procesami (BPMN, Forms).

Model jest spójny z definicjami danych przechowywanych w **Eximee Data Model Runtime**, co umożliwia bezproblemową integrację między komponentami.

## Bezpieczeństwo i dostęp

* **Autoryzacja:** oparcie o role domenowe i kontekst organizacyjny.
* **Dostępność:** kontrola widoczności spraw względem użytkownika i kanału.
* **Integracja z Eximee Security Framework:** dziedziczenie zasad autoryzacji z platformy.
* **Audyt:** każda operacja publikacji i odczytu jest rejestrowana.
* **Szyfrowanie danych wrażliwych:** TLS 1.2+ oraz integracja z bankowym KeyVault.

## Kluczowe cechy Eximee Case Repository

* Centralne repozytorium wszystkich spraw klienta.
* Obsługa danych z wielu źródeł – procesów Eximee i systemów zewnętrznych.
* Jednolity model danych (Case Data Model).
* Architektura oparta na zdarzeniach (event-driven).
* Wsparcie dla mikrofrontendów i integracji wielokanałowej.
* Pełne bezpieczeństwo i audyt.
* Skalowalność i wysoka dostępność.
* Zgodność z podejściem Omnichannel.

## Podsumowanie

**Eximee Case Repository** stanowi kluczowy element integracyjny ekosystemu Eximee.\
Zapewnia centralne źródło prawdy o wszystkich sprawach klienta, niezależnie od tego, w jakim systemie lub kanale zostały utworzone.\
Dzięki temu umożliwia budowę spójnych widoków klienta, automatyzację procesów i zwiększenie efektywności obsługi.\
Jest fundamentem dla raportowania, analiz oraz komunikacji między kanałami w architekturze **Omnichannel Banking**.


# Aplikacja biznesowa

## Aplikacja biznesowa na platformie Eximee

Aplikacja biznesowa w Eximee Low-Code Platform to kompletne rozwiązanie realizujące określony cel – np. proces sprzedażowy, onboarding klienta, czy obsługę posprzedażową. Tworzy ją zestaw powiązanych ze sobą elementów (artefaktów), które wspólnie definiują sposób działania aplikacji, interakcję z użytkownikiem, logikę przetwarzania i przepływ danych.

### Cztery kluczowe obszary aplikacji biznesowej

Każda aplikacja opiera się na czterech podstawowych elementach: **modelu danych**, **procesie biznesowym**, **logice aplikacji** oraz **warstwie front-end**. Elementy te można łączyć w zależności od potrzeb – nie każda aplikacja wymaga ich wszystkich.

<figure><img src="/files/I4lJrgwPMkCBnstEZItn" alt=""><figcaption></figcaption></figure>

### Model danych

Model danych definiuje strukturę informacji wykorzystywanych w aplikacji – od danych klienta, przez parametry produktu, po statusy procesowe. Stanowi punkt odniesienia dla wszystkich innych komponentów: formularzy, procesów, skryptów i integracji. Zapewnia spójność danych oraz ułatwia rozwój i utrzymanie aplikacji w czasie. Dzięki niemu dane są traktowane w sposób jednolity i kontrolowany – niezależnie od miejsca ich wykorzystania.

> Więcej na temat struktury i zarządzania modelem danych przeczytasz w rozdziale [Budowanie aplikacji - Model danych](/budowanie-aplikacji/model-danych)

### Proces biznesowy

Procesy w Eximee odwzorowują przebieg pracy aplikacji – od inicjacji przez klienta, po zakończenie sprawy lub wydanie decyzji. Mogą obejmować zarówno działania automatyczne (np. integracje, reguły decyzyjne), jak i zadania wykonywane przez użytkowników. Tworzone są w postaci graficznego modelu BPMN, co ułatwia zrozumienie logiki procesu i jego modyfikację. Procesy mogą być proste lub rozbudowane – z warunkami, równoległymi ścieżkami i podprocesami – w zależności od potrzeb.

> Opis modelowania i konfiguracji procesów znajdziesz w rozdziale [Budowanie aplikacji - Proces biznesowy](/budowanie-aplikacji/proces-biznesowy)

### Logika aplikacji i integracje

Logika aplikacji obejmuje reguły działania, które określają jak aplikacja reaguje na dane, zdarzenia i interakcje użytkowników. Może być realizowana przy pomocy skryptów (np. obliczenia, walidacje, formatowanie danych), jak również przez automatyczne kroki w procesach. Integralną częścią logiki są integracje z systemami zewnętrznymi – takimi jak CRM, scoring, rejestry publiczne czy systemy obsługi dokumentów. W Eximee możliwe jest budowanie tych integracji w sposób konfigurowalny, bez konieczności kodowania usług.

> Szczegółowe informacje o skryptach, walidacjach i integracjach dostępne są w rozdziale [Budowanie aplikacji - Logika biznesowa](/budowanie-aplikacji/logika-biznesowa)

### Front-end – formularze i interfejs użytkownika

Warstwa front-end to formularze i ekrany, które są widoczne dla użytkownika – klienta lub pracownika banku. Umożliwiają one wprowadzanie i przetwarzanie danych, prezentację informacji oraz realizację zadań w ramach procesów. Formularze są budowane w graficznym edytorze i mogą być wykorzystywane wielokrotnie – w różnych kontekstach i kanałach. Dzięki integracji z modelem danych i logiką aplikacji, interfejs staje się dynamiczny i kontekstowy – dopasowuje się do sytuacji użytkownika oraz etapu procesu.

> Budowa formularzy, komponentów i interfejsu użytkownika została omówiona w rozdziale [Budowanie aplikacji - Interfejs użytkownika](/budowanie-aplikacji/interfejs-uzytkownika)

### Spójne, modułowe podejście

Wszystkie cztery obszary – model danych, proces, logika i interfejs – są ze sobą powiązane, ale mogą być rozwijane niezależnie. Dzięki temu aplikacje tworzone na Eximee są modularne, łatwe do testowania i ponownego użycia. Platforma umożliwia też centralne [zarządzanie ich wersjami](/budowanie-aplikacji/aplikacja-biznesowa/wersjonowanie), publikowanie zmian bez przerywania działania oraz szybkie dostosowywanie do zmieniających się wymagań biznesowych i regulacyjnych.


# Obsługiwane kanały

## Kanały i konteksty uruchamiania aplikacji

Platforma Eximee została zaprojektowana z myślą o elastycznej obsłudze procesów w różnych kanałach kontaktu z klientem i pracownikiem banku. Dzięki temu aplikacje tworzone na platformie mogą działać spójnie w całym środowisku bankowym – niezależnie od miejsca uruchomienia.

### Kanały techniczne

Kanał techniczny definiuje środowisko, w którym uruchamiana jest część front-end'owa aplikacji – np. formularz, ekran zadania czy widok panelu klienta. To właśnie kanał techniczny decyduje o sposobie osadzenia i wyświetlenia aplikacji użytkownikowi.

Typowe kanały techniczne to:

* **bankowość internetowa** (desktop),
* **aplikacja mobilna**,
* **system CRM lub wewnętrzny portal pracowniczy**,
* **kanał partnera** (np. agent zewnętrzny),
* **publiczny portal banku** (dla klientów niezalogowanych).

Dzięki unifikacji komponentów i dostosowaniu wizualnemu do kanału hostującego, Eximee zapewnia spójne doświadczenie użytkownika we wszystkich tych środowiskach.

### Konteksty biznesowe (kanały biznesowe)

Oprócz kanału technicznego, aplikacja działa zawsze w określonym kontekście biznesowym. Ten kontekst obejmuje:

* **tożsamość i rolę użytkownika** (np. klient, doradca, partner),
* **warunki działania** (zalogowany/niezalogowany, działanie z uprawnieniami klienta lub własnymi),
* **zakres dostępnych danych i funkcji**.

Połączenie kanału technicznego i kontekstu działania tworzy tzw. **kanał biznesowy**.

Przykłady kanałów biznesowych:

* klient indywidualny zalogowany w bankowości internetowej,
* pracownik banku w CRM obsługujący wniosek w imieniu klienta,
* klient wypełniający formularz na publicznej stronie banku (bez logowania),
* użytkownik autoryzujący dyspozycję w aplikacji mobilnej,
* partner zewnętrzny inicjujący proces w imieniu klienta.

Definiowanie kanałów biznesowych pozwala na precyzyjne sterowanie logiką, uprawnieniami, widocznością komponentów oraz danymi dostępnymi w ramach procesu – zależnie od sytuacji, w której aplikacja jest uruchamiana.

### Wielokanałowość a omnikanałowość

Warto rozróżnić dwa podejścia do projektowania aplikacji w wielu kanałach:

* **Wielokanałowość** (multichannel):\
  Ten sam formularz lub proces jest dostępny w wielu kanałach technicznych – np. aplikacji mobilnej i bankowości internetowej – ale działa niezależnie w każdym z nich. Użytkownik musi zakończyć sprawę w tym samym kanale, w którym ją rozpoczął.
* **Omnikanałowość** (omnichannel):\
  Aplikacja umożliwia kontynuację tego samego procesu w różnych kanałach i kontekstach. Klient może rozpocząć wniosek w bankowości internetowej, dokończyć w aplikacji mobilnej, a ostatecznie zatwierdzić go wspólnie z doradcą w oddziale – cały czas w ramach tej samej sprawy, z zachowaniem pełnego kontekstu i historii.

Eximee wspiera oba podejścia, przy czym architektura platformy i centralne repozytorium danych umożliwiają efektywne wdrażanie rozwiązań omnikanałowych – z synchronizacją postępu, zadań i informacji między kanałami.

### Podsumowanie

Dzięki rozróżnieniu kanałów technicznych i biznesowych, platforma Eximee pozwala tworzyć elastyczne, kontekstowe i spójne aplikacje bankowe działające w całym ekosystemie instytucji. Projektanci aplikacji mogą precyzyjnie kontrolować zachowanie aplikacji w różnych środowiskach i dostosowywać je do roli oraz potrzeb użytkownika końcowego.


# Obszary zastosowania

Poniżej przedstawiono główne obszary, w których Eximee Low-Code Platform jest obecnie wykorzystywana w bankach.

## Cyfrowy onboarding i KYC

Budowa procesów umożliwiających zdalne otwieranie produktów bankowych i spełnienie wymogów identyfikacyjnych:

* onboarding konta osobistego i firmowego,
* weryfikacja tożsamości i aktualizacja danych w ramach KYC,
* zdalna rejestracja działalności gospodarczej zintegrowana z zakładaniem konta SME,
* aktualizacja danych klienta w bankowości internetowej.

## Sprzedaż produktów bankowych

Uruchamianie w pełni cyfrowych procesów pozyskiwania klientów i sprzedaży produktów:

* wnioski o konto osobiste, firmowe lub oszczędnościowe,
* kredyty i pożyczki gotówkowe,
* kredyty hipoteczne,
* sprzedaż ubezpieczeń lub kart kredytowych.

## Bankowość samoobsługowa i obsługa posprzedażowa

Rozwój usług, które klienci mogą realizować samodzielnie, bez kontaktu z pracownikiem banku:

* składanie dyspozycji (np. zamówienie zaświadczenia, zmiana limitu),
* aktualizacja danych kontaktowych lub osobowych,
* zgłaszanie reklamacji i śledzenie ich statusu,
* generowanie dokumentów,
* procesy posprzedażowe (np. renegocjacja umowy kredytowej).

## Procesy wewnętrzne i zgodność z regulacjami (back-office)

Digitalizacja procesów organizacyjnych i wsparcie zgodności z regulacjami:

* narzędzie do oceny zgodności projektów z RODO (np. GDPR Check),
* obiegi akceptacyjne (np. wniosek o zatwierdzenie produktu, zmiany taryf),
* monitorowanie spełnienia polityk wewnętrznych i procedur,
* zarządzanie dokumentacją i decyzjami zgodnie z wymaganiami audytu.

## Narzędzia wspierające pracę pracowników banku

Budowa aplikacji wspierających codzienną pracę zespołów operacyjnych i doradców:

* aplikacja do obsługi renegocjacji kredytów hipotecznych,
* panele do zarządzania sprawami klientów (case management),
* kokpity zadań i dashboardy dla zespołów sprzedażowych i back-office,
* wsparcie rozdzielania spraw i zadań w centrach operacyjnych.

## Ankiety i badania satysfakcji (NPS, CES, CSAT)

* tworzenie i udostępnianie ankiet po procesach sprzedażowych i obsługowych,
* automatyczne uruchamianie formularzy NPS lub CES w zależności od kontekstu,
* integracja z silnikiem procesowym i kanałami komunikacji (e-mail, bankowość online).

## Projekty specjalne i integracja międzyinstytucjonalna

Realizacja niestandardowych lub pilnych projektów wymagających szybkiego wdrożenia i szerokiej integracji:

* wnioski o subwencje w ramach Tarczy Finansowej PFR (wdrożone w kilkunastu bankach w ciągu kilku tygodni),
* programy rządowe (np. 500+, tarcze antykryzysowe),
* kampanie specjalne banków wymagające masowego dotarcia do klientów (np. migracje, zbieranie zgód, potwierdzenia danych).


# Budowanie aplikacji


# Aplikacja biznesowa


# Zarządzanie aplikacją


# Tworzenie aplikacji

{% hint style="info" %}
Dostępność funkcjonalności właścicielstwa aplikacji zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

## Utworzenie aplikacji

Aby utworzyć nową aplikację, przejdź do modułu **Aplikacje**, a następnie kliknij przycisk **Dodaj aplikację**.\
Zostanie otwarte okno, w którym należy:

* wpisać nazwę aplikacji (zgodnie z zasadami opisanymi w rozdziale [Konwencje nazewnicze elementów aplikacji](/budowanie-aplikacji/aplikacja-biznesowa/elementy-aplikacji-artefakty/konwencje-nazewnicze-elementow-aplikacji))
* wybór właściciela - należy wskazać grupę odpowiedzialną za aplikację,
  * Zwykły użytkownik może wybrać wyłącznie grupy, do których należy.
  * [Menedżer Artefaktów](/budowanie-aplikacji/aplikacja-biznesowa/zarzadzanie-aplikacja/menedzer-artefaktow) posiada uprawnienia do przypisania dowolnej grupy dostępnej w systemie.
* opcjonalnie - dodać ikonę.

![Ilustracja 1. Okno tworzenia nowej aplikacji](/files/YNRYWSrqra5GVPdkjruR)

Kliknięcie przycisku **Dodaj aplikację** spowoduje utworzenie aplikacji i automatyczne przejście do zakładki **Formularze**. Nazwa nowo utworzonej aplikacji pojawi się w lewym górnym rogu okna.

![Ilustracja 2. Okno utworzonej aplikacji](/files/fa17ffd414156a141dcbd7aa4c6ba2b00396768b)

## Dodawanie lub importowanie formularza lub procesu

Po utworzeniu aplikacji kolejnym krokiem jest dodanie do niej formularzy i procesów.

{% hint style="info" %}
Do aplikacji dodajemy tylko formularze i procesy (pozostałe artefakty zależne dodadzą się automatycznie).
{% endhint %}

Aby dodać do aplikacji formularz/proces, będąc w zakładce **Formularze** lub **Procesy**, kliknij przycisk **Dodaj formularz/proces**. W wyświetlonym oknie masz możliwość dodania nowego formularza lub procesu (opcja **Nowy formularz/proces**) albo zaimportowania istniejącego z repozytorium (opcja **Importuj istniejący**). W zależności od wybranej opcji okno dodawania artefaktu wygląda inaczej. Poniżej opisano sposób dodawania formularza - dla procesu kroki są identyczne.

Nowe artefakty mogą być dodawane do aplikacji wyłącznie przez osobę należącą do **grupy właścicielskiej** danej aplikacji.

### Dodanie nowego formularza

Jeśli chcesz dodać do aplikacji nowo utworzony wniosek, postępuj jak przy standardowym tworzeniu formularza:

* ustal jego nazwę i lokalizację,
* opcjonalnie dodaj opis,
* wybór właściciela - wskaż grupę odpowiedzialną za aplikację,
  * Zwykły użytkownik może wybrać wyłącznie grupy, do których należy.
  * [Menedżer Artefaktów](/budowanie-aplikacji/aplikacja-biznesowa/zarzadzanie-aplikacja/menedzer-artefaktow) posiada uprawnienia do przypisania dowolnej grupy dostępnej w systemie.
* opcjonalnie zmień liczbę kolumn (domyślnie 16 kolumn).

![Ilustracja 3. Okno dodawania do aplikacji formularza z zaznaczoną opcją "Nowy formularz".](/files/7RelHWUbCwe4X4c64jiX)

Po kliknięciu przycisku **Dodaj wniosek** zostanie otwarte okno nowo tworzonego formularza wymagającego zapisu.

### Importowanie istniejącego formularza

Jeśli wcześniej utworzyłeś formularz, wybierz w oknie **Dodaj formularz** opcję **Importuj istniejący** i wpisz nazwę wniosku w polu wyszukiwania (wpisując kolejne znaki zawężasz listę szablonów). Po kliknięciu na nazwie wniosku zostanie on dodany do aplikacji. Dodanie do aplikacji istniejącego formularza spowoduje automatyczne zaciągnięcie wszystkich zależnych elementów, takich jak komponenty złożone, treści, słowniki czy walidatory.

![Ilustracja 4. Okno dodawania do aplikacji formularza z zaznaczoną opcją "Importuj formularz".](/files/af0003899d3a4b6cfc378f7614ade9d6065b3d30)

{% hint style="info" %}
Wszystkie artefakty wchodzące w skład aplikacji możesz zobaczyć w zakładce **Wszystko**.
{% endhint %}


# Eksport/import aplikacji

{% hint style="info" %}
Dostępność funkcjonalności właścicielstwa aplikacji zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

Funkcje eksportu i importu aplikacji umożliwiają przenoszenie gotowych rozwiązań biznesowych pomiędzy różnymi środowiskami, np. z developerskiego na testowe lub produkcyjne.

## Eksport aplikacji

Eksportowanie aplikacji w Eximee Designer służy do zapisania jej w formie pliku, który zawiera wszystkie artefakty wchodzące w skład aplikacji - formularze, procesy, komponenty złożone, skrypty, słowniki, treści i inne powiązane elementy.

Eksport jest dostępny po przejściu do modułu **Aplikacje** i wybraniu aplikacji z listy.\
Przycisk **Eksportuj artefakt** ![](/files/92bfd2e8f5b617cc4fd4b5a38b15b5a49a41d724) znajduje się w pasku w prawym górnym rogu ekranu i jest dostępny z poziomu każdej zakładki składowej aplikacji.

Po kliknięciu przycisku **Eksportuj artefakt** zostanie otwarte okno dialogowe, którego wygląd i zawartość będą się różnić w zależności od tego, czy jest to pierwszy, czy kolejny eksport aplikacji.

Po wykonaniu eksportu system wygeneruje plik z rozszerzeniem .artifact i pozwoli na zapisanie go lokalnie.

Eksportowana aplikacja **nie** zawiera informacji o właścicielstwie.

### Pierwsze wydanie

W oknie pierwszego eksportu należy dodać opis wersji oraz przejrzeć jakie artefakty, w jakiej wersji wejdą w skład aplikacji. Kliknięcie przycisku **Wydaj** spowoduje otwarcie okna systemowego pozwalającego na zapisanie artefaktu na dysku (z możliwością dodania komentarza do tworzonej wersji).

![Ilustracja 1. Okno pierwszego eksportu aplikacji](/files/7a167631889b3e03de3a6fe1df18a121c1262c18)

### Kolejny eksport

W oknie kolejnego eksportu otrzymamy informację o poprzednim eksporcie (datę oraz opis), a na liście zmian pojawi się lista różnic w stosunku do poprzedniego eksportu, czyli tych artefaktów, które zostały dodane, zmienione lub usunięte. W przypadku, gdy od poprzedniego eksportu nie było zmian, w miejscu listy zmian pojawi się komunikat o braku danych do wyświetlenia.

![Ilustracja 2. Okno kolejnego eksportu aplikacji z listą zmian od poprzedniego wydania.](/files/43b315162694563a0f247967b2551a83f733ae7b)

### Historia eksportów

Przycisk **Historia eksportów** ![](/files/509fb9849fc7f2e3681c75df47e1cab01f4e870f), umieszczony w pasku w prawym górnym rogu ekranu, pozwala na wyświetlenie okna dialogowego z historią wszystkich eksportów aplikacji wraz z datą, opisem i informacją o użytkowniku, który wykonał eksport.

![Ilustracja 3. Okno historii kolejnych wydań](/files/443d88eebabec9434f26f109e557166eb8563f49)

## Import aplikacji

Import aplikacji pozwala wczytać do Eximee Designer wcześniej wyeksportowany plik aplikacji.

{% stepper %}
{% step %}

#### Import wyeksportowanej aplikacji — krok 1

Na liście aplikacji kliknij w prawym górnym rogu przycisk **Importuj aplikację**:

<figure><img src="/files/DkdwLoIymqtU2rFn4Gv6" alt=""><figcaption><p><em><strong>Ilustracja 4.</strong> Zakładka "Aplikacje" z opcją importu</em></p></figcaption></figure>
{% endstep %}

{% step %}

#### Import wyeksportowanej aplikacji — krok 2

W otwartym oknie dialogowym umieść wyeksportowany artefakt (plik z rozszerzeniem .artifact), a następnie kliknij **Importuj**:

<figure><img src="/files/EO6G7oaouxygtQCB7t1X" alt=""><figcaption><p><em><strong>Ilustracja 5.</strong> Okno importu artefaktu aplikacji</em></p></figcaption></figure>
{% endstep %}
{% endstepper %}

Po zakończonym imporcie system wyświetla komunikat o powodzeniu operacji. Jeśli artefakt został wgrany do repozytorium po raz pierwszy, pojawi się informacja potwierdzająca jego poprawne zaimportowanie. W przypadku, gdy w repozytorium znajduje się już artefakt o tej samej nazwie, system poinformuje, że wybrana wersja artefaktu już istnieje, jednak import zostanie zakończony pomyślnie.

{% hint style="info" %}
Okno importu służy do wczytania do repozytorium dowolnego artefaktu pobranego wcześniej z Eximee Designer – nie musi to być aplikacja, może to być np. formularz, proces czy skrypt.

Należy pamiętać, że wersja artefaktu, który ma zostać zaimportowany, powinna być wyższa niż wersja tego samego artefaktu znajdującego się już w repozytorium środowiska (więcej o wersjonowaniu w: [Wersjonowanie](/budowanie-aplikacji/aplikacja-biznesowa/wersjonowanie)).
{% endhint %}

### Zasady weryfikacji właścicielstwa podczas importu

Proces importu aplikacji i jej artefaktów podlega następującym weryfikacjom właścicielstwa:

1. **Aktualizacja aplikacji:**\
   Przy imporcie wersji wyższej niż obecna na środowisku, użytkownik **musi** należeć do grupy właścicieli aktualnej aplikacji.
2. **Nowa aplikacja:**\
   Jeśli aplikacja nie istnieje na środowisku, import może wykonać każdy, ale aplikacja zostanie zaimporotwana **bez przypisanego właściciela**.
3. **Import artefaktów:**\
   W przypadku importowania aplikacji z artefaktami (formularze, modele danych i inne obiekty), które są w wyższej wersji niż obecnie na środowisku, użytkownik importujący **musi** posiadać uprawnienia właścicielskie do tych konkretnych artefaktów wewnątrz aplikacji.

[Menedżer Artefaktów](/budowanie-aplikacji/aplikacja-biznesowa/zarzadzanie-aplikacja/menedzer-artefaktow) jako jedyny może importować wszystkie aplikacje oraz jej artefakty bez ograniczeń.


# Usunięcie aplikacji

{% hint style="info" %}
Dostępność funkcjonalności właścicielstwa aplikacji zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

## Operacja usunięcia

Usunąć aplikacje może jedynie właściciel aplikacji lub [Menedżer Artefaktów](/budowanie-aplikacji/aplikacja-biznesowa/zarzadzanie-aplikacja/menedzer-artefaktow).\
W celu usunięcia aplikacji należy, będąc w oknie modułu **Aplikacje**, kliknąć na końcu wiersza danej aplikacji menu kontekstowe i wybrać opcję **Usuń**.

![Ilustracja 1. Opcja usunięcia aplikacji](/files/pLqZz5QxhW0P5RovO6yg)

## Przywrócenie usuniętej aplikacji

Jeśli aplikacja będzie zawierać jakieś składowe, to będzie można jeszcze ją przywrócić, klikając u dołu ekranu opcję **Przywróć**.

![Ilustracja 2. Opcja przywrócenia usuniętej aplikacji](/files/Xj68caHomObnUCTtMwQX)


# Zmiana właścicielstwa aplikacji

{% hint style="info" %}
Dostępność funkcjonalności właścicielstwa aplikacji zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

## Operacja zmiany właściciela

Uprawnienie do zmiany właściciela aplikacji posiada wyłącznie [Menedżer Artefaktów](/budowanie-aplikacji/aplikacja-biznesowa/zarzadzanie-aplikacja/menedzer-artefaktow). W przeciwieństwie do standardowych użytkowników, których zakres widoczności ograniczony jest do ich własnych grup, Menedżer Artefaktów dysponuje dostępem do wszystkich grup w systemie.\
W celu zmiany właściciela aplikacji należy z poziomu **Listy Aplikacji**, z menu kontekstowego konkretnej aplikacji, wybrać opcję **Zmień właściciela aplikacji**.

![Ilustracja 1. Opcja zmiany właściciela aplikacji](/files/hib9n1tXAdHXTcY76kGa)

Podczas zmiany właściciela należy:

* wybrać nowego właściciela,
* zapoznać się z ostrzeżeniem,
* potwierdzić chęć przekazania aplikacji

![Ilustracja 2. Okno zmiany właściciela aplikacji](/files/ZR8KJnIcJVwulXT5wQln)

Po poprawnej operacji nowy własciciel będzie widoczny w kolumnie "właściciel".

### Zasady zmiany właścicielstwa artefaktów aplikacji

* Jeśli artefakt należący do aplikacji **ma tego samego właściciela**, zmiana właściciela aplikacji spowoduje również zmianę właściciela artefaktu.
* W przypadku artefaktów należących do **innego właściciela** niż aplikacja, ich grupa właścicielska pozostanie bez zmian.


# Menedżer Artefaktów

{% hint style="info" %}
Dostępność funkcjonalności właścicielstwa aplikacji zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

**Menedżer Artefaktów** to rola systemowa, posiadająca nadrzędne uprawnienia do wszystkich aplikacji oraz ich artefaktów. Użytkownik z tą rolą jest uprawniony do edycji, zapisu, importu oraz zmiany właścicielstwa aplikacji, niezależnie od standardowych uprawnień.

## Konfiguracja roli

System identyfikuje Menadżera Artefaktów na podstawie odpowiedniej konfiguracji:

* **Parametr:** `DESIGNER_SECURITY_ARTIFACT_MANAGER_ROLE_NAME`
* **Wartość domyślna:** `DEV_TESTERS`

Każdy użytkownik posiadający rolę `DEV_TESTERS` jest automatycznie rozpoznawany jako Menedżer Artefaktów, co zapewnia mu pełny dostęp do każdej aplikacji oraz artefaktu.


# Uruchamianie aplikacji

Jeśli nie chcesz rozpocząć od uruchomienia formularza tylko aplikacji, to pierwszym krokiem, który należy wykonać będzie ustawienie **punktu startowego** aplikacji (formularza lub procesu).

## Ustawienie punktu startowego aplikacji

Ustawienie punktu startowego można wykonać bezpośrednio w module **Aplikacje** – w zakładkach **Formularze** lub **Procesy**.

{% hint style="info" %}
Do poprawnego uruchomienia aplikacji konieczne jest wcześniejsze utworzenie modelu danych opisane w [Model danych](/budowanie-aplikacji/model-danych).
{% endhint %}

### Ustawienie formularza jako punkt startowy aplikacji (zalecane) i uruchomienie aplikacji

Jako startowy możemy ustawić jeden z formularzy dodanych do danej aplikacji. Po wejściu do zakładki **Formularze** klikamy w menu kontekstowe odpowiedniego wniosku i wybieramy opcję **Ustaw punkt startowy**:

![Ilustracja 1. Menu kontekstowe z opcją ustawienia wniosku jako punkt startowy.](/files/2a158d5e7d07736bf701bfa3492a470f5da2054f)

{% hint style="warning" %}
Uwaga! Po zmianie wniosku startowego konieczny może być "invalidate cache" w webforms (jeśli aplikacja była już wcześniej uruchamiana). W tym celu należy wykonać poniższe polecenie cURL (zastąp UZYTKOWNIK i HASLO odpowiednimi danymi):
{% endhint %}

{% code title="Invalidate cache" %}

```bash
curl -u UZYTKOWNIK:HASLO -X POST "http://webforms-dev.consdata.local/cache/invalidate?cacheType=PUBLISHED_TEMPLATE"
```

{% endcode %}

Aby uruchomić aplikację np. o nazwie wiki\_przyklad\_app, należy użyć następującego linku:

```
https://przykladowy.link.demo/stkn=#/wiki_przyklad_app
```

Przy uruchomieniu aplikacji zostanie otwarty **wniosek**, który został ustawiony jako punkt startowy.

### Ustawienie procesu jako punkt startowy i uruchomienie aplikacji

{% hint style="info" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

W niektórych przypadkach aplikacja powinna rozpocząć się od procesu, który steruje logiką działania.

Aby ustawić proces jako punkt startowy po wejściu do zakładki **Procesy** klikamy w tzw. "szaszłyk" i w menu kontekstowym odpowiedniego procesu wybieramy opcję **Ustaw punkt startowy**:

![Ilustracja 2. Menu kontekstowe z opcją ustawienia procesu jako punkt startowy.](/files/04b2b9f2b82d3f18660d4af1f349a46ff951139a)

Jeśli jako punkt startowy aplikacji zostanie ustawiony proces zamiast wniosku dodatkowo w zakładce **Właściwości** formularza należy przejść do zakładki **Przepływy** i w sekcji [**Akcje**](https://wiki.consdata.pl/display/IED/Akcje) zdefiniować następujące zdarzenie:

* **Komponent obsługujący akcję:** np. *Trigger lub Page*
* **Rodzaj zdarzenia** *:* *zależne od wybranego komponentu wzbudzającego zmianę*
* **Akcja formularza:** *START\_APPLICATION*
* **Nazwa aplikacji:** nazwa aplikacji, która ma zostać uruchomiona (aplikacja uruchomi **proces** ustawiony jako punkt startowy) lub nazwa procesu, który ma zostać wystartowany
* **Przekieruj na kolejny krok procesu:** warunek *JAVASCRIPT* - określa, czy ma nastąpić automatyczne przekierowanie do kolejnego kroku (*user task*); domyślna wartość: *false.*

![Ilustracja 3. Przykład zdefiniowania akcji START\_APPLICATION uruchomionej po kliknięciu Triggera.](/files/6f80507faa155c3c1b581fb4d6a070cf46db3659)

*Uruchomienie aplikacji nastąpi po wywołaniu zdarzenia, które obsługuje akcję START\_APPLICATION.*

### Informacja o ustawionym punkcie startowym

Jeżeli wniosek lub proces jest punktem startowym aplikacji, wyświetlana jest informacja w postaci taga z flagą i napisem "Punkt startowy".

![Ilustracja 4. Przykład prezentowania ustawionego punktu startowego](/files/7IJeSURe9G9QSuMmpNKq)


# Dokumentowanie aplikacji

{% stepper %}
{% step %}

### Utworzenie dokumentacji

W zakładce **Dokumentacja** należy użyć przycisku **Dodaj dokumentację**, a następnie podać nazwę tworzonej dokumentacji.

Wpis powinien zawierać biznesowy opis zmiany - skierowany do osób nietechnicznych oraz osób zainteresowanych produktem od strony biznesowej.

<figure><img src="/files/NWDkZPHquCBWsF9CgRPC" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Okno tworzenia dokumentacji</em></p></figcaption></figure>
{% endstep %}

{% step %}

### Edycja dokumentacji

Aby edytować istniejącą dokumentację, należy wejść w dokumentację i kliknąć przycisk **Edytuj dokumentację** ![Ilustracja 2](/files/d3ceadd2360fe4a6ef276b024a85b3aca4fba4fc).

Okno edycji jest podzielone na część tworzenia i podglądu. Pomiędzy ekranami znajduje się pasek umożliwiający zmianę szerokości obu części.

<figure><img src="/files/UEDccsN4S6AKSyEbXZed" alt=""><figcaption><p><em><strong>Ilustracja 2.</strong> Okno edycji dokumentacji</em></p></figcaption></figure>
{% endstep %}

{% step %}

### Tworzenie wpisów — składnia markdown

Wpisy tworzymy używając znaczników [markdown](https://www.markdownguide.org/basic-syntax/). Okno dokumentacji zawiera edytor markdown z podglądem.

Przykładowa dokumentacja z użyciem markdown (przykładowy materiał pokazujący różne elementy składni):

{% code fullWidth="false" expandable="true" %}

```markdown
# Markdown syntax guide

## Headers
# This is a Heading h1
## This is a Heading h2
###### This is a Heading h6

## Emphasis
*This text will be italic*
_This will also be italic_
**This text will be bold**
__This will also be bold__
_You **can** combine them_

## Lists
### Unordered
* Item 1
* Item 2
  * Item 2a
  * Item 2b

### Ordered
1. Item 1
2. Item 2
3. Item 3
   1. Item 3a
   2. Item 3b

## Images
![This is an alt text.](https://avatars.githubusercontent.com/u/10759137 "This is a sample image.")

## Links
You may be using [Markdown Live Preview](https://markdownlivepreview.com/).

## Blockquotes
> Markdown is a lightweight markup language with plain-text-formatting syntax, created in 2004 by John Gruber with Aaron Swartz.
>>
>> Markdown is often used to format readme files, for writing messages in online discussion forums, and to create rich text using a plain text editor.

## Tables
| Left columns | Right columns |
| ------------- |:-------------:|
| left foo | right foo |
| left bar | right bar |
| left baz | right baz |

## Blocks of code
```

{% endcode %}

{% hint style="info" %}
Edytor obsługuje tworzenie i podgląd markdown w czasie rzeczywistym. Między edytorem a podglądem możesz regulować szerokość za pomocą paska.
{% endhint %}
{% endstep %}

{% step %}

### Zarządzanie artefaktami dokumentacji

Dla artefaktu dokumentacji można:

* podejrzeć historię wersji,
* utworzyć kopię artefaktu,
* pobrać go na dysk.

Wystarczy w oknie **Dokumentacji** kliknąć menu kontekstowe danego artefaktu.

<figure><img src="/files/YqAA3DoLYRXAyc9dHdrx" alt=""><figcaption><p><em><strong>Ilustracja 3.</strong> Lista dokumentacji aplikacji z menu kontekstowym jednego z artefaktów.</em></p></figcaption></figure>
{% endstep %}
{% endstepper %}


# Formatowanie i najlepsze praktyki tworzenia changelogu

Changelog to zestawienie zmian wprowadzonych w aplikacji wraz z ich opisem biznesowym. Głównym celem jest prowadzenie przejrzystej historii rozwoju aplikacji, uporządkowanej według kolejności chronologicznej (od najnowszej) i pogrupowanej na paczki. Sposób dodania changelogu do aplikacji został opisany w: [Dokumentacja aplikacji](/budowanie-aplikacji/aplikacja-biznesowa/dokumentowanie-aplikacji).

## Składnia i formatowanie

Changelog powinien być pisany w ujednoliconej i spójnej strukturze oraz formacie opartym na nagłówkach i listach (wpisy tworzymy używając znaczników [Markdown](https://www.markdownguide.org/basic-syntax/)).

Struktura changelogu:

{% stepper %}
{% step %}
Nagłówek H1 (#)

* Tytuł changelogu.
* Umieszczony tylko raz na początku pliku.
  {% endstep %}

{% step %}
Nagłówek H2 (##)

* Nazwa paczki.
* Powinna uwzględniać nazwę aplikacji oraz datę wysyłki paczki.
* Każda paczka jest osobnym nagłówkiem.
* Paczki należy zapisywać w kolejności od najnowszej do najstarszej (najnowsze na górze).
  {% endstep %}

{% step %}
Nagłówek H3 (###)

* Kategoria wpisów.
* W ramach jednej paczki można dodać kilka nagłówków kategorii (kategorie zostały wyszczególnione dalej).
  {% endstep %}

{% step %}
Pojedynczy wpis zmiany

* Umieszczony w formie listy punktowanej pod odpowiednią kategorią.
* Składnia pojedynczego wpisu powinna wyglądać następująco:

  * \[numer Jiry]\(link do Jiry)\[numer Jiry klienta]\(link do Jiry klienta)\* Opis zmiany \[nazwa zmienionego artefaktu/artefaktów i jego/ich wersja po zmianie]

  \*Numer oraz link do Jiry klienta są opcjonalne, natomiast warto je dodać, jeśli zmiana jest odpowiedzią na zgłoszenie klienta.

<figure><img src="/files/dcNCWUYHrgorS5Jie82D" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Przykładowy fragment changelogu w oknie edycji</em></p></figcaption></figure>
{% endstep %}
{% endstepper %}

## Kategorie wpisów

* Nowe funkcjonalności - nowe elementy bądź funkcje w aplikacji,
* Modyfikacje - zmiany w istniejących funkcjonalnościach,
* Poprawki - wpisy dotyczące rozwiązania zgłoszonych błędów,
* Konfiguracja - wpisy z informacjami o parametrach konfiguracyjnych.

## Język wpisów i dobre praktyki

Dobrą praktyką jest stosowanie języka biznesowego oraz unikanie szczegółów technicznych, czyli opisywanie zmiany w kontekście wartości dla użytkownika. Przykład: "Poprawka w formaterze kwoty" może być opisana jako "Poprawa formatowania kwoty kredytu".

Przed wysłaniem paczki należy pamiętać, aby zaktualizować datę wysyłki w changelogu. Przykład: ALXXXXXXXX - XXXX-XX-XX → AL20250101 - 2025-01-01 (format YYYY-MM-DD).

Changelog wysyłany do klienta powinien w jak największym stopniu odzwierciedlać faktyczny stan paczki. Powinny znajdować się tam wszystkie wpisy związane z dodanymi funkcjonalnościami, modyfikacjami lub poprawkami.

## Przykładowy szablon changelogu

Poniżej przykład struktury i przykładowego wpisu. Zachowaj formatowanie i linki.

{% code expandable="true" %}

```markdown
# Changelog dla aplikacji 300plus
<!--
## EXIMEEYYYYMMDD_300PLUS_APP - YYYY-MM-DD
 
### Nowe funkcjonalności
- 1
- 2
 
### Modyfikacje
- 1
- 2
 
### Poprawki
- 1
- 2
-->
 
## EXIMEE20250901_300PLUS_APP - 2025-09-01
 
### Poprawki
- [EXIMEE-1234](https://jira.consdata.pl/browse/EXIMEE-1234) Przykładowy opis zmiany [artefakt: 300plus 1.02]
```

{% endcode %}

(Przykład powyżej służy jedynie jako szablon — w praktyce listę paczek i wpisów zapisuj od najnowszej do najstarszej, stosując się do opisanych reguł.)


# Elementy aplikacji (artefakty)

### Biblioteka elementów aplikacji

W Eximee Designer, w module **Biblioteka**, każdy twórca aplikacji ma dostęp do zakładek umożliwiających przeglądanie i tworzenie różnych **elementów aplikacji**. Do najczęściej wykorzystywanych należą:

* formularze
* procesy BPMN
* komponenty złożone i biznesowe
* treści (TextContents)
* skrypty, walidatory skryptowe, zadania skryptowe
* słowniki i formatery
* wydruki

<figure><img src="/files/0jQRUxGr9isWJ8HCl5D9" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Moduł "Biblioteka"</em></p></figcaption></figure>

### Wspólne właściwości

Choć różnią się one funkcją i zastosowaniem, wszystkie zarządzane są w spójny sposób. W każdej zakładce użytkownik może tworzyć nowe elementy, przeglądać istniejące oraz wykonywać operacje kontekstowe, takie jak:

* wyświetlenie historii wersji,
* duplikowanie,
* pobieranie najnowszej wersji,
* usuwanie elementu z repozytorium.


# Konwencje nazewnicze elementów aplikacji

W projektach realizowanych w Eximee Designer stosowanie spójnych konwencji nazewniczych dla elementów aplikacji jest kluczowe dla utrzymania porządku, przejrzystości i efektywnej współpracy w zespole.

Dobrze dobrane nazwy ułatwiają:

* szybkie wyszukiwanie i filtrowanie komponentów w repozytorium,
* rozpoznanie funkcji i przeznaczenia danego elementu bez konieczności jego otwierania,
* unikanie konfliktów nazw i przypadkowego nadpisywania artefaktów,
* zarządzanie dużymi zbiorami formularzy, procesów, skryptów itp., zwłaszcza w środowiskach z wieloma aplikacjami i zespołami.

Poniższa tabela prezentuje zalecane konwencje nazewnicze dla wszystkich głównych typów elementów aplikacji w Eximee. Są one zgodne z dobrymi praktykami stosowanymi w projektach produkcyjnych i umożliwiają zachowanie porządku w skalowalnych rozwiązaniach.

{% hint style="info" %}
Nazwy należy standardowo tworzyć w języku angielskim. Wyjątek stanowią sytuacje, w których nazwa formularza została określona odgórnie w języku polskim.
{% endhint %}

#### Tabela konwencji nazewniczych elementów aplikacji Eximee

<table><thead><tr><th width="138.272705078125">Typ elementu</th><th width="195.818115234375">Format nazwy</th><th>Przykład</th></tr></thead><tbody><tr><td><strong>Aplikacja</strong></td><td><mark style="background-color:orange;">prefix</mark>_app</td><td><code>kontoJunior_app</code>, <code>800plus_app</code></td></tr><tr><td><strong>Formularz</strong></td><td><mark style="background-color:orange;">prefixName</mark></td><td><code>kontoJuniorStart</code>, <code>kontoJuniorForm</code>, <code>kontoJuniorAcceptance</code></td></tr><tr><td><strong>Pozostałe elementy(np. skrypty)</strong></td><td><mark style="background-color:orange;">prefixName</mark></td><td><code>kontoJuniorCheckAmount</code></td></tr><tr><td><strong>Procesy</strong></td><td><mark style="background-color:orange;">prefixNameProcess</mark></td><td><code>kontoJuniorProcess</code>, <code>kontoJuniorSendNotificationProcess</code></td></tr></tbody></table>

Zasady ogólne

* <mark style="background-color:orange;">prefix</mark> - nazwa biznesowa danego projektu, umieszczana na początku każdego elementu aplikacji\
  w formacie camelCase
* <mark style="background-color:purple;">Name</mark> - nazwa danego elementu w formacie camelCase

{% hint style="warning" %}
W przypadku formularzy i aplikacji należy brać pod uwagę to, że nazwa formularza/aplikacji pojawia się potem m.in. w adresie URL.
{% endhint %}


# Zarządzanie elementami aplikacji


# Eksport elementu

Eksport elementu pozwala na wygenerowanie i pobranie pliku `.artifact` zawierającego wybraną składową (np. formularz, proces czy komponent złożony).

W celu eksportowania artefaktu, będąc na liście danego typu elementu (w przykładzie moduł **Biblioteka**, zakładka **Formularze**), należy kliknąć w menu kontekstowe tego artefaktu i wybrać opcję **Pobierz**.

<figure><img src="/files/mUS5AWevfP86Cl9apjmr" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Menu kontekstowe wybranego formularza</em></p></figcaption></figure>

> Szczegółowy opis procesu eksportowania całych aplikacji znajduje się w rozdziale dotyczącym [eksportu aplikacji](/budowanie-aplikacji/aplikacja-biznesowa/zarzadzanie-aplikacja/eksport-import-aplikacji#eksport-aplikacji).


# Import elementu

Import elementu aplikacji umożliwia wczytanie do Eximee Designer pliku `.artifact` zawierającego wcześniej wyeksportowany artefakt (t.j. formularz, proces, komponent lub całą aplikację). Funkcja ta służy m.in. do przenoszenia gotowych rozwiązań między środowiskami (np. z developerskiego na testowe).

Importowany element zostaje zapisany w repozytorium, o ile jego wersja jest wyższa niż wersja znajdująca się już w środowisku.

> Szczegółowy opis procesu importowania artefaktu znajduje się w rozdziale dotyczącym [importu aplikacji](/budowanie-aplikacji/aplikacja-biznesowa/zarzadzanie-aplikacja/eksport-import-aplikacji#import-aplikacji).


# Tworzenie duplikatu elementu

Tworzenie duplikatu przebiega analogicznie dla każdego typu artefaktu. Dla celów demonstracyjnych poniżej przedstawiono ten proces na przykładzie tworzenia duplikatu formularza.

W celu stworzenia kopii należy, będąc na liście danego typu artefaktów (w przykładzie moduł **Biblioteka**, zakładka **Formularze**), kliknąć w menu kontekstowe tego artefaktu i wybrać opcję **Duplikuj**.

<figure><img src="/files/mUS5AWevfP86Cl9apjmr" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Menu kontekstowe wybranego formularza</em></p></figcaption></figure>

***

W wyświetlonym oknie (tutaj **Kopiuj formularz**) ustalamy nazwę nowego artefaktu (nazwa musi być unikalna oraz zgodna z zasadami opisanymi w: [*Zapis wraz z publikacją elementu*](/budowanie-aplikacji/aplikacja-biznesowa/elementy-aplikacji-artefakty/zarzadzanie-elementami-aplikacji/zapis-wraz-z-publikacja-elementu)).

<figure><img src="/files/qc5oDf4KdTyjwoWZr7B9" alt=""><figcaption><p align="center"><em><strong>Ilustracja 2.</strong> Okno tworzenia duplikatu artefaktu</em></p></figcaption></figure>

{% hint style="info" %}
Należy pamiętać o dobrych praktykach konwencji nazewniczych. Dla formularza to format `prefixName` np. `kontoJuniorForm` (więcej w: [Konwencje nazewnicze elementów aplikacji](/budowanie-aplikacji/aplikacja-biznesowa/elementy-aplikacji-artefakty/konwencje-nazewnicze-elementow-aplikacji)).
{% endhint %}


# Tworzenie nowego elementu

### Tworzenie nowego elementu aplikacji (na przykładzie formularza)

Aby utworzyć nowy **formularz** – jeden z podstawowych elementów aplikacji – należy przejść do modułu **Biblioteka**, a następnie do zakładki **Formularze**. W prawym górnym rogu ekranu znajduje się przycisk **Dodaj formularz**, który inicjuje proces tworzenia.

<figure><img src="/files/t41BaBnFOf10WdJxVG3F" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Widok zakładki „Formularze” w module „Biblioteka” z przyciskiem tworzenia formularza</em></p></figcaption></figure>

***

Po kliknięciu przycisku otworzy się okno, w którym należy uzupełnić podstawowe dane:

* **Nazwa formularza** – zgodna z konwencją nazewniczą (więcej w: [*Konwencje nazewnicze elementów aplikacji*](/budowanie-aplikacji/aplikacja-biznesowa/elementy-aplikacji-artefakty/konwencje-nazewnicze-elementow-aplikacji)),
* **Lokalizacja w repozytorium** – miejsce, w którym formularz zostanie zapisany,
* **Liczba kolumn** – domyślnie ustawiona na 16; można ją zmienić (więcej w: [Edycja stron](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/edycja-stron)),
* **Opis** – pole opcjonalne, pomocne przy dokumentowaniu funkcji formularza.

<figure><img src="/files/uM0rxfY38CvCV4sq5M7l" alt=""><figcaption><p align="center"><em><strong>Ilustracja 2.</strong> Okno dialogowe tworzenia nowego formularza</em></p></figcaption></figure>

***

Po zatwierdzeniu (przycisk **Dodaj formularz**) zostanie otwarty edytor z pustym szablonem formularza w zakładce **Kroki**. Dodawanie komponentów możliwe jest po przejściu do zakładki **Wniosek** (1), a zapisanie formularza do repozytorium – po kliknięciu przycisku **Zapisz** (2).

<figure><img src="/files/8cvyl3Vj7TveIgm36XLK" alt=""><figcaption><p align="center"><em><strong>Ilustracja 3.</strong> Edytor nowo utworzonego formularza w zakładce „Wniosek”</em></p></figcaption></figure>

***

Proces tworzenia pozostałych elementów aplikacji (takich jak komponenty złożone, skrypty czy walidatory) przebiega analogicznie:

1. Przejdź do odpowiedniej zakładki w module **Biblioteka**,
2. Kliknij przycisk **Dodaj**,
3. Wypełnij dane konfiguracyjne,
4. Zatwierdź i przejdź do edycji nowego elementu.


# Usuwanie elementów

Aby usunąć element aplikacji biznesowej należy go odszukać w odpowiedniej zakładce, a następnie z menu kontekstowego (szaszłyk) wybrać opcję **Usuń**.

{% hint style="info" %}
Możliwe jest usunięcie tylko całego artefaktu, a nie poszczególnych jego wersji.
{% endhint %}

<figure><img src="/files/F3nyYCRUpnE4N94IcWhr" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Menu kontekstowe dla komponentu złożonego</em></p></figcaption></figure>

{% hint style="warning" %}
Usuwany artefakt nie może być używany na innym artefakcie. Próba usunięcia takiego artefaktu zostanie przerwana, a użytkownik zostanie poinformowany o zależnościach uniemożliwiających usunięcie.
{% endhint %}

{% hint style="info" %}
W trakcie usuwania artefaktu nie może on posiadać wersji roboczej (draftu). Próba usunięcia takiego artefaktu zostanie przerwana, a użytkownik zostanie poinformowany odpowiednim komunikatem o błędzie.<br>
{% endhint %}

#### Artefakty możliwe do usunięcia <a href="#usuwanieartefaktowifolderow-artefaktymozliwedousuniecia" id="usuwanieartefaktowifolderow-artefaktymozliwedousuniecia"></a>

* Formularze
* Procesy
* Komponenty złożone
* Treści
* Skrypty
* Walidatory skryptowe
* Zadania skryptowe
* Emaile
* Słowniki
* Formatery
* Komponenty niestandardowe
* Wydruki

Informacja o usunięciu artefaktu zostaje zapisana w logach w następujący sposób *("artifact1"* oraz *"22100"* oznaczając tu przykładową nazwę i przykładowy identyfikator usuwanego artefaktu):

{% code overflow="wrap" %}

```
[designer] 2017-02-20 09:06:06,413 CET [main] [INFO ] p.c.i.g.t.t.v.c.a.remove.ArtifactTrashCommand     :32 - > Removing artifact [name=artifact1, id=22100][designer] 2017-02-20 09:06:06,489 CET [main] [INFO ] p.c.i.g.t.t.v.c.a.remove.ArtifactTrashCommand     :34 - < Artifact [name=artifact1, id=22100] removed successfully
```

{% endcode %}

{% hint style="warning" %}
**Bezpieczne usuwanie**

Usunięte artefakty i foldery mogą zostać bezpiecznie przywrócone za pomocą skryptów administracyjnych, o ile od usunięcia nie upłynęły 3 dni.\
Potrzebne informacje o usuniętych folderach i artefaktach będzie można odczytać z logów aplikacji.
{% endhint %}


# Zapis wraz z publikacją elementu

## Zapis aktualnie tworzonego/edytowanego elementu aplikacji <a href="#zapiszpublikacja-zapisaktualnietworzonego-edytowanegoartefaktu" id="zapiszpublikacja-zapisaktualnietworzonego-edytowanegoartefaktu"></a>

Po dokonaniu zmian oraz kliknięciu przycisku **Zapisz**, dostaniemy popup z możliwością zapisania nowej wersji elementu aplikacji biznesowej.

W nazwie elementu oraz w opisie **można** wykorzystać następujące znaki:

* wielkie i małe litery (bez polskich znaków),
* liczby,
* myślniki ( - ),
* znaki podkreślenia ( \_ ).

Jest możliwość dodania komentarza oraz ustalenia, czy aktualna wersja artefaktu to nowa wersja Major (`*.1`), czy podwersja dla aktualnej gałęzi (`1.*`). Więcej na temat wersjonowania w rozdziale [Wersjonowanie](/budowanie-aplikacji/aplikacja-biznesowa/wersjonowanie).

<figure><img src="/files/m4JLRsQeRWw9C5Etw4Uz" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Standardowy popup zapisywania artefaktu</em></p></figcaption></figure>

## Zależności, które zostaną zmienione <a href="#zapiszpublikacja-artefakty-ktorychzachowaniezmieniasz" id="zapiszpublikacja-artefakty-ktorychzachowaniezmieniasz"></a>

Przy zapisie elementu aplikacji wyświetlana jest lista innych elementów, na które zapisywana wersja ma wpływ. Należy się z nią zapoznać i zaznaczyć checkbox **Zapoznałem się z listą zależności**.

<figure><img src="/files/uU3myXDMoMTfRbF2yBvj" alt=""><figcaption><p align="center"><em><strong>Ilustracja 2.</strong> Popup zapisywania artefaktu z listą zależności</em></p></figcaption></figure>

## Publikacja wybranej wersji elementu aplikacji <a href="#zapiszpublikacja-publikacjawybranejwersjiwniosku" id="zapiszpublikacja-publikacjawybranejwersjiwniosku"></a>

Publikacja innej wersji elementu aplikacji niż najwyższa dostępna w repozytorium jest możliwa na kilka sposobów. Na przykład będąc w trybie tylko do odczytu w edytorze formularza, można wybrać przycisk **Wersje**, a następnie po wyświetleniu okna **Historia wersji** z menu kontekstowego wybrać opcję **Publikuj**:

<figure><img src="/files/bQHSjcvh3UeYNKwHZZRr" alt=""><figcaption><p align="center"><em><strong>Ilustracja 3.</strong> Okno z historią wersji wniosku i menu kontekstowym zawierającym opcję publikacji</em></p></figcaption></figure>

Okno z historią wersji można wyświetlić także będąc w edytorze formularzy, gdzie dla każdego szablonu w menu kontekstowym dostępna jest opcja **Historia wersji**.

## Aktualnie obowiązująca wersja elementu aplikacji <a href="#zapiszpublikacja-aktualnieobowiazujacawersjaartefaktu" id="zapiszpublikacja-aktualnieobowiazujacawersjaartefaktu"></a>

Jedyną informacją na temat aktualnie obowiązującej wersji artefaktu jest **sprawdzenie daty ostatniego zapisu**.

{% hint style="warning" %}
W przypadku formularzy należy pamiętać, że to nie wersja artefaktu wskazuje na tę obowiązującą. Poniższa ilustracja pokazuje, że zmiany dokonywane były w wersji 2.\*, natomiast czy jest to wersja obowiązywania wniosku zależy od tego, czy inna wersja nie była publikowana (patrz wyżej).
{% endhint %}

<figure><img src="/files/0BtIo2C0CmBOvo3v3Kgt" alt=""><figcaption><p align="center"><em><strong>Ilustracja 4.</strong> Okno z historią wersji wniosku (wersja 2.* jest wersją z najnowszymi zmianami)</em></p></figcaption></figure>


# Zmiana nazwy elementu

### Zmiana nazwy szablonu wniosku

Szablon wniosku jako jedyny artefakt w repozytorium może podlegać zmianie nazwy. Zmiany możemy dokonać będąc na liście wniosków (moduł **Biblioteka**, zakładka **Formularze**) i w menu kontekstowym danego artefaktu wybrać opcję **Zmień nazwę**. W wyświetlonym okienku ustalamy nową nazwę, a następnie zatwierdzamy ją klikając przycisk **Zmień nazwę** (informacje na temat możliwej nazwy w: [*Zapis wraz z publikacją elementu*](/budowanie-aplikacji/aplikacja-biznesowa/elementy-aplikacji-artefakty/zarzadzanie-elementami-aplikacji/zapis-wraz-z-publikacja-elementu)).

<figure><img src="/files/e1SEcHiNKLvqv5sWTBwt" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Okno zmiany nazwy formularza</em></p></figcaption></figure>

{% hint style="info" %}
Zmiana nazwy jest możliwa tylko w przypadku formularza. Nie można zmienić nazwy całej aplikacji.
{% endhint %}

{% hint style="info" %}
Należy pamiętać o dobrych praktykach konwencji nazewniczych. Dla formularza to format `prefixName` np. `kontoJuniorForm` (więcej w: [Konwencje nazewnicze elementów aplikacji](/budowanie-aplikacji/aplikacja-biznesowa/elementy-aplikacji-artefakty/konwencje-nazewnicze-elementow-aplikacji)).
{% endhint %}

***

Zmiana nazwy szablonu wniosku nie jest możliwa, jeśli na szablonie są założone blokady (więcej w: [*Zapis wraz z publikacją elementu*](/budowanie-aplikacji/aplikacja-biznesowa/elementy-aplikacji-artefakty/zarzadzanie-elementami-aplikacji/zapis-wraz-z-publikacja-elementu)). W repozytorium nie może również istnieć szablon o takiej samej nazwie jak nowo wprowadzona.

Jeśli nie zostaną spełnione określone warunki – brak unikalności wprowadzonej nazwy (więcej w: [*Zapis wraz z publikacją elementu*](/budowanie-aplikacji/aplikacja-biznesowa/elementy-aplikacji-artefakty/zarzadzanie-elementami-aplikacji/zapis-wraz-z-publikacja-elementu)) lub występowanie blokad na szablonie – zostanie wyświetlony komunikat o błędzie.

<figure><img src="/files/dhkMPKlMNekjiwmrCvht" alt=""><figcaption><p align="center"><em><strong>Ilustracja 2.</strong> Komunikat o błędzie przy próbie zmiany nazwy wniosku</em></p></figcaption></figure>


# Testy


# Checklista testowa uwzględniająca przepływy biznesowe

Checklisty testowe nie powinny być tylko listą technicznych przypadków. Ich rolą jest **odzwierciedlenie logiki procesów biznesowych** – tak, jak przechodzi przez nie klient.

W przypadku procesów stworzonych w Eximee checklistę budujemy **krok po kroku**. Najpierw **identyfikujemy kluczowe etapy procesu** – na przykład rejestrację wniosku, walidację danych, zatwierdzenie, aż po zakończenie procesu. Każdy z tych etapów opisujemy prostymi, jasnymi krokami do sprawdzenia.


# Najczęstsze błędy i dobre praktyki testowania

### Najczęstsze błędy:

* testowanie za późno,
* brak testów biznesowych,
* testy tylko na jednym środowisku i jednej rozdzielczości,
* brak testów integracyjnych.

### Dobre praktyki:

* testy na kilku środowiskach,
* scenariusze testowe ([Checklista testowa uwzględniająca przepływy biznesowe](/budowanie-aplikacji/aplikacja-biznesowa/testy/checklista-testowa-uwzgledniajaca-przeplywy-biznesowe)),
* testy integracji ([Testowanie integracji z usługami zewnętrznymi](/budowanie-aplikacji/aplikacja-biznesowa/testy/testowanie-integracji-z-uslugami-zewnetrznymi)),
* testy na różnych urządzeniach (mobile + desktop),
* włączenie do testów osób biznesowych.


# Narzędzia diagnostyczne (logi, widoki audytowe, FormStore, Cockpit)

## Logi diagnostyczne

[Logi diagnostyczne](/zarzadzanie-aplikacja-biznesowa/testowanie-i-debugowanie-aplikacji/audyt-aplikacji-biznesowej/logi-diagnostyczne).

## Widoki audytowe

### Terminal w Linuxie

Na serwerze logi znajdują się zazwyczaj w katalogach **/var/log/eximee** oraz **/var/log/eximee\_sensitive**.

Najczęściej sięgamy do pliku **eximee\_platform.log**, który na początek daje najwięcej informacji.

Warto znać kilka podstawowych komend:

* **cd** – zmiana folderu,
* **cat**, **less** i **more** – do przeglądania logów,
* oraz **grep** – do wyszukiwania konkretnych wpisów. Np: grep "ERROR" /var/log/eximee/eximee\_platform.log, To polecenie wyszuka wszystkie linie z błędami w pliku logu.

### Kibana

**Kibana** to narzędzie, które może być wykorzystane do przeglądania i analizy logów oraz danych testowych, które zostały wcześniej zebrane i zapisane w systemie (np. w Elasticsearch).

Umożliwia:

* przeglądanie logów z działania systemu w uporządkowanej, czytelnej formie,
* filtrowanie danych według różnych kryteriów (np. ID operacji, daty, statusu czy typu błędu),
* szybkie wyszukiwanie konkretnych zdarzeń i analizę ich przebiegu krok po kroku,
* identyfikowanie błędów oraz sprawdzanie, w jakim momencie i w jakich warunkach wystąpiły,
* tworzenie prostych wizualizacji (np. wykresów), które pomagają zauważyć powtarzające się problemy lub wzorce.

<figure><img src="/files/i3QqCeHVNJDfITKFaTg5" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Przykładowy interfejs Kibany.</em></p></figcaption></figure>

## EximeeBPMS Cockipit

Dowiedz się więcej: [EximeeBPMS Cockpit](/eksploatacja-aplikacji/obsluga-procesow/eximeebpms-cockpit).


# Obsługa danych testowych w modelu danych

Model danych to centralny element analizy biznesowej.

### Dane testowe w modelu

* umożliwiają szybkie prototypowanie formularzy i procesów,
* pozwalają na weryfikację logiki procesów BPMN i usług,
* umożliwiają przeprowadzenie pełnych testów end-to-end bez integracji z systemami zewnętrznymi.

### Metody testów

* testy przy użyciu defaultValue,
* testy przy pomocy lokalnych źródeł danych = providerów.

{% hint style="info" %}
Więcej o modelu danych: [Model danych](/budowanie-aplikacji/model-danych).
{% endhint %}


# Struktura aplikacji low-code i metodyka testowania

## **Struktura aplikacji a testy**

Aplikacja Eximee to kontener na artefakty ([Aplikacja biznesowa](/budowanie-aplikacji/aplikacja-biznesowa)).

### **Testy formularza - co warto sprawdzić?**

* poprawność działania pól (czy są widoczne, wymagane),
* walidacje i reguły biznesowe,
* integrację z modelem danych (czy dane są poprawnie pobierane i zapisywane),
* wygląd treści i układ pól.

Więcej o formularzach: [Formularze](/budowanie-aplikacji/interfejs-uzytkownika/formularze).

### **Testy modelu danych - co warto sprawdzić?**

* czy wszystkie wymagane w aplikacji pola są obecne,
* czy wartości domyślne są ustawione zgodnie z wymaganiami,
* czy zmiany w modelu nie powodują błędów w formularzach lub procesach korzystających z tego modelu.

Więcej o modelu danych: [Model danych](/budowanie-aplikacji/model-danych).

### **Testy procesu BPMN - co warto sprawdzić?**

* czy przepływ procesu jest zgodny z wymaganiami biznesowymi (ścieżki, warunki, decyzje),
* czy integracja z formularzami i modelem danych działa poprawnie,
* czy wywołania zadań skryptowych i obsługa wyjątków są poprawne.

Więcej o procesach: [Proces biznesowy](/budowanie-aplikacji/proces-biznesowy).

## **Testy integracyjne i całościowe**

### **Zakres testów integracyjnych**

* połączenie formularza z logiką procesową (BPMN),
* weryfikacja działania ScriptCode i reguł biznesowych,
* integracje z systemami zewnętrznymi (CRM, płatności),
* generowanie dokumentów PDF i przekazywanie ich dalej w procesie.
* obsługa omnikanałowości – przekazywanie kontekstu między kanałami (desktop → mobile).

### **Zakres testów całościowych (E2E)**

* pełny przepływ formularz → proces → dokument → integracja → status końcowy,
* sprawdzenie, czy logika biznesowa, interfejsy i integracje tworzą spójne doświadczenie.
* testowanie scenariuszy krytycznych i biznesowych zgodnych z wymaganiami.


# Testowanie integracji z usługami zewnętrznymi

Testy integracji są bardzo ważne, gdyż **aplikacja komunikuje się z wieloma zewnętrznymi systemami** np. CRM czy systemy płatności. Jeśli integracja nie działa poprawnie, skutkuje to błędami biznesowymi, utratą danych lub niepoprawnym działaniem całego procesu.

## Metody testowania integracji

### Mocki

* to symulacje odpowiedzi systemów zewnętrznych,
* możliwość przetestowania różnych scenariuszy odpowiedzi,
* testy mogą być niezależne od dostępności usług.

### Testy danych wejściowych

* walidacja poprawności wysyłanych zapytań (np. struktura JSON, XML).

### Testy danych wyjściowych

* sprawdzenie, czy system poprawnie przetwarza dane zwrócone z zewnątrz,
* obsługa błędów i wyjątków.

### Testy jednostkowe w skryptach

Dowiedz się więcej: [Testy jednostkowe skryptów](/budowanie-aplikacji/logika-biznesowa/scriptcode/testy-jednostkowe-skryptow).


# Walidacja formularzy i logiki biznesowej – testy manualne i eksploracyjne

Formularze są **kluczowym punktem kontaktu użytkownika z aplikacją**. Błędy w walidacji lub logice biznesowej mogą prowadzić do niepoprawnych danych, frustracji użytkowników, a nawet ryzyka prawnego.

### Techniki czarnoskrzynkowe

* podział na klasy równoważności (klasy równoważności - zbiory danych wejściowych i wyjściowych, dla których zakładamy, że system zachowa się w ten sam sposób).
* analiza wartości brzegowych,
* testowanie w oparciu o tablicę decyzyjną,
* testowanie przejść pomiędzy stanami.

### Testy manualne

* systematyczne sprawdzanie pól i reguł zgodnie z checklistą,
* sprawdzamy m.in. poprawność działania pól, komunikaty błędów, poprawność przepływu.

### Testy eksploracyjne

* podejście mniej formalne – tester wciela się w rolę użytkownika,
* szukanie nietypowych scenariuszy np. bardzo długie wartości pól, nietypowe formaty danych (np. daty), pominięcie pól obowiązkowych
* cel: odkrycie błędów, których nie przewidziano w analizach.


# Wersjonowanie

W Eximee każdy **element aplikacji** – np. formularz, proces, skrypt czy treść – posiada własną historię wersji, zarządzaną bezpośrednio w repozytorium. Mechanizm wersjonowania umożliwia bezpieczne wprowadzanie zmian, śledzenie modyfikacji oraz łatwe przywracanie wcześniejszych wersji w razie potrzeby.

### **Wersje główne i podrzędne**

System wersjonowania rozróżnia dwa poziomy wersji:

* **Wersje główne (major)** – oznaczane kolejnymi liczbami całkowitymi: `1`, `2`, `3`, itd.\
  Służą do oznaczania zmian, które mają wpływ na działanie aplikacji lub jej strukturę (np. zmiana schematu danych, logiki procesu, powiązań między komponentami).
* **Wersje podrzędne (minor)** – oznaczane jako liczba zmiennoprzecinkowa względem wersji głównej: `1.1`, `1.2`, `1.3`, itd.\
  Używane są przy wprowadzaniu mniejszych zmian, które nie wpływają na interfejs aplikacji ani nie wymagają dostosowania zależnych komponentów (np. zmiana tekstu, poprawki układu, kosmetyczne modyfikacje).

{% hint style="info" %}
**Pierwsza wersja każdego elementu aplikacji to `1.0`.**
{% endhint %}

Przy zapisywaniu zmian użytkownik decyduje, czy tworzy **nową wersję główną** czy **podrzędną**. Wersjonowanie odbywa się ręcznie – system nie narzuca automatycznego podbicia numeru wersji.

### **Wersja robocza (szkic)**

W momencie edycji elementu aplikacji automatycznie tworzona jest jego **wersja robocza (draft)**. Wersja robocza to tymczasowa kopia edytowanego elementu, która nie wpływa jeszcze na działanie aplikacji i nie jest widoczna dla innych użytkowników.

Kluczowe zasady pracy z wersją roboczą:

* Dla danej **gałęzi wersji głównej** (`np. 3.*`) może istnieć tylko **jedna wersja robocza** w danym czasie.
* Edytowanie wersji roboczej **blokuje gałąź**, co oznacza, że inni użytkownicy nie mogą jednocześnie wprowadzać zmian na tej samej wersji głównej.
* Blokada jest zdejmowana automatycznie, gdy użytkownik:
  * zapisze wersję roboczą jako nową wersję `major` lub `minor`,
  * albo porzuci wersję roboczą bez zapisu.

Wersja robocza pozwala na bezpieczne eksperymentowanie ze zmianami – dopiero zapis (promocja) wersji do repozytorium sprawia, że staje się ona dostępna w historii i może być wykorzystana w aplikacjach.

### **Historia wersji**

Każdy element aplikacji posiada dostępną z poziomu interfejsu zakładkę **Historia wersji**, w której widoczne są:

* wszystkie zatwierdzone wersje (`1.0`, `1.1`, `2.0` itd.),
* opisy zmian (jeśli zostały dodane przy zapisie),
* autor i data modyfikacji,
* dostęp do porównania zawartości między wersjami,
* możliwość przywrócenia wybranej wersji jako nowej roboczej.

Dzięki temu łatwo można prześledzić zmiany w czasie i zachować pełną kontrolę nad rozwojem każdego elementu aplikacji.

<figure><img src="/files/udZqd2B4ne9JbhXsuN6d" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Widok "Historii wersji"</em></p></figcaption></figure>

Na ilustracji 1 widzimy historię wersji szablonu wniosku, który posiada wiele wersji głównych. W wersji głównej 11.\* ma 5 wersji podrzędnych (od 11.0-11.4).

### Odcinanie gałęzi głównej, w tym produkcyjnej

Odcinanie gałęzi głównej jest szczególnie zalecane przed rozpoczęciem większych zmian — takich jak przebudowa procesów, modyfikacja struktury danych czy rozwój nowych funkcjonalności — które mogłyby wpłynąć na stabilność działającej aplikacji.

Mechanizm odcinania gałęzi głównej stosowany jest do rozdzielenia stabilnej wersji (np. produkcyjnej) aplikacji lub wniosku od prac nad nowymi fukcjonalnościami. Odcinanie gałęzi polega na utworzeniu nowej wersji głównej (major), która stanowi niezależną przestrzeń do dalszego rozwoju.

<figure><img src="/files/fA3Zi4DCK4euw8gFnG6K" alt=""><figcaption><p align="center"><em><strong>Ilustracja 2.</strong> Rozdzielenie wersji produkcyjnej i rozwojowej</em></p></figcaption></figure>

W praktyce oznacza to, że wersja 1.\* (np. 1.12) może nadal funkcjonować na produkcji, podczas gdy zespół równolegle pracuje nad wersją 2.\*, rozwijając ją niezależnie aż do momentu jej gotowości do wdrożenia. Takie podejście pozwala jednocześnie utrzymywać stabilną wersję aplikacji oraz rozwijać kolejną, minimalizując ryzyko błędów i konfliktów między zmianami. W razie potrzeby możliwe jest również wprowadzanie poprawek w gałęzi produkcyjnej bez wpływu na nową, rozwijaną wersję.

<figure><img src="/files/QvCUJezpzzN5oIo8EWc6" alt=""><figcaption><p align="center"><em><strong>Ilustracja 3.</strong> Równoległy rozwój wersji 2.0 przy utrzymaniu wersji 1.*</em></p></figcaption></figure>

Odcinanie gałęzi produkcyjnej jest szczególnie zalecane przed rozpoczęciem większych zmian — takich jak przebudowa procesów, modyfikacja struktury danych czy rozwój nowych funkcjonalności — które mogłyby wpłynąć na stabilność działającej aplikacji.


# Edycja wybranej wersji

## Edycja elementu aplikacji – na przykładzie formularza

W zależności od miejsca w systemie, z którego korzystamy, sposób przejścia do edycji elementu aplikacji może się nieco różnić.

### **Edycja najnowszej wersji formularza**

Jeśli znajdujesz się w module **Biblioteka**, w zakładce **Formularze**, edycja wybranego formularza będzie możliwa po kliknięciu w jego wiersz na liście, a następnie użyciu przycisku **Edytuj** (ikona ołówka w prawym górnym pasku).

Alternatywnie, formularz można otworzyć również z poziomu zakładki **Formularze** w module **Aplikacje**, o ile dany formularz został wcześniej dodany do danej aplikacji. Wówczas kliknięcie w jego wiersz przeniesie użytkownika bezpośrednio do edytora formularza.

### **Edycja wybranej wersji formularza**

Aby edytować konkretną wersję formularza (np. starszą lub testową), należy otworzyć widok **Historia wersji**:

* Z poziomu edytora formularza – przez kliknięcie przycisku **Wersje**,
* Z poziomu modułu **Biblioteka** lub **Aplikacje** – przez menu kontekstowe w zakładce **Formularze**, wybierając opcję **Historia wersji**.

<figure><img src="/files/Ly4ioSCJo6xVEpGYr82y" alt=""><figcaption><p align="center"><em><strong>lustracja 1.</strong> Wybór opcji "Historia wersji" w zakładce "Formularze" modułu "Aplikacje"</em></p></figcaption></figure>

**Historia wersji** wyświetla rozwijaną listę wersji głównych (`1`, `2`, `3`, ...) wraz z przypisanymi do nich wersjami podrzędnymi (`1.1`, `1.2`, ...). Kliknięcie w wiersz danej wersji podrzędnej otwiera ją w trybie podglądu lub edycji – w zależności od dostępnych uprawnień i stanu wersji.

<figure><img src="/files/ew1Aqgcoh5Z9ozy6SCJj" alt=""><figcaption><p align="center"><em><strong>Ilustracja 2.</strong> Okno "Historia wersji" z rozwiniętą wersją główną 2.* wniosku</em></p></figcaption></figure>

{% hint style="warning" %}
Dla jednej wersji głównej formularza możliwa jest edycja tylko jednej wersji roboczej w danym czasie. Szczegóły opisano w sekcji: **Draft (szkic/kopia robocza) elementu aplikacji**
{% endhint %}


# Wersja robocza elementu

Mechanizm wersji roboczych umożliwia bezpieczną edycję elementu aplikacji (takiego jak formularz, proces czy skrypt) bez wpływu na opublikowane wersje.

### **Tworzenie wersji roboczej**

Przejście do edycji elementu powoduje automatyczne:

* zablokowanie możliwości edycji dla innych użytkowników w obrębie danej **wersji głównej** (np. `1.*`),
* utworzenie **wersji roboczej** na podstawie wybranej wersji (np. `1.8`).

{% hint style="info" %}
Dla każdej wersji głównej może istnieć tylko **jedna aktywna kopia robocza**. Jeśli już istnieje, dostęp do edycji będzie zablokowany do momentu jej zapisania lub porzucenia.
{% endhint %}

***

### **Praca z kopią roboczą**

Podczas edycji zmiany są zapisywane automatycznie:

* **co 30 sekund**,
* oraz **przy opuszczeniu edytora** (np. zamknięcie zakładki, przejście do innego widoku).

W górnym pasku edytora wyświetlany jest **czas od ostatniego zapisu** na serwerze. Po ponownym otwarciu edytora, wersja robocza zostaje odtworzona z ostatnio zapisanym stanem.

<figure><img src="/files/0qN1JuKC4M1YgWRwDxLB" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Informacja o kopii roboczej</em></p></figcaption></figure>

Zatwierdzenie zmian odbywa się przez kliknięcie przycisku **Zapisz jako nową wersję**, co powoduje:

* zapis wszystkich zmian do repozytorium,
* utworzenie nowej wersji głównej (major) lub podrzędnej (minor),
* zwolnienie blokady edycji.

***

### **Porzucanie wersji roboczej**

Autor wersji roboczej może w dowolnym momencie zrezygnować z zapisanych zmian, wybierając z menu lewego paska opcję **Porzuć kopię roboczą**.

Ta operacja:

* usuwa aktualną wersję roboczą,
* przywraca dostęp do edycji danej wersji głównej innym użytkownikom.

<figure><img src="/files/unfW3OGKtMaNLVic4iRK" alt=""><figcaption><p align="center"><em><strong>Ilustracja 2.</strong> Menu z opcją "Porzuć kopię roboczą"</em></p></figcaption></figure>

***

### **Odblokowanie edycji elementu**

Jeśli wersja robocza została utworzona przez innego użytkownika i edycja jest zablokowana, możliwe jest **wymuszenie odblokowania edycji** poprzez opcję **Odblokuj edycję elementu** (również w menu po lewej stronie).

<figure><img src="/files/uxbyyl9h8zv5d0O4Mqpl" alt=""><figcaption><p align="center"><em><strong>Ilustracja 3.</strong> Menu z opcją "Odblokuj edycję artefaktu"</em></p></figcaption></figure>

{% hint style="warning" %}
*Uwaga: operacja ta jest nieodwracalna – wszystkie niezapisane zmiany wersji roboczej zostaną bezpowrotnie usunięte.*
{% endhint %}

<figure><img src="/files/6UuNdgrDQlsdQaxBmHZU" alt=""><figcaption><p align="center"><em><strong>Ilustracja 4.</strong> Popup z potwierdzeniem odblokowania artefaktu</em></p></figcaption></figure>


# Porównywanie zmian

Porównywanie zmian w elementach aplikacji umożliwia szybkie sprawdzenie różnic między dwiema wersjami tego samego komponentu lub między dwoma wyeksportowanymi elementami. Dzięki temu można:

* analizować zmiany wprowadzane przez zespół,
* weryfikować zgodność zależności,
* przygotować komponenty do migracji lub wdrożenia.

Funkcjonalności te dostępne są w zakładkach **Różnica** i **Porównaj artefakty**, znajdujących się w module **Przegląd** w Eximee Designer.

***

## Zakładka **Różnica** – porównanie wersji tego samego elementu

Pozwala porównać dwie wersje tego samego elementu aplikacji, np. formularza, skryptu czy komponentu złożonego.

**Jak działa?**

* Użytkownik wybiera element (np. formularz) z listy.
* Następnie wybiera dwie wersje: „lewą” i „prawą”.
* System prezentuje różnice między wersjami – mogą to być zmiany w treści, kodzie, strukturze czy właściwościach.

<figure><img src="/files/YZFwCNRaDN1uqmDZ4F2T" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Porównanie artefaktu w wersji 1.5 i 1.9</em></p></figcaption></figure>

{% hint style="info" %}
**Obsługiwane typy elementów:**

* formularze
* komponenty złożone
* komponenty biznesowe
* skrypty
* walidatory skryptowe
* zadania skryptowe
  {% endhint %}

Funkcjonalność ta pozwala na szczegółowy przegląd zmian przed zapisaniem nowej wersji, przy przeglądzie historycznym lub w pracy zespołowej.

***

## Zakładka **Porównaj artefakty** – porównanie dwóch wyeksportowanych elementów

Umożliwia porównanie dwóch plików `.xml` lub `.json` z wyeksportowanymi elementami aplikacji – skupiając się na ich **zależnościach**.

**Jak działa?**

Użytkownik przeciąga dwa pliki do pola **drag & drop**.

<figure><img src="/files/e8wl9J6MONDRCvQwXGVJ" alt=""><figcaption><p align="center"><em><strong>Ilustracja 2.</strong> Okno porównywania artefaktów</em></p></figcaption></figure>

System analizuje zależności i prezentuje listę różnic.

<figure><img src="/files/IqK5woFt6PV6wJoFHp15" alt=""><figcaption><p align="center"><em><strong>Ilustracja 3.</strong> Porównanie dwóch wyeksportowanych artefaktów</em></p></figcaption></figure>

**Typy wykrywanych różnic:**

* ➕ **Nowa zależność** – występuje tylko w drugim pliku.
* ➖ **Usunięta zależność** – występowała tylko w pierwszym pliku.
* 🔁 **Różnica wersji zależności** – zależność dotyczy tego samego elementu, ale z inną wersją.

Jeśli nie wykryto różnic, pojawia się komunikat: **„Brak danych do wyświetlenia”**.

#### Kiedy korzystać z porównywania?

* Przed publikacją nowej wersji komponentu – by upewnić się, co się zmieniło.
* W czasie code review – dla oceny zmian wprowadzonych przez zespół.
* Podczas migracji – aby porównać eksporty między środowiskami.
* W trakcie integracji – by upewnić się, że zależności są zgodne z oczekiwaniami.


# Model danych

### Czym jest model danych?

**Model danych** w platformie Eximee to centralny element, który opisuje **biznesową strukturę danych** wykorzystywanych w aplikacji low-code. Model pełni dwie funkcje:

* dokumentującą, dostarczając jednoznacznej informacji na temat źródła pochodzenia wartości każdego pola,
* techniczną, wykonując operacje konieczne do pozyskania wartości.

Model danych umożliwia modelowanie struktury danych w strukturze drzewa. Każdy węzeł drzewa reprezentuje obiekt dziedziny biznesowej aplikacji, np. wnioskodawca, pożyczka czy adres korespondencyjny. Każdy liść drzewa oznacza jedno pole przechowujące konkretną wartość.

Każde pole modelu ma określony sposób pozyskiwania wartości (tzw. *"źródło danych"*). Źródła mogą wyliczać dane **lokalnie**, na podstawie stałych wartości domyślnych, algorytmów zaimplementowanych w ScriptCode (np. PageService, ServiceTask, ...) oraz danych wprowadzane ręcznie przez użytkowników (np. na polach wniosku o pożyczkę, czy zadaniu analityka kredytowego). Wartości mogą też być pozyskiwane **zdalnie** z usług za pomocą REST API.

<figure><img src="/files/eBW4jRHpzyi8i2l5k1J6" alt=""><figcaption></figcaption></figure>

Dane opisane w modelu są przechowywane w wielu miejscach, niekoniecznie w komponentach platformy Eximee. Zadaniem modelu danych jest pobieranie wartości dla każdego pola ze wskazanego miejsca we odpowiednim momencie. Jest to zatem komponent **koordynujący pozyskiwanie danych**, nie tylko przechowujący je.

Każda aplikacja low-code posiada swoją definicję modelu danych. Nie ma konieczności tworzenia jednego, wspólnego *"mega-modelu"* odpowiadającego wszystkim obszarom instytucji. Model danych istnieje wyłącznie w **kontekście uruchomionej aplikacji** i nie jest globalny dla całej platformy. Oznacza to, że dla każdej uruchomionej aplikacji tworzona jest odrębna instancja modelu danych (patrz [Przechowywanie danych w modelu](/budowanie-aplikacji/model-danych/przechowywanie-danych-w-modelu))

{% hint style="info" %}
Dobry model danych może znacząco ułatwić utrzymanie i rozwój aplikacji. Możliwość szybkiej weryfikacji źródła danej wartości jest kluczowe przy analizie problemów oraz podczas planowania zmian rozwojowych w aplikacji. Pamiętaj o zrozumiałych nazwach obiektów i pól, konkretnej dokumentacji w opisach oraz o aktualizacji definicji modelu!
{% endhint %}


# Struktura modelu danych

## Struktura drzewa

{% columns %}
{% column %}
Model danych ma strukturę drzewa ułatwiającą odwzorowanie hierarchicznej struktury obiektów domeny biznesowej.

**Liście** drzewa reprezentują najbardziej szczegółowy element struktury. Liście, zwane polami, nie posiadają już żadnych innych elementów podrzędnych (dzieci) i reprezentują pojedyncze pole danych. Przykładami mogą być "imię klienta" czy "numer rachunku bankowego".

**Węzły** drzewa reprezentują obiekty złożone z innych obiektów i/lub pól. Przykłady: "adres korespondencyjny", "dochód klienta".
{% endcolumn %}

{% column %}

<figure><img src="/files/07Hok7uw4qzZE8WDZ4hR" alt="" width="216"><figcaption><p><em><strong>Ilustracja 1.</strong> Struktura drzewa</em></p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% hint style="info" %}
Istnieje możliwość zmiany kolejności węzłów i liści na drzewku poprzez ich przytrzymanie i przeciągnięcie. Zmiana kolejności jest możliwa wyłącznie w obrębie tego samego poziomu hierarchii oraz podczas pracy na wersji roboczej. Modyfikacja ta ma charakter wizualny i nie wpływa na logikę działania modelu.
{% endhint %}

### Węzły

Każdy węzeł modelu danych posiada atrybuty:

* klucz unikalny wśród swojego rodzeństwa (potomków tego samego węzła)
* liczebność wyrażoną wzorem `n..m` oznaczającym od `n` wystąpień minimalnie do `m` maksymalnie, np:
  * `1..1` - obiekt występuje tylko raz
  * `0..1` - obiekt jest opcjonalny
  * `1..null` - obiekt występuje co najmniej raz, bez ograniczenia na maksymalną liczbę wystąpień
* opis znaczenia obiektu dla aplikacji

{% hint style="info" %}
Węzły można zatem jednoznacznie wskazać za pomocą klucza powstałego poprzez złączenie kluczy węzłów nadrzędnych, np: `client.email`.
{% endhint %}

### Liście

Poza atrybutami węzłów, liście posiadają dodatkowo:

* źródła danych - określają jak i skąd pobierana jest wartość
* domyślna wartość - co zwróci pole, jeżeli żadne ze źródeł danych nie zwróci wartości

Pole może mieć zdefiniowaną listę źródeł danych. Rozstrzyganie wartości pola polega na wywoływaniu źródeł danych w kolejności ich zdefiniowania aż do uzyskania niepustej wartości. Zatem pierwsze źródło zwracające niepustą wartość wygrywa.

Dane z modelu możemy pobierać tylko dla wybranych przez nas pojedynczych kluczy, tj. nie możemy pobierać wartości kluczy, które mają pod sobą dzieci, tak jak nie możemy pobrać całego modelu w jednym zapytaniu.

## Tablice w modelu danych <a href="#strukturamodeludanychbudowanieiuzywanie-definiowanietablicowychpolmodeludanych" id="strukturamodeludanychbudowanieiuzywanie-definiowanietablicowychpolmodeludanych"></a>

Węzły modelu oznaczone jako wielokrotne (liczebność maksymalna `>1`) tworzą tablicę prostych wartości (dla pól) oraz złożonych obiektów (dla węzłów nie będących liśćmi). Możliwe jest również zdefiniowanie kolekcji zagnieżdżonych.

### Klucze i identyfikatory <a href="#strukturamodeludanychbudowanieiuzywanie-kluczeiidentyfikatory" id="strukturamodeludanychbudowanieiuzywanie-kluczeiidentyfikatory"></a>

Odwołując się do węzłów modelu danych zdefiniowanych jako tablica (lub będącymi potomkami tablicy) należy zawsze używać notacji tablicowej:

* tablica\[].pole - pobiera wszystkie wystąpienia pola; zależnie od używanego API zwróci kolekcję lub pojedynczy string z separatorem ","
* tablica\[0].pole - pobierze pojedynczą wartość rozwiązaną wierszem kolekcji wskazanym w kluczu (w przykładzie 0 oznacza pierwszy element tablicy),
* tablica.pole - spowoduje błąd, nie ma możliwości odniesienia się do tablicowego węzła bez notacji tablicy,

### Definiowanie tablicy <a href="#strukturamodeludanychbudowanieiuzywanie-definiowanietablicywmodeludanych" id="strukturamodeludanychbudowanieiuzywanie-definiowanietablicywmodeludanych"></a>

W celu zdefiniowania tablicowego pola konieczne jest:

* wielokrotny węzeł modelu danych musi posiadać krotność większą niż `multiplicityMax=1`, np. `1..null`,
* wielokrotny węzeł modelu danych musi mieć zdefiniowane źródła wskazujące na tablicę, indeksy tej kolekcji zostaną użyte do indeksacji powtórzeń wartości modelu,
* węzły poniżej wielokrotnego węzła modelu danych mogą w mapowaniu stosować indeks iterowanego węzła modelu do wskazania konkretnych elementów wyjścia usługi,
  * nadrzędny węzeł zawsze udostępni w kontekście wykonania swój bieżący indeks (w trakcie rozwiązywania wartości dla kolekcji) pod identyfikatorem *`nazwaWezłaIdx`,*
  * pola iterowane rodzicem powinny wskazywać na obiekty wewnątrz kolekcji, po której iteruje rodzic,
  * nie jest to jednak stricte konieczne, możliwe jest wykorzystanie tego indeksu do iterowania po zupełnie innym polu lub do wyciągania pól w ogóle nie będących tablicami.

{% hint style="info" %}
Przykładowo, mając wynik usługi, który składa się ze stałego pola i dwóch tablic - o których wiadomo, że mają tę samą długość (tablicaA, tablicaB, poleC) - możliwe jest stworzenie mapowania, w którym model iteruje po tablicyA, ale jego podpola wyciągają kolejne pola tablicyB i stałą wartość z polaC.
{% endhint %}

## Powiązanie providera z modelem danych

Provider to lokalne źródło danych napisane w [ScriptCode](https://docs.eximee.com/budowanie-aplikacji/logika-biznesowa/scriptcode/wprowadzenie-do-scriptcode), które definiuje sposób pozyskiwania wartości dla pól modelu. Może być wykorzystywane przez pola do zasilania ich watości. Źródłem danych może być funkcja:

* skryptowa,
* wywołująca zewnętrzną usługę REST,
* odwołująca się do innego elementu modelu,
* pobierająca wartość z konfiguracji aplikacji.

Opisany poniżej provider stanowi **źródło danych dla liścia modelu danych**. Służy ono do pobrania aktualnego kursu waluty z zewnętrznego API (NBP):

* `exchangeRate` jest **liściem (polem)** w drzewie,
* pole to nie posiada dzieci i reprezentuje pojedynczą wartość (kurs waluty),
* może być zagnieżdżone w węźle, np.: `exchangeRates.exchangeRateEUR`.

<figure><img src="/files/L35ZXkz8tERn5Ajhzc1a" alt="przykład z kodem providera"><figcaption><p><em><strong>Ilustracja 2.</strong> Przykład providera pobierającego aktualny kurs waluty z API (NBP)</em></p></figcaption></figure>

Przebieg działania:

* z parametrów wejściowych providera pobierany jest klucz, czyli kod waluty (`currencyCode`), np. „EUR” lub „USD”,
* wartość ta jest przekazywana do providera z modelu danych,
* provider wykonuje zapytanie GET do skonfigurowanego endpointu `nbpExchangeRate` przy użyciu `api.rest.v1.get`,
* parametry ścieżki (`pathParams`) budują adres zapytania w postaci: `/rates/A/{currencyCode}` (litera „A” oznacza tabelę średnich kursów walut publikowanych przez NBP),
* odpowiedź z API zawiera obiekt `body`, w którym znajduje się tablica `rates`, a z tablicy pobierany jest pierwszy element (`rates[0]`), następnie jego pole `mid`, które reprezentuje średni kurs waluty,
* provider zwraca obiekt zawierający pole `exchangeRate`, wartość tego pola odpowiada pobranemu kursowi waluty i może być dalej wykorzystana w modelu danych lub formularzu.

### Konfiguracja źródeł danych dla pola

Każde pole w modelu danych posiada możliwość zdefiniowania **źródeł danych**.\
Konfiguracja dostępna jest po kliknięciu ikony ołówka przy wybranym polu, co otwiera szufladę ustawień źródeł danych powiązanych z tym polem. Jeżeli dla danego klucza zostały już zdefiniowane źródła danych, ich nazwy są widoczne w panelu - w przedstawionym przykładzie jest to `exchangeRateFromNBPProvider`. Po wybraniu źródła możliwa jest konfiguracja parametrów wejściowych oraz mapowania wyjścia.

<figure><img src="/files/WcZAk9WD1q0m1aGGtoex" alt="przykład z kodem providera"><figcaption><p><em><strong>Ilustracja 3.</strong> Przykład wykorzystania providera jako źródła danych w modelu</em></p></figcaption></figure>

W zakładce **Parametry** definiowane są wartości przekazywane do providera.\
W opisywanym przypadku:

* klucz: `currencyCode`
* wartość: `EUR`

Parametr ten jest wykorzystywany przez provider do wywołania zewnętrznego API.

W sekcji **Mapowanie** określane jest, które dane z odpowiedzi providera zostaną przypisane do pola w modelu. W tym przykładzie mapowana jest wartość `exchangeRate`.

Uzyskana wartość może być następnie wykorzystana w modelu danych lub bezpośrednio w formularzu. Więcej o wykorzystaniu modelu danych na wniosku w zakładce [Model danych na interfejsie](https://docs.eximee.com/~/revisions/6RARJsssdz6tDsOideLu/budowanie-aplikacji/interfejs-uzytkownika/formularze/praca-z-komponentami-bazowymi/model-danych-na-interfejsie).


# Przechowywanie danych w modelu

## Inicjalizacja modelu

Model danych dla aplikacji jest tworzony w momencie wystartowania instancji aplikacji (patrz [Uruchamianie aplikacji](/budowanie-aplikacji/aplikacja-biznesowa/uruchamianie-aplikacji)) . Po stworzeniu modelu może on dostarczać wartości dla pól, zgodnie z definicją źródeł danych. Oraz przyjmować wartości dla pól przechowywanych lokalnie.

## Miejsce zapisu danych

Dane zapisane w modelu możemy podzielić na dwa rodzaje - z uwagi na miejsce przechowywania oraz to, kto nimi zarządza.

### Dane pobierane z usług

Jeżeli aplikacja korzysta z danych zapisanych i zarządzanych przez systemy organizacji lub zewnętrzne, są one pobierane za pomocą usług. Aplikacja low-code nie jest właścicielem tych danych, nie może ich modyfikować i nie kontroluje zmian ich wartości.

Wartości pobierane są z usługi i zawsze aktualne, z dokładnością do cache (patrz [Edycja modelu danych](/budowanie-aplikacji/model-danych/edycja-modelu-danych#zrodlo-danych)).

Przykłady

* aktualny adres klienta
  * klient składa wniosek o zakup ubezpieczenia
  * po złożeniu wniosku, a przed wygenerowaniem umowy sprzedaży, klient zmienia dane adresowe zapisane w banku (zazwyczaj przez dedykowany proces)
  * na umowie sprzedaży ubezpieczenia mamy zaktualizowany adres - zostanie on pobrany w procesie zgodnie z definicją danych w modelu
* saldo rachunku
  * podczas przyjmowania dyspozycji aplikacja weryfikuje czy na wskazanym przez klienta rachunku znajdują się odpowiednie środki do pokrycia kosztów obsługi
  * przed faktycznym pobraniem środków aplikacja może ponownie zweryfikować środki, aby poprawnie obsłużyć obciążenie rachunku

### Dane przechowywane w modelu

Kiedy dane są tworzone i zarządzane przez aplikację, są one przechowywane w modelu danych. Aplikacja low-code jest ich właścicielem, może je modyfikować i kontroluje zmiany ich wartości.

Przykłady

* wnioskowany limit karty kredytowej
  * podczas składania wniosku o kartę kredytową klient podaje wartość oczekiwanego limitu
  * aplikacja może zmienić tę wartość w trakcie obsługi procesu (np. zmniejszyć)
  * na wygenerowanej umowie (i zapewne w komunikacji do klienta) mamy aktualną wartość limitu
* adres korespondencyjny klienta do obsługi procesu
  * podczas składania wniosku kredytowego klient podaje adres korespondencyjny
  * domyślnie aplikacja prezentuje adres zapisany w systemach banku (pobrany z usługi)
  * klient jednak może zmienić ten adres i życzyć sobie korespondencji dotyczącej tego procesu na inny adres
  * aplikacja zachowuje wartości wprowadzone przez klienta

## Dane poza modelem

Aplikacja low-code nie musi przechowywać wszystkich danych w modelu. Cześć danych ma charakter tymczasowy i służy jedynie do wyznaczenia docelowej wartości lub podjęcia decyzji, np:

* lista rachunków klienta
  * generuje dziedzinę wyboru konta z komponentu Pola wyboru wartości z listy
  * pozwala klientowi łatwo wybrać konkretny rachunek
  * w modelu danych chcemy mieć tylko wybrany przez Klienta rachunek, cała lista nie jest nam potrzebna
* wiek klienta
  * pozwala podjąć decyzję o możliwości zakupienia produktu (np. *Karta <26*)
  * jest wyliczany z numeru PESEL

Dane tymczasowe, operacyjne mogą być zachowywane w zmiennych sesyjnych na formularzach, zmiennych procesowych lub w zmiennych skryptów.


# Tworzenie modelu danych

Aby utworzyć model danych w aplikacji wystarczy przejść do widoku modelu danych i nacisnąć przycisk *Inicjalizuj model danych*.

<figure><img src="/files/kxtQkipOTWOC84eZau5P" alt=""><figcaption></figcaption></figure>

Po inicjalizacji model danych pozostaje częścią aplikacji low-code. Platforma Eximee będzie automatycznie go migrować pomiędzy środowiskami oraz uruchamiać wraz ze startem aplikacji.


# Edycja modelu danych

## Edytor modelu danych

Do edytora modelu danych przechodzimy wybierając "Model danych" na ekranie głównym aplikacji w Eximee Designer

<figure><img src="/files/dTbABT36RhCrCfuQRNNH" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Zakładka "Model danych" aplikacji low-code</em></p></figcaption></figure>

Edytor modelu danych podzielony jest na trzy zakładki:

* *Struktura,* gdzie zarządzamy strukturą modelu oraz uzupełniamy parametry węzłów,
* *Źródła danych*, gdzie definiujemy i parametryzujemy źródła danych,
* *Źródło*, gdzie edytujemy JSON będący źródłową reprezentacją modelu - funkcjonalność dla zaawansowanych użytkowników.

{% hint style="info" %}
Jeżeli Twoja aplikacja nie posiada jeszcze modelu danych możesz go utworzyć klikając przycisk "Inicjalizuj model danych".
{% endhint %}

## Struktura

Struktura modelu danych prezentowana jest w formie drzewa na lewym panelu edytora. Gałęzie drzewa można zwijać i rozwijać.

<figure><img src="/files/9JnPmmIMJw6UuDJQruoq" alt=""><figcaption><p><em><strong>Ilustracja 2</strong>. Prezentacja struktury modelu danych</em></p></figcaption></figure>

Zaznaczenie węzła drzewa powoduje automatyczne filtrowanie węzłów na liście po prawej stronie.

<figure><img src="/files/xgilgb4zh12jJyroFDoY" alt=""><figcaption><p><em><strong>Ilustracja 3.</strong> Zaznaczenie węzła w edytorze modelu danych</em></p></figcaption></figure>

Na górze listy węzłów wypisany jest klucz stanowiący aktualny filtr widoku: *"client.surname"* w tym przypadku.

## Parametryzacja elementów modelu

### Węzeł

<figure><img src="/files/EKSDFKzzp5r8EYrfv76P" alt=""><figcaption><p><em><strong>Ilustracja 3.</strong> Edycja węzła modelu</em></p></figcaption></figure>

W sekcji edycji węzła modelu można edytować klucz oraz dokumentację (*"opis"*) obiektu. Można również oznaczyć obiekt jako tablica.

{% hint style="info" %}
Przy kluczu obiektu znajduje się przycisk kopiujący klucz do schowka systemowego.
{% endhint %}

W menu kontekstowym znajduje się opcja usuwania węzła razem z jego potomkami.

Aby dodać pole do węzła należy kliknąć przycisk *"Dodaj pole"*.

### Pole

Sekcja pola w modelu danych posiada dodatkowo możliwość podania domyślnej wartości dla pola.

<figure><img src="/files/Pz3qxOxMXUloRW4HLRJ6" alt=""><figcaption><p><em><strong>Ilustracja 4.</strong> Pole w modelu</em></p></figcaption></figure>

### Źródło danych

Kliknięcie na chips źródła danych lub ikonę ołówka obok otwiera szufladę z listą źródeł danych i możliwością edycji użycia (kolejność źródeł, parametry źródła, mapowanie wartości).

<figure><img src="/files/xbNG112IwXIP2vCQ0GCF" alt=""><figcaption><p><em><strong>Ilustracja 5.</strong> Użycie źródła danych</em></p></figcaption></figure>

Domyślnie, dla każdego **liścia** drzewa modelu danych (czyli pola które nie posiada dalszych pod-pól) platforma automatycznie dodaje specjalne źródło danych typu **ValueMap**. Jest to wbudowane źródło, które przechowuje wartość pola w strukturze pamięci aplikacji (w tzw. mapie wartości wniosku) – można to traktować jako odpowiednik zmiennej sesyjnej przechowującej dane w kontekście całej aplikacji (formularza). Domyślne mapowanie ValueMap wykorzystuje pełną ścieżkę kluczy danego pola jako klucz w tej wewnętrznej mapie (np. dla pola `kraj` znajdującego się wewnątrz obiektu `daneOsobowe` klucz w mapie wartości będzie `daneOsobowe.kraj`). Dzięki temu po związaniu pól formularza z modelem, **nie jest wymagane pisanie dodatkowego kodu do zapisywania wprowadzonych danych** – wartość wprowadzona przez użytkownika zostanie automatycznie umieszczona pod odpowiednim kluczem w pamięci modelu.

#### Źródło danych - defensywna logika i puste wartości

Źródła modelu danych nie mogą zakładać deterministycznej kolejności wywołań ani tego, że wszystkie dane wejściowe są już dostępne. Platforma może wywołać źródło wcześniej (np. przy ustalaniu krotności dynamicznych sekcji formularza lub modelu), nawet jeśli dane pole nie jest jeszcze używane wprost w formularzu czy procesie.

Dlatego źródła danych muszą być projektowane defensywnie: w sytuacji braku danych, danych niekompletnych lub „jeszcze niegotowych” powinny zwracać bezpieczne, puste wartości (null, pustą listę, pusty obiekt) i nie zgłaszać wyjątków. Pusta wartość oznacza: na tym etapie nie potrafię określić wartości i pozwala zadziałać kolejnym źródłom w kaskadzie, w szczególności źródłom domyślnym (np. ValueMap lub domyślne wartości na definicji pola).

Wyjątki należy rezerwować wyłącznie dla rzeczywistych błędów technicznych (np. błędów komunikacji lub niepoprawnej konfiguracji), które powinny przerywać działanie systemu (przerwanie formularza, wycofanie transakcji procesu itp.), a nie dla stanów przejściowych procesu.


# Wykorzystanie modelu danych

Model danych można wykorzystywać na interfejsie użytkownika (patrz [Model danych na interfejsie](/budowanie-aplikacji/interfejs-uzytkownika/formularze/praca-z-komponentami-bazowymi/model-danych-na-interfejsie) oraz w procesie biznesowym (patrz [Model danych w procesie](/budowanie-aplikacji/proces-biznesowy/model-danych-w-procesie))


# API modelu danych

W skryptach, walidatorach oraz zadaniach skryptowych możemy korzystać z API modelu danych

```
interface Model {
   get(key || key[] :string): string;                    // Pobranie zmiennej z modelu danych o wskazanym id
   indexes(key[] : string): List<String>;                // Pobieranie indexy podanego klucza z tablicy
}
```

### GET

Aby skorzystać z wartości z modelu danych, należy posłużyć się API zaprezentowanym w poniższym fragmencie kodu:

```js
function callService(input){
    const valueFromModel = api.model.v1.get("user.pesel"); // Pobranie peselu z pojedynczego node modelu -> "12312312311"
    let customersLastName = api.model.v1.get("BazaOfert.Kredytobiorcy[0].Nazwisko") // Pobranie nazwiska z indexu 0 -> "Kowalski"
    let customersPesel = api.model.v1.get("BazaOfert.Kredytobiorcy[].PESEL") //Pobranie wszystkie Pesele z tablicy -> "74082109492,49020106066"
    return [{'output':customerLastName}]
}
```

### INDEXES

Aby pobrać listę indeksów dla tablicy, należy posłużyć się API zaprezentowanym w poniższym fragmencie kodu:

```js
 const answersIndexes = api.model.v1.indexes("Survey.Questions[]")
 let surveyResults = answersIndexes.map((idx) => {
        return {
            "question": api.model.v1.get(`Survey.Questions[${idx}].Content`),
            "answer": api.model.v1.get(`Survey.Questions[${idx}].Answer`)
        }
    })
```


# Integracja z zewnętrznymi systemami poprzez REST API

Zasilenie pól modelu danymi zwracanymi z usług REST jest możliwe poprzez podpięcie skryptowego ([ScriptCode](/budowanie-aplikacji/logika-biznesowa/scriptcode)) providera.


# Bazy projekcji low-code

#### Wprowadzenie: Czym jest baza projekcji Low-Code?

Baza projekcji low-code (*Eximee Registry*) to wewnętrzny mechanizm platformy Eximee, który pozwala na przechowywanie i przekazywanie danych pomiędzy różnymi instancjami tej samej aplikacji lub pomiędzy wieloma osobnymi aplikacjami low-code. Działa ona jak wspólny schowek na informacje, który low-coder może samodzielnie obsługiwać z poziomu Eximee Designer za pomocą prostych skryptów (ScriptCode).

#### Do czego służy ten mechanizm?

Narzędzie to powstało po to, aby aplikacje budowane w low-code mogły łatwo dzielić się wiedzą o bieżących sprawach bez konieczności tworzenia ciężkich, programistycznych integracji backendowych. Warstwa low-code zyskuje dzięki temu pełną niezależność w zarządzaniu stanem swoich procesów.

W praktyce low-coder używa bazy projekcji do:

* **Agregacji kontekstu rozbitego na wiele spraw:** Przechowywania powiązań między różnymi aplikacjami low-code, na przykład lista wnioskowanych obecnie kredytów na PESEL klienta
* **Adresacji danych przychodzących:** Przechowywanie par *identyfikator zewnętrzny*:*identyfikator wewnętrzny* pozwalających optymalnie odnaleźć sprawę, której należy przekazać zdarzenie z Kafka lub MQ

#### Co bazy projekcji dają Low-Coderom?

Najważniejsze wartości, jakie dają Low-Coderom bazy projekcji:

1. **Brak konieczności angażowania programistów:** Jako Low-Coder możesz samodzielnie zapisywać dane poza kontekstem jednej aplikacji, w pełni zarządzając strukturą danych.
2. **Szybki dostęp do danych:** Z poziomu Low-Code możesz szybko odszukać zestaw danych, którego potrzebujesz. Masz pełną kontrolę nad kluczem wyszukiwania.
3. **Izolacja i dedykowany zakres:** Dzięki podziałowi baz projekcji na przestrzenie nazw (*namespace*) masz komfort działania bez wpływu na inne zespołu. Możesz współdzielić przestrzenie aby wymieniać się informacjami z innymi aplikacjami, ale nie musisz.

#### Jak korzystać z Bazy Projekcji w ScriptCode?

Dostęp do bazy projekcji (*Eximee Registry*) masz zapewniony bezpośrednio z poziomu każdego skryptu ScriptCode uruchamianego w kontekście formularza (np. w walidatorach, serwisach stron, EntryService czy ExitService), na poziomie obsługi zadań automatycznych procesu czy konsumentów zdarzeń z Kafka/MQ. Wszystkie operacje realizujesz za pomocą wbudowanego interfejsu `api.registry`

{% content-ref url="/pages/EFGCHzyQoetdv6UD1ym7" %}
[Obsługa baz projekcji (Registry)](/budowanie-aplikacji/logika-biznesowa/scriptcode/script-code-bazy-projekcji)
{% endcontent-ref %}


# Dobre praktyki przy tworzeniu modelu danych

## Wprowadzenie do modelowania danych

Tworząc model danych dla aplikacji w Eximee, należy kierować się zasadami, które ułatwią utrzymanie systemu oraz zapewnią spójność danych w skali całej organizacji. Dobrze zaprojektowany model to fundament sprawnego przepływu informacji między interfejsem użytkownika a silnikiem procesowym.

### Standardy nazewnictwa kluczy

Skuteczny model danych powinien być intuicyjny. Przy projektowaniu kluczy stosuj poniższe standardy techniczne:

| Aspekt               | Zasada                                                              | Przykład (Dobrze)       | Przykład (Źle)     |
| -------------------- | ------------------------------------------------------------------- | ----------------------- | ------------------ |
| **Format**           | Stosuj camelCase, jeden język (angielski), brak znaków PL i spacji. | `startDateOfEmployment` | `Data_Rozpoczecia` |
| **Logika (Boolean)** | Zaczynaj od `is` lub `has`.                                         | `isPoliticallyExposed`  | `czy_pep`          |
| **Wzorzec "of"**     | Używaj konstrukcji "of" dla jasności kontekstu.                     | `countryOfResidence`    | `residenceCountry` |
| **Identyfikatory**   | Unikaj generycznego `id`. Dodawaj kontekst biznesowy.               | `customerId`            | `id`               |

### Zasady projektowania struktury i rozwoju

Poniższe reguły definiują podejście do architektury modelu i jego ewolucji w czasie:

| Zasada                     | Opis i uzasadnienie biznesowe                                                                                                                                                                                                             |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Hierarchia i struktura** | Struktura drzewa musi odpowiadać naturalnej hierarchii danych biznesowych. Grupuj pola w obiekty semantyczne (np. `customerData.name` lub `registerAddress`). Ułatwia to mapowanie całych struktur do usług i zwiększa czytelność modelu. |
| **Dane vs Obliczenia**     | Przechowuj dane źródłowe (np. daty), a nie wartości zmienne lub wyliczalne (np. wiek). Jeśli wyliczenie jest niezbędne, dodaj je jako pole obok zasilane dynamicznie przez provider.                                                      |
| **Unikanie duplikacji**    | Przed dodaniem pola sprawdź, czy podobna informacja już istnieje. Różne obiekty (np. adresy) powinny dzielić te same nazwy kluczy wewnętrznych (np. `streetName`), aby zachować spójność technologiczną.                                  |
| **Strategia YAGNI**        | Nie modeluj struktury „na zapas”. Dodawaj tylko te pola, które są rzeczywiście wymagane na obecnym etapie procesu. Nadmiarowy model utrudnia analitykę.                                                                                   |
| **Reużywalność**           | Projektując nową strukturę, traktuj istniejące modele w innych aplikacjach jako punkt odniesienia. Zachowuj jednolite nazewnictwo tych samych pojęć w skali całej organizacji.                                                            |
| **Aktualizacja wymagań**   | Przy każdej modyfikacji procesu BPMN (np. dodanie lub usunięcie kroku) lub formularza (np. dodanie nowej sekcji z danymi) wykonaj analizę wpływu na model danych. Brak synchronizacji to najczęstsza przyczyna błędów.                    |

### Dokumentacja i parametry techniczne

Model danych w Eximee to nie tylko struktura, ale również metadane ułatwiające integrację i utrzymanie:

| Parametr                    | Zasada i dobre praktyki                                                                                                                                       |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Atrybut `docs`**          | Dokumentuj znaczenie biznesowe oraz kontekst kluczy i providerów. W dokumentacji aplikacji stosuj pełną notację kropkową (np. `customerData.address.street`). |
| **Wartość `defaultValue`**  | Pozwala na przypisanie domyślnej wartości (np. flaga `false`), gdy źródła nie dostarczą danych. Zapobiega to błędom typu `null pointer`.                      |
| **Krotność (Multiplicity)** | Parametry muszą precyzyjnie oddawać logikę biznesową. Dla pól wymaganych `Min=1`. Dla list o nieograniczonej długości stosuj `Max=null`.                      |
| **Logika źródeł**           | Dokumentuj kolejność i mapowania dostawców (providers). Pamiętaj - pierwsze źródło, które zwróci wartość inną niż `null`, ma pierwszeństwo.                   |

## Typowe błędy i jak ich unikać

Poniżej przedstawiono przegląd najczęstrzych błędów popełnianych przy tworzeniu modelu danych oraz jego wykorzystaniu - ich przyczyny, skutki oraz jak ich unikać.

| Błąd                          | Przyczyna                                               | Skutek                                                                                                   | Rozwiązanie                                                                                                                                                                                                            |
| ----------------------------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Brak powiązania z formularzem | Zapomniano ustawić "Klucz modelu danych" w komponencie. | Dane nie są zapisywane (pole puste po odświeżeniu).                                                      | Ustaw klucz w właściwościach komponentu, wpisując dokładny klucz pola z modelu danych. Po zapisaniu formularza komponent zapisze swoją wartość do tego pola, a przy uruchomieniu pobierze z modelu istniejącą wartość. |
| Literówki i niezgodności nazw | Ręczne wpisywanie nazw w opcji "Klucz modelu danych".   | Komponent nie połączy się z właściwym polem w modelu danych - wartość nie zapisze się do modelu.         | "Używaj ikony kopiowania obok klucza w modelu danych.                                                                                                                                                                  |
| Błędne użycie tablic          | Pominięcie notacji indeksowej (np. `produkty.cena`).    | Składnia bez \[] lub indeksu jest niepoprawna i spowoduje błąd uniemożliwiający uruchomienie formularza. | W sekcjach powtarzalnych stosuj notację `produkty[].cena`.                                                                                                                                                             |
| Niewidoczny model danych      | Brak artefaktu w aplikacji.                             | Model nie został zainicjowany.                                                                           | Użyj przycisku "Zainicjuj model danych" w zakładce "Model danych" aplikacji.                                                                                                                                           |


# Interfejs użytkownika


# Formularze

Formularze w **Eximee Designer** stanowią podstawowy element aplikacji biznesowej i służą do tworzenia interfejsu użytkownika, w którym dane są wprowadzane, prezentowane i przekazywane dalej do procesów oraz usług.

Projektowanie formularza obejmuje dodawanie niezbędnych komponentów - [bazowych](/budowanie-aplikacji/interfejs-uzytkownika/formularze/praca-z-komponentami-bazowymi), [złożonych](/budowanie-aplikacji/interfejs-uzytkownika/komponenty-rozszerzone/komponenty-zlozone) i innych elementów wykorzystywanych w aplikacji. Prace projektowe prowadzi się w zakładce [**Wniosek**](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza), natomiast strukturą formularza (kroki i strony) zarządza się w zakładce [**Kroki**](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/kroki-i-strony-formularza).

Dodatkowe obszary edycji to:

* **Tłumaczenia** – definiowanie treści w wielu językach,
* **Model danych** – mapowanie pól formularza na dane procesowe,
* **Właściwości** – konfiguracja zapisu, wyglądu i przepływów, serwisów wejścia i wyjścia,
* **Źródło** – podgląd definicji formularza w formacie XML,
* **Audyt** – podgląd naruszeń wykrytych na formularzu, obejmujących zgodność z wymaganiami WCAG.


# Tworzenie formularza


# Kroki i strony formularza

**Kroki** i **strony** to podstawowe elementy struktury formularza w Eximee Designer, które pozwalają organizować wieloetapowe formularze. **Krok** grupuje jedną lub więcej stron i reprezentuje logiczny etap formularza (np. etap zbierania danych współwłaścicieli firmy, danych o dochodach kredytobiorcy lub podsumowanie wniosku), a **strona** to pojedynczy ekran/podstrona zawierający konkretne pola i komponenty. Projektant definiuje w ten sposób ścieżkę nawigacji użytkownika – określa kolejność kroków, znajdujące się w nich strony oraz warunki ich wyświetlania. W interfejsie użytkownika kroki mogą być sygnalizowane za pomocą belki postępu (tzw. belki kroków) – jej widoczność konfiguruje się w zakładce **Właściwości.**

<figure><img src="/files/VnomXHeHGna0CnnQcS0Y" alt=""><figcaption><p>Ilustracja 1. Przykładowy widok belki kroków na wniosku.</p></figcaption></figure>

## Zakładka „Kroki” – edycja struktury formularza

Strukturą kroków i stron zarządzamy w zakładce **Kroki** edytora wniosku. Po otwarciu formularza zakładka ta jest domyślnie wyświetlana w trybie podglądu (tylko do odczytu). Widać tam listę wszystkich kroków i należących do nich stron – dla każdego elementu pokazany jest **identyfikator biznesowy (mid)**, **tytuł** (jeśli nadano) oraz **warunek widoczności** (wyrażenie warunkowe określające, czy dany krok/strona ma się wyświetlić).

{% hint style="warning" %}
*Uwaga:* warunki te nie są w tym widoku wykonywane, a jedynie prezentowane informacyjnie.
{% endhint %}

Aby edytować strukturę, należy przełączyć zakładkę **Kroki** w tryb edycji (ikona „ołówka” – **Edytuj proces**) – może być konieczne uprzednie zwolnienie ewentualnej blokady roboczej (szkicu) formularza. W trybie edycji można dodawać i usuwać kroki oraz strony, edytować ich podstawowe właściwości, a także zmieniać kolejność za pomocą mechanizmu *drag & drop.* Należy przy tym pamiętać o kilku zasadach:

* **Nie można usunąć wszystkich kroków!** – w formularzu musi pozostać przynajmniej jeden krok.
* **Dodanie nowego kroku** automatycznie tworzy nową stronę wewnątrz tego kroku (krok nie może być pusty).
* **Usunięcie kroku** powoduje usunięcie wszystkich stron, które on zawiera.
* **Przenoszenie stron między krokami** odbywa się poprzez przeciąganie myszą. Można np. przeciągnąć stronę z jednego kroku do innego.
* **Usuwanie poszczególnych stron** lub kroków jest dostępne z menu kontekstowego (ikona „kosza” przy elemencie). Dla strony dodatkowo dostępna jest opcja „Otwórz”, która przenosi do edycji zawartości tej strony w zakładce **Wniosek**.

> **Tip:** Belka postępu (kroków) wyświetlana użytkownikowi może być w razie potrzeby ukryta – służy do tego opcja *Widoczność belki kroków* w zakładce **Właściwosci**.

### Właściwości kroków

**Każdy krok posiada zestaw podstawowych właściwości definiujących jego rolę w formularzu.**\
W Eximee Designer są one widoczne zarówno w zakładce **Kroki**, jak i w zakładce [**Źródło**](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/podglad-definicji-formularza-xml).\
W zakładce **Kroki** właściwości te są dostępne jako pola tekstowe, które można uzupełnić zgodnie z podpowiedziami wyświetlanymi w tych polach.\
W zakładce **Źródło** te same właściwości występują pod swoimi technicznymi identyfikatorami:

* id – unikalny identyfikator kroku (wewnętrzna nazwa techniczna). Kroki domyślnie otrzymują ID w formie `Step1`, `Step2` itd. Jego edycja dostępna jest jedynie z poziomu zakładki [**Źródło**](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/podglad-definicji-formularza-xml).
* **titleKey** – klucz tłumaczeniowy tytułu kroku. Domyślnie przyjmuje wartość `StepX.title` (gdzie X to ID kroku). Ustawienie lub edycja odpowiedniego tytułu jest możliwa w zakładce **Kroki** gdzie można szybko dodać lub edytować tytuł dla głównego języka wniosku lub zakładce **Tłumaczenia** po wyszukaniu interesujacego nas kroku gdzie mozna dodawać lub edytować tytuł dla różnych języków zawartych w wniosku.
* **visibleCondition** – warunek widoczności kroku, zapisany w postaci wyrażenia logicznego. Jeśli warunek jest **niespełniony**, dany krok zostanie **automatycznie pominięty** podczas prezentacji wniosku użytkownikowi. W warunku można odwołać się do wartości pól lub zmiennych sesyjnych (szczegóły składni patrz rozdział [*Język wyrażeń*](/budowanie-aplikacji/interfejs-uzytkownika/formularze/dynamicznosc-formularza/jezyk-wyrazen) w dokumentacji). Warunek można również skonfigurować w zakłądce **Kroki –** w polu „Dodaj warunek” przy odpowiednim kroku.\
  Przykładowo, aby krok był widoczny tylko gdy użytkownik zaznaczył checkbox o ID `GesCheckbox1`, warunek może wyglądać następująco:

```javascript
// Warunek widoczności kroku (przykład)
getValue("GesCheckbox1") == "true"
```

Ten warunek zwróci "true" w przypadku gdy Checkbox1 zostanie zaznaczony, co spowoduje pojawienie się kroku, w którym warunek został użyty.

{% hint style="warning" %}
Uwaga!

Zdefiniowanie warunku widoczności dla kroku nie powoduje automatycznej aktualizacji belki kroków. Aby widoczność kroku odświeżała się dynamicznie, należy dla wszystkich stron znajdujących się w tym kroku:

* ustawić taki sam warunek widoczności,
* dodać nasłuchiwanie na komponenty użyte w warunku (zakładka **Wniosek** → Właściwości strony → sekcja **Interakcje)**.
  {% endhint %}

Pamiętaj, że id kroku jest wartością unikalną i najlepiej go nie zmieniać po utworzeniu kroków (jest on powiązany np. z kluczami tłumaczeń i logiką). Natomiast *tytuł* i *warunek widoczności* można w każdej chwili modyfikować – zmiany te wpływają na zachowanie i wygląd formularza podczas wypełniania.

## Właściwości stron

Każda strona formularza posiada rozbudowany zestaw właściwości, podzielonych w edytorze na sekcje tematyczne: **Podstawowe właściwości**, **Układ, Jakość danych**, **Interakcje**, **Stylizacja**, **WCAG** oraz **Pozostałe**. Aby edytować właściwości konkretnej strony, należy otworzyć tę stronę w trybie edycji w zakładce **Wniosek** (np. klikając na liście w zakładce Kroki nazwę strony lub wybierając opcję „Otwórz”) i następnie kliknąć w puste tło strony – w prawym panelu pojawią się właściwości strony.\
**Uwaga:** niektóre podstawowe właściwości (identyfikator, tytuł, warunek widoczności) można również zmieniać z poziomu listy w zakładce **Kroki**, jednak większość ustawień jest dostępna wyłącznie w edycji strony.

Poniżej zestawienie kluczowych właściwości strony według sekcji:

#### Podstawowe właściwości strony

* **Id** – unikalny identyfikator strony. Id automatycznie przyjmuje kolejną wartość `PageX` (gdzie X odpowiada nr strony) przy tworzeniu nowej strony i nie można go zmienić w edytorze graficznym – jest to tylko możliwe w zakładce **Źródło**. **Id** musi być unikalny w ramach formularza i jest widoczny w adresie url podczas wypełniania wniosku.
* **Identyfikator biznesowy (mid)** – opcjonalny „przyjazny” identyfikator strony. Domyślnie **mid** jest taki sam jak **Id** strony ale można nadać my własną nazwę biznesową. Jest również edytowalny w zakładce **Kroki,** klikając pierwszą kolumnę w wierszu strony. **Mid p**owinien być unikalny.
* **Tytuł** – tytuł strony wyświetlany użytkownikowi (np. Podsumowanie). Można wpisać tekst statyczny, pozostawić pusty lub uzupełnić w zakładce **Tłumaczenia** jeśli strona ma mieć tytuł w różnych językach.
* **Tytuł (klucz)** – klucz tłumaczenia tytułu strony. Działa analogicznie do *titleKey* kroku – pozwala zdefiniować tytuł w różnych językach (wartość domyślna to np. `PageX.title` gdzie X to numer strony). W zakładce **Tłumaczenia** można dodać odpowiednie wpisy dla tego klucza.
* **Numer strony** – numer porządkowy, wskazujący, którą z kolei stroną wniosku jest dany ekran. Jest to pole tylko do odczytu (system sam numeruje strony w kolejności ich występowania w strukturze).
* **Etykieta przycisku "Dalej/Wyślij"** – pozwala zdefiniować niestandardowy tekst nawigacyjnego przycisku przechodzenia do następnej strony bądź wysłania wniosku, widocznego na danej stronie(np. „Zobacz podsumowanie” zamiast „Dalej”). Domyślnie przycisk ma etykietę „**Dalej**” lub „**Wyślij** **wniosek**” na ostatniej stronie.
* **Etykieta przycisku "Dalej/Wyślij" (klucz)** – klucz tłumaczenia etykiety przycisku. Jest automatycznie uzupełniany przez formularz wartością `PageX.nextButtonLabel` (gdzie X to numer strony). Jeśli formularz jest wielojęzyczny, należy dodać odpowiednie wartości w zakładce **Tłumaczenia.**\
  \&#xNAN;*Hierarchia wyświetlania etykiety przycisku:* jeżeli dla strony nie zdefiniowano własnej etykiety przycisku, w polu stosowana jest etykieta podana z zmiennych sesyjnych `nextButtonText` / `submitButtonText`, a w dalszej kolejności wykorzystywane są globalne klucze platformowe (`iew.navigation.next` / `iew.navigation.submit`).

#### Układ

* **Liczba kolumn** – pole przedstawia liczbę kolumn zdefiniowaną dla danego formularza. Pole jest nieedytowalne z poziomu zakładki **Wniosek.** Zmiana w zakładce **Źródło** została opisana w [Edycji stron](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/edycja-stron)

#### Jakość danych

* **Warunek widoczności** – formuła (wyrażenie), która określa, czy strona ma być pokazana użytkownikowi. Jeśli warunek zwróci wartość `false`, strona zostanie pominięta podczas wyświetlania wniosku (użytkownik jej nie zobaczy). Warunki piszemy jako wyrażenia JavaScript – możemy korzystać z funkcji takich jak `getValue("idKomponentu")` (pobranie wartości komponentu o podanym identyfikatorze) czy `isVisible("idKomponentu")` (sprawdzenie widoczności komponentu). Więcej przykładów zostało opisanych w [Język wyrażeń definiowania warunków (warunki z getValue)](/budowanie-aplikacji/logika-biznesowa/jezyk-wyrazen-definiowania-warunkow-warunki-z-getvalue)\
  Edytor warunków podpowiada dostępne składnie, identyfikatory pól i nazwy zmiennych. Przykładowy warunek dla strony, która ma się pojawić tylko jeśli pole wyboru ma określoną wartość:

```javascript
// Strona widoczna tylko gdy wybrano w polu "typWniosku" wartość "A"
getValue("typWniosku") == "A"
```

* **Walidatory** – pole które pozwala na podpięcie dodatkowych reguł sprawdzających poprawność danych wprowadzonych na stronie. Dodawanie walidatorów odbywa się poprzez dołączenie odpowiedniego walidatora skryptowego – wiecej informacji można znaleźć w sekcji [Walidacje złożone (własne)](/budowanie-aplikacji/interfejs-uzytkownika/formularze/praca-z-komponentami-bazowymi/walidacja-wartosci-komponentow/walidacje-zlozone-wlasne)

#### Interakcje

* **Nasłuchiwanie** – mechanizm odpowiadający za **dynamiczne odświeżanie** stanu strony/komponentu/zmiennej w reakcji na zmiany w nasłuchiwanych elementach. Oznacza to, ze jeżeli np. warunek widoczności strony odwołuje się do wartości innego komponentu, należy dodać ten komponent do atrybutu **Nasłuchiwanie**. Dzięki temu zmiana wartości tamtego komponentu spowoduje ponowne przeliczenie/odświeżenie warunku i ewentualne pokazanie/ukrycie strony. W atrybucie **Nasłuchiwanie,** można wskazać wiele komponentów.\
  Edycja odbywa się przez okno listy – po kliknięciu przycisku **Lista,** pojawia się popup z listą dostępnych komponentów. Można je wyszukać podając zarówno **Id** jak i **mid**. W popupie widoczne są również komponenty już wybrane - nie da sie wybrać dwa razy tego samego.\
  \&#xNAN;*Przykład:* jeśli strona ma **Warunek widoczności** zależny od pola `umowaCheckbox`, należy dodać `umowaCheckbox` do **Nasłuchiwania** tej strony. Analogicznie postępujemy dla warunków kroków – ponieważ krok nie ma własnego atrybutu nasłuchiwania, komponenty warunkujące jego widoczność dodajemy do nasłuchiwania pierwszej strony kroku.

#### Stylizacja

* **Nazwa stylu** – lista styli CSS przypisana do strony. Umożliwia nadanie stronie (oraz wszystkim jej elementom) indywidualnego wyglądu poprzez stylowanie w arkuszu CSS. Wartość wpisana w to pole będzie dodana jako klasa HTML do kontenera strony. Można tutaj wpisać wiele klas rozdzielonych spacją. *(Więcej informacji znajduje się w dokumentacji w sekcji* [Style formularza i style komponentu](/budowanie-aplikacji/interfejs-uzytkownika/formularze)*.)*
* **Przycisk dalej przyklejony (customPositionedNavbarCondition)** – warunek dla specyficznego zachowania przycisku nawigacyjnego „Dalej”/„Wyślij”. Jest to funkcja używana głównie w natywnych aplikacjach mobilnych – pozwala np. sprawić, że przycisk będzie zawsze widoczny na dole ekranu (przypięty), jeśli spełniony jest dany warunek. Po ustawieniu warunku na *true*, dla danej strony przycisk nawigacyjny zmieni swój sposób wyświetlania.\ <sub>*(Dostępność funkcjonalności zależy od licencji i moze nie być dostępna we wszystkich wdrożeniach)*</sub>
* **Ukryj przycisk rezygnacji ("X")** – flaga określająca, czy na stronie ma być widoczny przycisk anulowania (oznaczony iksem, zwykle w nagłówku formularza). Domyślnie w kanale mobilnym, taki przycisk jest wyświetlany, pozwalając przerwać wniosek. Zaznaczenie tej opcji spowoduje ukrycie go na danej stronie.\ <sub>*(Dostępność funkcjonalności zależy od licencji i moze nie być dostępna we wszystkich wdrożeniach)*</sub>
* **Ukryj przycisk wstecz** – flaga kontrolująca widoczność przycisku nawigacji wstecz (ze strzałką) w aplikacji mobilnej. W niektórych szablonach mobilnych obok tytułu formularza wyświetlany jest strzałka „wstecz” do poprzedniego ekranu – włączenie tej flagi usunie ten element na danej stronie.\ <sub>*(Dostępność funkcjonalności zależy od licencji i moze nie być dostępna we wszystkich wdrożeniach)*</sub>
* **Ukryj tytuł wniosku** – flaga decydująca o pokazywaniu tytułu całego wniosku na górze ekranu. W typowych wdrożeniach webowych tytuł formularza jest wyświetlany np. w nagłówku. Jeśli formularz ma własny tytuł graficzny lub po prostu chcemy zaoszczędzić miejsce, możemy ukryć domyślny tytuł zaznaczając tę opcję.\ <sub>*(Dostępność funkcjonalności zależy od licencji i moze nie być dostępna we wszystkich wdrożeniach)*</sub>

#### WCAG

* **Strona zawiera formularz** – flaga określająca, czy strona ma być traktowana przez technologię asystującą jako samodzielny formularz. Ustawienie tej opcji nada kontenerowi strony atrybut `role="form"`, co bywa wymagane dla spełnienia standardów dostępności WCAG (zwłaszcza gdy w ramach jednej aplikacji występuje wiele niezależnych formularzy). Szczegóły dot. tej właściwości opisuje sekcja [*WCAG – strona jako formularz*](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/zakladka-audyt-naruszenia-wcag/wcag-strona-jako-formularz). Włączenie tej opcji zwykle nie jest konieczne dla zwykłych stron wniosku (które i tak znajdują się wewnątrz głównego formularza całej aplikacji), ale może być użyteczne w nietypowych scenariuszach.

#### Pozostałe

* **Kurtyna** – konfigurowalny komunikat wyświetlany u góry strony w formie zasłony. Pozwala on np. zablokować interakcję z pozostałą częścią formularza dopóki użytkownik nie wykona jakiejś akcji lub po prostu wyświetlić wyróżnione ogłoszenie. **Kurtyny** mogą służyć jako bannery informacyjne. Właściwość ta umożliwia wybór wcześniej zdefiniowanej **Treści (TextContent)** jako komunikatu lub wpisanie komunikatu tekstowego.\ <sub>*(Dostępność funkcjonalności zależy od licencji i moze nie być dostępna we wszystkich wdrożeniach)*</sub>
* **Dolny pasek (bottom bar)** – dodatkowy pasek na dole strony (tylko w aplikacjach mobilnych) służący do prezentowania np. rozwijanej sekcji z dodatkowymi informacjami lub akcjami. Dostępnych jest kilka właściwości konfigurujących ten pasek:

  * *Czy rozwijać tekst? (expandable)* – zaznaczenie, czy dolny pasek ma zawierać **rozwijalną treść** (czyli początkowo zwinięty komunikat z opcją „rozwiń”). Domyślnie opcja jest włączona (pasek jest rozwijalny). Jeśli ją odznaczymy, pasek będzie stały (niezwijalny).
  * *Alternatywny wygląd (mode)* – włącza alternatywny sposób prezentacji paska. W zależności od wdrożenia może to oznaczać inną kolorystykę lub styl paska.
  * *Tekst przycisku rozwijania (showToggleTextKey)* – klucz tłumaczeń dla tekstu linku/przycisku, który rozwija pasek. Domyślnie może to być np. „Czytaj więcej”. Wpisując tutaj np. `bottom.expand`, należy dodać odpowiedni wpis w tłumaczeniach (np. *bottom.expand = "Pokaż więcej informacji"*). Analogicznie działa *Tekst przycisku zwijania (hideToggleTextKey)* – klucz dla tekstu opcji zwinięcia paska (np. „Ukryj szczegóły”).
  * *Warunek widoczności paska (visibleCondition)* – warunek logiczny określający, czy w ogóle pokazać dolny pasek na danej stronie. Jeśli np. pasek ma być widoczny tylko dla nowych klientów, można tu wpisać odpowiedni warunek.
  * *Treść rozwinięta (topTextContentName)* – nazwa artefaktu **Treść (TextContent)**, którego zawartość będzie wyświetlana po rozwinięciu dolnego paska. Pozwala to projektantowi stworzyć bogaty HTML (np. listę, tabelkę, linki) w komponencie **Treść** i osadzić go w pasku.
  * *Treść zwinięta (bottomTextContentName)* – analogicznie, nazwa artefaktu Treść z zawartością, która jest widoczna **przed rozwinięciem** paska (czyli krótki komunikat na pasku). Po kliknięciu „rozwiń” komunikat ten może zostać zastąpiony lub rozszerzony treścią *topTextContent*.

  <sub>*(Dostępność funkcjonalności zależy od licencji i moze nie być dostępna we wszystkich wdrożeniach)*</sub>
* **Warunek wymagalności zalogowania (loginRequiredCondition)** – warunek określający konieczność zalogowania użytkownika przed wyświetleniem strony. Jeśli zostanie tu zdefiniowany warunek (np. `getValue("czyKlientZalogowany") != "true"`), to w przypadku jego spełnienia system wymusi uwierzytelnienie użytkownika (logowanie) zanim strona zostanie pokazana. Ta funkcjonalność jest używana w scenariuszach, gdy część wniosku dostępna jest tylko dla zalogowanych użytkowników.

*Dodatkowo istnieją pewne właściwości strony dostępne tylko poprzez edycję XML (zakładka Źródło). Należą do nich m.in. `fixedColumns`/`inheritLayout` – związane z dziedziczeniem układu kolumn ze starej wersji silnika – czy `migratedLayoutOn` (znacznik migracji układu). W większości przypadków nie ma potrzeby ich ręcznej modyfikacji.*

## Dobre praktyki projektowe

Projektując strukturę kroków i stron warto kierować się kilkoma dobrymi praktykami, które ułatwią utrzymanie wniosku i zapewnią poprawne działanie logiki:

* **Przemyślane nazewnictwo:** Nazwy artefaktów (formularzy, komponentów, zmiennych) powinny być spójne i zrozumiałe. Ustal, czy używasz języka polskiego czy angielskiego i trzymaj się konwencji. **Id** i **mid** dla stron najlepiej nadawać tak, by odzwierciedlały ich zawartość lub rolę. Unikaj pozostawiania domyślnych nazw typu *Page1* – lepiej zastąpić je np. *DaneAdresowe* czy *Podsumowanie*. Dzięki temu łatwiej odnajdziesz się w strukturze, a identyfikatory biznesowe pojawiające się np. w warunkach będą bardziej czytelne.
* **Unikalne identyfikatory:** Każdy krok, strona i komponent powinien mieć unikalny **mid** (identyfikator biznesowy). System co prawda wymusza unikalność wewnątrz jednego formularza, ale jeśli duplikujesz artefakty lub kopiujesz fragmenty formularzy, łatwo przeoczyć powielone identyfikatory. Duplikaty **mid** mogą prowadzić do niepoprawnego działania warunków czy nasłuchiwania. Przy powielaniu elementów zawsze sprawdzaj i zmieniaj **mid** na unikalny. Podobnie klucze tłumaczeń – nie używaj jednego klucza do dwóch różnych tekstów.
* **Czytelność i modularność warunków:** Tworząc złożone wyrażenia warunkowe, dbaj o ich czytelność. Wykorzystuj nawiasy i konwencje nazewnicze, by jasno oddać intencję (np. `getValue("dochódNetto") > 0 && getValue("etat") == "true"` zamiast nieczytelnego ciągu). Unikaj powtarzania tej samej logiki w wielu warunkach – jeśli kilka pól lub stron korzysta z tego samego wyrażenia, rozważ wyciągnięcie go do jednej zmiennej sesyjnej lub do pola technicznego. Przykładowo możesz dodać **pole techniczne** o **mid** `czyKlientVIP` z domyślnym wyrażeniem oceniającym dane klienta, i potem w warunkach różnych kroków odwoływać się tylko do `getValue("czyKlientVIP")`. Taka **centralizacja wyrażeń** uprości zmiany w przyszłości (modyfikujesz formułę w jednym miejscu) i zmniejszy ryzyko błędów.\
  W Eximee można oznaczyć **pole tekstowe** jako **pole techniczne,** zaznaczajac odpowiednią opcje w **Właściwościach** pole tekstowego - w sekcji **Bezpieczeństwo**. Pole takie jest niewidoczne dla użytkownika, ale dostępne dla logiki – przydatne dla przechowywania wartości pomocniczych.
* **Testowanie logiki widoczności:** Po skonfigurowaniu warunków i nasłuchiwania zawsze **przetestuj różne scenariusze** wypełniania wniosku. Upewnij się, że kroki i strony pojawiają się i znikają zgodnie z założeniami w odpowiedzi na dane użytkownika. Testuj kombinacje odpowiedzi – zwłaszcza krawędziowe przypadki – aby uniknąć sytuacji, gdzie np. pewna ścieżka nawigacji omyłkowo omija ważną stronę. Pamiętaj o przypadku, gdy warunek odwołuje się do pola z wartością domyślną: jeśli pole kontrolujące jest niewidoczne, ale ma ustawioną domyślną wartość spełniającą warunek, to zależna strona/komponent **i tak się wyświetli**.\
  \&#xNAN;*Przykład*: pole radio ma domyślnie zaznaczoną pierwszą opcję „TAK” i warunkowo pokazujemy inne pole właśnie gdy jest „TAK” – nawet gdy radio jest ukryte, domyślna wartość *"TAK"* wciąż powoduje ujawnienie zależnego pola. Takie sytuacje należy świadomie obsłużyć, np. ustawić brak domyślnej odpowiedzi dla radio.
* **Porządek i spójność:** Utrzymuj porządek w strukturze – nie twórz zbędnych, pustych kroków, nie umieszczaj pojedynczych pól na osobnych stronach jeśli nie jest to konieczne (lepiej pogrupować tematycznie pola w ramach jednej strony, aby użytkownik nie musiał klikać „Dalej” dla każdej drobnej informacji). Staraj się też, by każdy krok odpowiadał logicznie jednemu tematowi procesu – ułatwi to zarówno użytkownikowi zrozumienie progresu, jak i Tobie ewentualną rozbudowę wniosku.
* **Nazewnictwo tłumaczeń:** Jeśli formularz jest dwujęzyczny, zadbaj o jednolite nazewnictwo kluczy tłumaczeń dla kroków i stron. Zwyczajowo używa się wzorca `StepX.title` i `PageX.title` . W zakładce **Tłumaczenia** łatwo przejrzysz wszystkie klucze – unikaj duplikatów lub niepotrzebnie podobnych wpisów.
* **Reużywanie komponentów:** Jeżeli pewien zestaw pól pojawia się w wielu miejscach, rozważ stworzenie [**komponentu złożonego**](/budowanie-aplikacji/interfejs-uzytkownika/komponenty-rozszerzone/komponenty-zlozone) zamiast duplikowania tych pól ręcznie w każdym miejscu. Ułatwi to wprowadzanie zmian i zachowanie spójności.
* **Parkowanie wniosku:** Jeśli Twój proces biznesowy dopuszcza parkowanie (zapisywanie robocze) przed wysłaniem, upewnij się, że w formularzu jest to poprawnie obsłużone. Standardowo Eximee pozwala użytkownikowi zaparkować wniosek przy pomocy przycisku „Zapisz i wróć później” (jeśli wdrożenie go przewiduje). Nie dotyczy to jednak kroków po punkcie zapisu – tam parkowanie wniosku jest niemożliwe, więc nie musisz nic dodatkowego robić.

## Debugowanie kroków i stron – lista kontrolna

Pomimo starań, w skomplikowanych wnioskach mogą pojawić się problemy z logiką nawigacji lub widoczności. Oto lista kontrolna, która pomoże znaleźć najczęstsze błędy:

1. **Krok/strona nie pojawia się w ogóle:**
   * Sprawdź warunek widoczności kroku oraz wszystkich nadrzędnych elementów. Być może warunek jest zawsze fałszywy (np. literówka w nazwie pola w wyrażeniu powoduje, że zawsze zwraca **false**).
   * Upewnij się, że identyfikatory użyte w Warunku widoczności istnieją i są poprawne.
   * Sprawdź, czy dany krok nie został umieszczony jako element innego kroku. Eximee nie obsługuje zagnieżdżonych kroków — każdy krok musi znajdować się na najwyższym poziomie struktury.
2. **Warunek widoczności nie działa dynamicznie:**

   Jeśli warunek bazuje na polu zmienianym przez użytkownika, a strona/krok nie pojawia się lub nie znika podczas interakcji, prawie na pewno brakuje **Nasłuchiwania**. Sprawdź, czy komponent zależny ma dodany **Nasłuchiwanie** na to pole. W przypadku braku, dodaj brakujące powiązania i przetestuj ponownie.
3. **Element wyświetla się, chociaż nie powinien:**\
   Typowa przyczyna to warunek odwołujący się do pola z wartością domyślną, o czym wspomniano wyżej. Jeżeli zależność jest bardziej złożona, sprawdź też, czy nie pomyliłeś operatorów (np. użycie `==` zamiast `!=`) lub typów danych (porównujesz tekst z liczbą?).\
   W debugowaniu warunków pomocne może być tymczasowe dodanie na formularzu pola tekstowego i ustawienie jego tekstu jako wynik problematycznego wyrażenia – zobaczysz wtedy „na żywo”, co jest zwracane przez dane wyrażenie.
4. **Problemy z nawigacją między krokami:**\
   Jeśli przycisk „Dalej” nie reaguje lub użytkownik utknął, upewnij się, że w danym kroku jest co najmniej jedna **widoczna** strona. Może się zdarzyć, że wszystkie strony w kroku zostały ukryte warunkami – wtedy po ukończeniu poprzedniego kroku system może nie mieć dokąd przejść. Rozwiązanie: albo zapewnić, że choć jedna strona zawsze się pojawi, albo warunkowo pominąć cały krok (warunek na kroku zamiast na każdej stronie osobno).
5. **Nie można edytować formularza (ikona edycji wyszarzona):** Prawdopodobnie formularz został zablokowany przez mechanizm szkicu (draft) – np. inny użytkownik go edytował i nie zapisał.\
   Można wycofać blokadę zgodnie z opisem w sekcji *Draft – szkic/kopia robocza*. W Eximee Designer w widoku listy formularzy przy zablokowanym artefakcie pojawia się odpowiednia informacja i opcja przejęcia szkicu.
6. **Sprawdzenie powiązań procesów:** Gdy używasz EximeeRouter2, zweryfikuj w konfiguracji Punktu zapisu nazwę procesu i mapping business key. Błędna nazwa procesu może spowodować, że po wysłaniu nic się nie wydarzy (wniosek zapisze się, ale proces nie wystartuje). W logach systemowych szukaj komunikatów dotyczących uruchomienia procesu.
7. **Logi i tryb developerski:** W razie trudnych do zdiagnozowania problemów skorzystaj z logów przeglądarki (konsola JS) oraz logów serwera Eximee. Zweryfikuj w zakładce **Źródło** czy właściwości kroków i stron są tam zgodne z oczekiwaniami (to pozwoli wyłapać np. niechcący nadpisane identyfikatory albo brakujące wpisy).
8. **Korzystaj z FAQ:** W razie wątpliwości zajrzyj do dokumentu **FAQ Eximee Designer** – wiele typowych problemów zostało tam opisanych wraz z rozwiązaniami. Np. wyjaśniono tam dlaczego komponent zależny może się pokazać mimo ukrycia kontrolki (wartość domyślna), czy co zrobić, gdy zmiany w komponencie złożonym nie są widoczne we wniosku.

Zastosowanie powyższej listy kontrolnej powinno pomóc w szybkiej identyfikacji większości błędów związanych z mechanizmem kroków i stron. Jeśli problem jest nietypowy, warto przeanalizować go krok po kroku, upraszczając warunki (np. tymczasowo ustawić je na `true`/`false` w celu odseparowania wpływu innych czynników) i dodając elementy diagnostyczne (pola techniczne, pola tekstowe itp.).

## Powiązania z innymi sekcjami dokumentacji

Mechanizm „Kroki i strony” jest ściśle powiązany z innymi aspektami tworzenia wniosku w Eximee. Dla pełnego zrozumienia i poprawnej konfiguracji warto zapoznać się również z poniższymi tematami dokumentacji:

* **Procesy i EximeeRouter2** – jeżeli formularz jest częścią większego procesu biznesowego, zapoznaj się z dokumentem [**Procesy**](/budowanie-aplikacji/proces-biznesowy/proces-jako-logika-biznesowa). Opisano tam, jak definiować i uruchamiać procesy w Eximee BPMS oraz jak Eximee Designer komunikuje się z EximeeRouter2 przy wysyłaniu wniosku. Zrozumienie tej integracji pozwoli lepiej wykorzystać akcje zapisu w **Punkcie zapisu** (np. przekazywanie zmiennych procesu, obsługa wyjątków).
* **Tłumaczenia** – zakładka **Tłumaczenia** w edytorze umożliwia dodawanie tłumaczeń tekstów używanych w formularzu (w tym tytułów stron, etykiet przycisków itp.). Pamiętaj, że klucze takie jak *titleKey* czy *labelForNextOrSubmitButtonKey* wymagają dodania odpowiadających wpisów w tym miejscu, inaczej użytkownikowi nie wyświetli się interesujaca nas treść.
* **Stylizacja i UX** – mechanizm kroków wpływa na doświadczenie użytkownika, dlatego warto poznać możliwości **stylizacji** formularza. W dokumentacji dot. stylów znajdziesz informacje, jak globalnie dostosować wygląd belki kroków, przycisków nawigacyjnych, czy układu stron. Np. istnieją *style platformowe* oraz możliwość dodawania własnych arkuszy CSS do wniosku. Odpowiednie sekcje (np. *Stylizacja komponentów*) pokazują przykłady użycia właściwości stylów.
* **WCAG – dostępność** – jeśli projekt wymaga zgodności ze standardem WCAG, koniecznie przeczytaj dedykowaną dokumentację **WCAG**. Zawiera ona wytyczne odnośnie budowy dostępnych formularzy, opisy funkcji takich jak *ariaLabel/Description*, audyt dostępności w edytorze oraz wskazówki tworzenia komponentów przyjaznych dla czytników ekranowych. W kontekście kroków i stron, upewnij się np. czy każdy krok jest logicznie oznajmiany (jeśli belka kroków jest ukryta, rozważ dodanie ukrytych nagłówków na stronach informujących o etapie). Flaga *role=form* wspomniana wcześniej również odnosi się do zaleceń WCAG.

Na zakończenie, mechanizm „Kroki i strony” stanowi szkielet każdego wniosku w Eximee Designer – opanowanie jego zasad pozwoli Ci budować rozbudowane, a zarazem przejrzyste formularze. Korzystaj z dokumentacji i powyższych wskazówek podczas pracy, a Twoje wnioski będą poprawnie nawigować użytkownika od pierwszego kroku aż do strony podziękowania w sposób przyjazny i zgodny z założeniami biznesowymi.


# Punkt zapisu wniosku i mechanizm ostatnich stron

## **Punkt zapisu wniosku**

**Punkt zapisu wniosku** to kluczowy element przepływu formularza w systemie Eximee. Definiuje moment przekazania danych wniosku do repozytorium formularzy i wywołania powiązanych akcji – takich jak uruchomienie procesu BPMN, zapis danych w systemie zewnętrznym lub wyświetlenie użytkownikowi końcowych stron informacyjnych.\
Jest on konfigurowany w zakładce **Kroki** edytora wniosku i występuje jako jedna z pozycji w sekwencji kroków formularza. Najczęściej umieszczany jest jako **ostatni krok wniosku**. Wszystkie strony znajdujące się w krokach **poniżej** Punktu zapisu wniosku traktowane są jako **strony zakończenia**.

![Ilustracja 1. Widok punktu zapisu wniosku w zakładce "Kroki"](/files/803ad50e42a692daca43e0ee482426fdb40b5a71)

W momencie przechodzenia wniosku, przekroczenie tego punktu powoduje zapis wniosku do repozytorium formularzy wraz ze wszystkimi wypełnionymi na nim danymi.

### Właściwości kroku Punkt zapisu wniosku

Krok **Punkt zapisu wniosku** posiada następujące właściwości:

* może być w dowolny sposób **przesuwany** za pomocą mechanizmu *drag & drop* w strukturze kroków,
* **nie można go usunąć**, ponieważ stanowi integralny element szablonu,
* **nie można w nim umieszczać stron** – pełni funkcję techniczną, a nie wizualną.

### Konfiguracja punktu zapisu wniosku

W momencie przekroczenia punktu zapisu system wykonuje akcję zapisu danych.\
Jeśli w tym momencie ma zostać uruchomiony proces BPMN, należy w sekcji **Punkt zapisu wniosku** dodać element **EximeeRouter2**.

Konfiguracja tego elementu obejmuje:

* **Nazwę procesu** – klucz definicji procesu BPMN (zgodny z identyfikatorem procesu w EximeeBPMS).
* **Numer sprawy (Business key)** – identyfikator biznesowy wniosku. Może wskazywać komponent formularza lub zmienną sesyjną zawierającą unikalny numer sprawy.\
  Jeśli pole nie zostanie wypełnione, system automatycznie przyjmie numer wniosku jako klucz biznesowy.

![Ilustracja 2. Widok punktu zapisu wniosku z podpiętym procesem EximeeRouter2](/files/54632cb0779e0640d2d86788a58d9f39b2c3bfe5)

Przykładowa konfiguracja XML w zakładce **Źródło** formularza:

```
<saveActions>
  <action xsi:type="eximeeWorkflow">
    <processDefinitionKey>nazwa_procesu</processDefinitionKey>
    <businessKeyMapping>numer_sprawy</businessKeyMapping>
  </action>
</saveActions>
```

Ustawienie tych parametrów powoduje, że po przejściu punktu zapisu wniosku system:

1. Zapisuje dane z formularza w repozytorium (FormStore),
2. Inicjuje proces BPMN w silniku **EximeeBPMS**,
3. Przekazuje dane z formularza do procesu zgodnie z mapowaniem w zakładce **Model danych**.

## Mechanizm ostatnich stron

Po przejściu punktu zapisu wniosku system wyświetla tzw. **ostatnie strony wniosku** – końcowe ekrany widoczne po wysłaniu formularza. W przypadku braku stron zakończenia system automatycznie prezentuje standardową stronę podziękowania zdefiniowaną na poziomie aplikacji Forms.

Strony zakończenia mogą służyć do:

* prezentacji komunikatu potwierdzającego wysłanie wniosku (np. podziękowania, numeru referencyjnego),
* przekazania informacji o dalszym przebiegu procesu,
* wywołania dodatkowych usług lub walidatorów.

Charakterystyka ostatnich stron:

* dane ze stron zakończenia **nie są zapisywane** **w repozytorium** wraz z danymi zebranymi z pełnoprawnych stron wniosku,
* komponenty na stronach zakończenia **działają jak zwykłe komponenty**, mogą wykonywać walidacje, usługi lub wyświetlać dane słownikowe,
* po wysłaniu wniosku i przejściu na strony zakończenia użytkownik **nie może wrócić do poprzednich stron**,
* **nie ma możliwości zaparkowania** wniosku po jego wysyłce,
* po przejściu przez strony zakończenia wniosek **nie trafia do puli wniosków porzuconych**,
* kroki zakończenia działają analogicznie jak zwykłe kroki i możemy im definiować podstawowe własności zgodnie z [instrukcją](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/kroki-i-strony-formularza).

### Definiowanie ostatnich stron wniosku

Proces tworzenia ostatnich stron jest analogiczny do definiowania zwykłych stron formularza.\
Jedyną różnicą jest ich **położenie** – należy je umieścić w kroku **poniżej Punktu zapisu wniosku**.

Ilustracja poniżej przedstawia kroki przykładowego szablonu wniosku. Szablon ten posiada:

* trzy strony wniosku umieszczone w krokach **Step1** i **Step2**
* **Punkt zapisu wniosku** określający miejsce strony podziękowania,
* jedną stronę zakończenia znajdującą się w kroku **Step3**.

![Ilustracja 3. Przykładowe kroki ze stroną podziękowania](/files/8730f1d11a7ef9c0c730eb8802ada304fb56af25)

Wszystkie strony umieszczone w krokach znajdujących się poniżej **Punktu zapisu wniosku** traktowane są jako strony zakończenia.


# Edycja stron

## Wprowadzenie

W ramach projektowania formularza w **Eximee Designer** użytkownik ma możliwość edycji poszczególnych **stron wniosku**, które tworzą jego strukturę logiczną i wizualną.\
Każda strona może zawierać [komponenty bazowe](/budowanie-aplikacji/interfejs-uzytkownika/formularze/praca-z-komponentami-bazowymi/dodawanie-i-parametryzowanie-komponentow) lub złożone, a jej zachowanie i wygląd można modyfikować w panelu właściwości strony.

## Struktura formularza a strony

Formularz w Eximee składa się z **kroków (steps)** i **stron (pages)**. Zarządzanie stronami odbywa się w **zakładce Kroki**, natomiast ich treść i układ modyfikujemy w **zakładce Wniosek**.

## Warunki widoczności

Warunki widoczności umożliwiają kontrolę nad tym, czy dana strona zostanie wyświetlona użytkownikowi.\
Definiowane są zakładce **Wniosek** na wybranej stronie, w sekcji **Jakość danych** (pole **Dodaj warunek widoczności**) za pomocą wyrażeń logicznych tworzonych w **zaawansowanym edytorze warunków**, który pozwala odwoływać się do wartości pól formularza lub zmiennych sesyjnych.

Warunki widoczności można również definiować w zakładce **Kroki** – poprzez opcję **Dodaj warunek**, co pozwala określić logikę prezentacji poszczególnych kroków formularza.

Więcej informacji: Zaawansowany edytor warunków.

## Edycja układu strony

Każda strona ma zdefiniowany układ kolumn, ustalany w momencie tworzenia formularza.\
Zmiana liczby kolumn (**numColumns**) możliwa jest wyłącznie poprzez edycję kodu XML w zakładce **Źródło**.

{% code title="Przykład fragmentu strony z ustawioną liczbą kolumn 12" %}

```xml
<system:Page id="Page3" mid="Page3" titleKey="Page3.title">
  <system:Page.layout>
    <ns6:GridLayout makeColumnsEqualWidth="true" numColumns="12"/>
  </system:Page.layout>
</system:Page>
```

{% endcode %}

{% hint style="info" %}
**Uwaga:**\
Przed zmniejszeniem liczby kolumn należy dostosować szerokość komponentów (`horizontalSpan`) - ich suma w wierszu nie może przekraczać liczby kolumn strony.
{% endhint %}

## Stylizacja strony

Każda strona może mieć przypisane własne style CSS.\
Styl definiuje wizualną prezentację strony (np. układ, marginesy, kolor tła). Zdefiniowany styl może być ustawiony w panelu **Właściwości** (sekcja **Stylizacja**) lub bezpośrednio w źródle XML poprzez atrybut `styleName`.

Właściwości `fixedColumns` i `styleName` pozwalają określić wygląd strony - odpowiednio strukturę układu i przypisany styl CSS.

Zaleca się stosowanie stylów platformowych zgodnych z wdrożoną szatą graficzną.\
Więcej informacji: *Style formularza i komponentu*.

## Właściwości strony

Po kliknięciu w puste miejsce edytora wniosku otwiera się panel **Właściwości** strony.

<div align="center"><figure><img src="/files/O7yWM9ryqA4sEwnmw00N" alt="" width="152"><figcaption><p><em><strong>Ilustracja 1.</strong> Fragment panelu "Właściwości" strony</em></p></figcaption></figure></div>

> Więcej informacji na temat właściwości strony [tutaj](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/kroki-i-strony-formularza#wlasciwosci-stron)

## Dobre praktyki

* Ustal spójną konwencję nazw stron (np. *Page1*, *Page2*, *Summary*).
* Stosuj warunki widoczności tylko tam, gdzie to konieczne.
* Ustal jednolitą liczbę kolumn w obrębie wszystkich stron formularza.
* Projektuj układ komponentów tak, aby ich suma `horizontalSpan` w wierszu nie przekraczała liczby kolumn strony. Przy zmianie liczby kolumn pamiętaj, aby dopasować szerokość komponentów.
* Strony znajdujące się po [punkcie zapisu](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/punkt-zapisu-wniosku-i-mechanizm-ostatnich-stron) traktowane są jako **strony zakończenia** (np. podziękowanie, potwierdzenie)

## FAQ

**Czy można zmienić kolejność stron w formularzu?**\
Tak. W zakładce **Kroki** można przeciągać strony metodą *drag & drop*. Zmiany zapisywane są automatycznie.

**Jak ukryć stronę przed użytkownikiem?**\
W panelu właściwości strony należy ustawić **warunek widoczności** (`visibleCondition`). Strona zostanie pokazana tylko, jeśli warunek zwróci wartość `true`.

**Czy liczba kolumn strony może być inna niż w całym formularzu?**\
Tak, ale tylko po edycji źródła XML w zakładce **Źródło** - zmieniając atrybut `numColumns` w elemencie `<system:Page.layout>`.

**Jak ustawić stronę jako stronę podziękowania?**\
Wystarczy umieścić ją za [**Punktem zapisu wniosku**](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/punkt-zapisu-wniosku-i-mechanizm-ostatnich-stron) - system automatycznie potraktuje ją jako stronę zakończenia.


# Przyciski nawigacyjne

## Działanie przycisków nawigacyjnych

Formularze w Eximee są wyposażone w domyślny zestaw przycisków nawigacyjnych, które umożliwiają użytkownikowi przemieszczanie się między kolejnymi stronami wniosku oraz jego finalne wysłanie. W zależności od położenia w strukturze formularza system automatycznie wyświetla przyciski **Wróć**, **Dalej** lub **Wyślij wniosek**.

Przyciski **Wróć** i **Dalej** służą do nawigowania między stronami wniosku w ramach tego samego kroku lub między krokami, jeśli formularz został podzielony na kilka etapów. Przycisk **Wyślij wniosek** jest widoczny wyłącznie na stronie poprzedzającej [**Punkt zapisu wniosku**](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/punkt-zapisu-wniosku-i-mechanizm-ostatnich-stron) i jego użycie powoduje zapis danych w repozytorium formularzy oraz zakończenie procesu wypełniania.

Domyślne przyciski są generowane przez aplikację **Forms** i działają automatycznie, bez potrzeby definiowania dodatkowych akcji. Ich zachowanie odpowiada standardowemu przepływowi wniosku i jest zgodne z konfiguracją określoną w strukturze kroków formularza.

## Zmiana etykiety przycisków „Dalej”, „Wyślij wniosek”, "Wróć"

Eximee Designer pozwala na modyfikację treści przycisków w celu dostosowania ich do kontekstu biznesowego, językowego lub etapu procesu. Zmiana może zostać dokonana na poziomie całego formularza albo wyłącznie dla wybranej strony.

Dla pojedynczej strony właściwość przycisku jest definiowana w edytorze formularza w **Podstawowe właściwości** interesujacej nas strony w polach:

* **Etykieta przycisku dalej/wyślij** (labelForNextOrSubmitButtonKey). Umożliwia to zastąpienie domyślnej etykiety „Dalej” lub „Wyślij wniosek” własnym tekstem, np. „Przejdź do podsumowania” czy „Zakończ rejestrację”.
* **Etykieta przycisku wstecz** (labelForBackButtonKey). Umożliwia to zastąpienie domyślnej etykiety „Wróć” własnym tekstem, np. „Powrót” czy „Wróć na poprzednią stronę”. Wprowadzone tłumaczenia odnosi się tylko do danej strony, bez wpływu na pozostałe elementy wniosku.

<div align="center"><figure><img src="/files/SaY0XwJPbTBbXa449dBy" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Miejsce zmiany treści przycisku Dalej i Wróć</em></p></figcaption></figure></div>

To rozwiązanie pozwala projektantowi dopasować język komunikacji z użytkownikiem do kontekstu działania, szczególnie w złożonych formularzach, w których poszczególne kroki pełnią różne funkcje.

{% hint style="info" %}
Wniosek demo: demoCustomButtons
{% endhint %}

## Zmiana treści przycisków w systemie tłumaczeń

Jeśli konieczna jest globalna zmiana etykiet przycisków w całym formularzu, można ją wprowadzić w zakładce **Tłumaczenia**. Nadpisanie wartości przypisanych do tych kluczy pozwala na zmianę treści przycisków bez potrzeby edycji każdej strony osobno.

Aby zmodyfikować etykiety przycisków funkcyjnych na szablonie wniosku, wejdź w zakładkę **Tłumaczenia** i dodaj lub edytuj odpowiednie klucze wraz z treściami:

| Nazwa klucza           | Wartość domyślna                 | Opis                                                      |
| ---------------------- | -------------------------------- | --------------------------------------------------------- |
| iew\.navigation.submit | "Wyślij"/"Wyślij wniosek/Zapisz" | Tekst na przycisku na ostatniej stronie wniosku           |
| iew\.navigation.next   | "Dalej"                          | Tekst na przycisku przejścia na kolejną stronę wniosku    |
| iew\.navigation.prev   | "Wstecz"/"Powrót"/"Cofnij"       | Tekst na przycisku przejścia na poprzednią stronę wniosku |

Dla przycisków **Dalej**, **Wróć** i **Wyślij wniosek** stosowane są klucze tłumaczeń systemowych powiązane z ich funkcją. Każdy z nich może mieć zdefiniowaną wartość w różnych językach, dzięki czemu możliwe jest pełne dostosowanie interfejsu do wymagań projektu i lokalizacji.

System tłumaczeń w Eximee wykorzystuje hierarchię nadpisywania treści. Priorytet mają tłumaczenia wprowadzone dla konkretnej strony, następnie zmienne sesyjne i tłumaczenia przypisane do formularza, a na końcu klucze domyślne dostarczane z platformą. Taki mechanizm gwarantuje spójność interfejsu i umożliwia elastyczne zarządzanie treścią przy zachowaniu kontroli nad językiem w całej aplikacji.

{% hint style="info" %}
Wniosek demo: demoPrzyciskiWniosku
{% endhint %}

## Podsumowanie

Mechanizm przycisków nawigacyjnych w Eximee jest integralną częścią logiki przepływu formularza i nie wymaga dodatkowej konfiguracji. Jednocześnie umożliwia pełną personalizację treści, zarówno dla pojedynczych stron, jak i dla całego formularza. Projektant może w prosty sposób tworzyć spójne, wielojęzyczne formularze, które zachowują czytelność i zgodność z procesami biznesowymi.


# Siatka layoutu / szata

## Siatka layoutu

**Siatka layoutu** to graficzne przedstawienie **kolumn i wierszy**, w których umieszczane są komponenty formularza. Pozwala projektować i organizować układ formularza – definiuje sposób rozmieszczenia komponentów na stronie oraz kontroluje proporcje między nimi.\
Dzięki siatce twórca formularza może precyzyjnie ustawić szerokość i położenie elementów, zachowując spójność wizualną i czytelność interfejsu.

Siatka layoutu jest widoczna zarówno w trybie edycji formularza, jak i w trybie tylko do odczytu.

### Widok siatki w edytorze wniosku

Włączenie siatki layoutu możliwe jest w zakładce **Wniosek** – po kliknięciu przycisku **„Siatka layoutu”** znajdującego się u dołu panelu bocznego.

<div align="center"><img src="/files/0dd3fe336c91bbc3df53b45b1fee450508283fd3" alt="Ilustracja 1. Przycisk &#x22;Siatka layoutu&#x22;"></div>

Po włączeniu widoku siatki formularz zostaje rozszerzony o dodatkowe elementy pomocnicze:

* siatkę kolumn (pomocną przy projektowaniu i modyfikacji layoutu wniosku) oraz granice obszarów komponentów,
* identyfikatory stron, komponentów bazowych i komponentów złożonych,
* widoczność pól technicznych.

<figure><img src="/files/HRec5PQLllMZHXp0uXhy" alt=""><figcaption><p><em><strong>Ilustracja 2.</strong> Pole techniczne widoczne po włączeniu opcji "Siatka layoutu"</em></p></figcaption></figure>

Widok siatki nie wpływa na publikowany wygląd formularza – to jedynie **narzędzie pomocnicze** ułatwiające rozmieszczanie komponentów i analizę układu.

<figure><img src="/files/59UQqbpvxE5Q2H7hr8Cl" alt=""><figcaption><p><em><strong>Ilustracja 3.</strong> Widok zakładki "Wniosek" bez włączonej siatki layoutu</em></p></figcaption></figure>

<figure><img src="/files/BeVVnCFJaJKkqHN2fl1Q" alt=""><figcaption><p><em><strong>Ilustracja 4.</strong> Widok zakładki "Wniosek" z siatką layoutu</em></p></figcaption></figure>

## Zmiana szaty

**Zmiana szaty** to opcja w Eximee Designer, która umożliwia przełączanie się między szatami wniosku, czyli wizualnymi warstwami formularza.

Przełączenie między szatami następuje po kliknięciu przycisku **Zmiana szaty** znajdującego się u dołu panelu bocznego edytora formularza.

<div align="center"><img src="/files/d0527808643e67073ff32d62628296e061f8703e" alt="Ilustracja 5. Przycisk &#x22;Zmiana szaty&#x22;"></div>

Po kliknięciu przycisku otwiera się lista dostępnych szat zdefiniowanych dla instancji platformy.\
Wybranie innej szaty natychmiast zmienia wygląd formularza w podglądzie – nie wpływa jednak na jego logikę ani strukturę komponentów.

### FAQ

**Czy siatka layoutu zmienia wygląd formularza dla użytkownika końcowego?**\
Nie. Siatka jest widoczna tylko w trybie edycji i nie wpływa na opublikowany wygląd formularza.

**Czy można zmienić szatę dla jednej strony formularza?**\
Nie. Szata jest przypisywana do całego formularza lub aplikacji, a nie do poszczególnych stron.

**Czy zmiana szaty wpływa na układ kolumn?**\
Nie bezpośrednio, ale różne szaty mogą mieć inne wartości marginesów i odstępów, co może wymagać drobnych poprawek rozmieszczenia komponentów.


# Podgląd definicji formularza (XML)

Zakładka **Źródło** umożliwia podgląd i edycję technicznej definicji formularza (także [komponentu złożonego](/budowanie-aplikacji/interfejs-uzytkownika/komponenty-rozszerzone/komponenty-zlozone) i biznesowego) w formacie **XML**.\
Umożliwia ona bezpośredni dostęp do struktury szablonu, dzięki czemu można sprawdzić lub zmodyfikować elementy, które nie są dostępne w standardowym widoku edytora.

## **Funkcje**

1. **Podgląd definicji XML**
   * Wyświetla pełną strukturę formularza, w tym:
     * kroki i strony wniosku (`<system:Page>`),
     * komponenty bazowe i złożone,
     * definicje warunków widoczności i nasłuchiwania (`<data:ListeningOn>`, `<data:ClearOn>`),
     * układ siatki (`<system:Page.layout>`),
     * tłumaczenia (`titleKey`, `labelKey`).
2. **Edycja ręczna**
   * W zakładce **Źródło** można edytować kod XML wniosku - np. poprawiać parametry layoutu, zmieniać liczby kolumn lub wprowadzać atrybuty niewystępujące w interfejsie graficznym.
   * Jest to szczególnie przydatne przy pracy z bardziej zaawansowanymi właściwościami, takimi jak:
     * `numColumns` – liczba kolumn na stronie,
     * `horizontalSpan` – szerokość komponentu w kolumnach.
3. **Weryfikacja poprawności**
   * System automatycznie waliduje składnię XML, a błędy (np. brak zamykających tagów, błędne atrybuty) są sygnalizowane w edytorze.
   * W przypadku błędu zapisu formularz nie zostanie zapisany w repozytorium.

**Przykład fragmentu kodu w zakładce Źródło**

```xml
<system:Page id="Page3" mid="Page3" page="3" titleKey="Page3.title" fixedColumns="true">
    <p1:GesText id="GesText3" mid="GesText3" labelKey="GesText3.label" textKey="GesText3.text">
        <data:ListeningOn/>
        <data:ClearOn/>
        <p1:GesText.layoutData>
            <ns6:GridData horizontalAlignment="FILL" horizontalSpan="10" verticalAlignment="CENTER"/>
        </p1:GesText.layoutData>
    </p1:GesText>
    <system:Page.layout>
        <ns6:GridLayout makeColumnsEqualWidth="true" numColumns="12"/>
    </system:Page.layout>
    <data:Curtains/>
</system:Page>
```

Powyższy kod pokazuje definicję strony formularza o identyfikatorze 'Page3' z jednym komponentem etykieta 'GesText&#x33;*'* oraz układem strony w 12 kolumnach.

## **Dobre praktyki**

* Edycję w zakładce **Źródło** należy wykonywać ostrożnie - najlepiej po zapisaniu aktualnej wersji formularza.
* Przed wprowadzeniem zmian warto sprawdzić ich wpływ na formularz w zakładce **Wniosek**.

## **Zastosowania**

* **Zmiana liczby kolumn** (`numColumns`), gdy nie jest dostępna w interfejsie graficznym.
* **Przenoszenie definicji stron lub komponentów** pomiędzy formularzami.
* **Szukanie zależności danego komponentu** przed usunięciem go.

## **FAQ**

**Czy zmiany wprowadzone w Źródle są natychmiast widoczne?**\
Tak, zmiany są widoczne po zapisaniu lub przełączeniu się na inną zakładkę edytora.

**Czy można edytować tylko fragment XML?**\
Tak, można edytować dowolny element - zarówno komponent, jak i cały blok strony - pod warunkiem zachowania poprawnej składni.

**Czy zakładka Źródło pokazuje także tłumaczenia i style?**\
Tak, widoczne są klucze tłumaczeń (`*.labelKey`, `*.titleKey`) oraz klasy CSS powiązane z komponentami lub stronami.

<figure><img src="/files/FXIQ0YqfrMwB1cGFM0Fm" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Widok zakładki „Źródło” w edytorze wniosku</em></p></figcaption></figure>


# Właściwości formularza

Zakładka **Właściwości** umożliwia konfigurację parametrów dotyczących zachowania, wyglądu i interakcji formularza w czasie jego działania.\
Parametry te wpływają na to, jak formularz jest prezentowany użytkownikowi, w jaki sposób komunikuje się z usługami oraz jakie elementy interfejsu są widoczne. Właściwości są pogrupowane w sekcje tematyczne.

![Ilustracja 1. Wygląd zakładki "Właściwości"](/files/b5c9879381ed29913fe0bf13098b5da7e5a2222b)

## **Sekcja "Ogólne"**

### **Opis wniosku**

Pole tekstowe pozwalające na dodanie krótkiego opisu lub komentarza do projektu formularza. Opis ten nie jest prezentowany użytkownikowi końcowemu, ale ułatwia identyfikację w repozytorium i w pracy zespołowej.

### **Serwisy wejścia**

W sekcji tej znajduje się lista usług, które są podpięte na wniosku jako serwisy startowe. Usługi te uruchomią się na początku życia wniosku, jeśli warunek aktywności jest spełniony. Usługi wejścia wykonywane są sekwencyjnie, zgodnie z kolejnością na liście. W trybie edycji istnieje możliwość dodania i usunięcia serwisu wejścia oraz zdefiniowania warunku uruchomienia usługi.

<figure><img src="/files/plhOJ0E9ZPtDQlj5h6t1" alt=""><figcaption><p><em><strong>Ilustracja 2.</strong> Sekcja "Serwisy wejścia" z dodanymi usługami</em></p></figcaption></figure>

### **Serwisy mapujące parametry wejścia**

{% hint style="info" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

Sekcja **Serwisy mapujące parametry wejścia** umożliwia podłączenie usług, których zadaniem jest **zasilenie pól formularza** danymi jeszcze przed jego uruchomieniem.\
Serwisy te uruchamiane są automatycznie **przy wejściu na wniosek** - zarówno podczas standardowego otwarcia formularza, jak i w przypadku jego **odparkowania** (wznowienia sesji).

Dzięki tym usługom można np. przekazać dane klienta z systemu zewnętrznego, ustawić wartości startowe pól lub otworzyć wniosek na określonej stronie.

#### **Cechy charakterystyczne serwisów mapujących**

* nie posiadają **parametrów wyjściowych**,
* wynik działania serwisu jest **bezpośrednio mapowany na pola formularza lub zmienne sesyjne**,
* mogą określać stronę, na której formularz ma się otworzyć,
* wykonują się **zawsze jako pierwsze** - jeszcze przed serwisami wejścia.

#### Przykład implementacji (ServiceProxy)

W celu zasilenia pola należy w usłudze zwrócić w mapie klucz, który będzie posiadał identyfikator pola na wniosku oraz wartość, która zostanie mu przypisana. Nie należy definiować **outputFields** dla pól zwracanych z metody callService(). Aby otworzyć wniosek na określonej stronie należy przekazać do wyjściowej mapy zmienną ***recentlyRequestedPageMid*** i przekazać do niej mid odpowiedniej strony.

{% code expandable="true" %}

```java
@Component
@Service(AbstractServiceProxy.class)
public class DemoMappingEntryService extends AbstractServiceProxy {

    private final static String TEXT_FIELD = "GesComplexComponent1.GesTextField1";
    private final static String PAGE_MID = "_recentlyRequestedPageMid";

    public DemoMappingEntryService() {
        this.name = "DemoMappingEntryService";
        this.description = "For test purposes ONLY!";
    }

    @Override
    public List<Map<String, String>> callService(Map<String, List<String>> map)
            throws ServiceProxyException {
        return Collections.singletonList(ImmutableMap.of(
                TEXT_FIELD, "Wartość przekazana z usługi DemoMappingEntryService",
                PAGE_MID, "Page2"));
    }
}

```

{% endcode %}

{% hint style="info" %}
Wniosek demo: demoSerwisMapujacyParametryWejscia
{% endhint %}

### **Serwisy wyjścia**

W sekcji tej znajduje się lista usług, które są podpięte na wniosku jako serwisy końcowe. Serwisy te uruchomią się przed końcem życia wniosku, jeśli warunek aktywności jest spełniony.

### **Statystyki**

W tej sekcji znajdują się opcje związane ze zbieraniem statystyk z wniosku. Dla każdego wniosku istnieje możliwość określenia, które statystyki mają być zbierane oraz z jaką częstotliwością.

#### Statystyki zewnętrzne

Dodatkowo w sekcji Statystyki można włączyć zrzucanie statystyk Google Tag Manager. O samej funkcjonalności można przeczytać w dokumentacji GTM: [Statystyki GTM](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/statystyki-gtm).

## **Sekcja "Wygląd"**

Sekcja ta odpowiada za konfigurację elementów interfejsu widocznych w trakcie wypełniania wniosku.

### **Panel boczny i dolny**

{% hint style="info" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

Pozwala włączyć lub wyłączyć widoczność dodatkowych paneli (np. menu bocznego z informacjami, powiadomieniami lub blokami treści). Panele mogą być wykorzystywane do prezentowania przydatnych linków czy elementów cross-sell.

Do paneli można podpinać artefakty typu [Treść (TextContent)](https://github.com/Consdata/eximee-docs/tree/main/budowanie-aplikacji/interfejs-uzytkownika/formularze/biblioteka-komponentow-bazowych/tresc-textcontent/README.md), wybierane z repozytorium. Edycja panela (dodania warunku widoczności, nasłuchiwań, stylów czy wybranie slotu) wymaga kliknięcia ikony ołówka, a zapisanie zmian kliknięcia symbolu zapisu. O położeniu dodanej treści decyduje opcja **Slot**. Panele pozwalają na zdefiniowanie wielu treści, które będą wyświetlane jedna pod drugą.

<figure><img src="/files/CtWL5E1HB5cM1Y5QT4Un" alt=""><figcaption><p><em><strong>Ilustracja 3</strong></em><strong>.</strong> <em>Panel boczny i dolny - przykład definiowania treści</em></p></figcaption></figure>

<figure><img src="/files/3K0fnjoZFzZy07KIJ6kl" alt=""><figcaption><p><em><strong>Ilustracja 4.</strong> Przykładowy wygląd panelu bocznego na wniosku</em></p></figcaption></figure>

Treść panelu dolnego jest określana przez ustawienie opcji Slot na odpowiednią wartość, która jest zależna od wdrożenia.

<figure><img src="/files/PpdOgJQDwePYbLZojKOJ" alt=""><figcaption><p><em><strong>Ilustracja 5</strong></em><strong>.</strong> <em>Przykładowy wygląd panelu dolnego na wniosku</em></p></figcaption></figure>

### **Widoczność kroków**

Kontroluje wyświetlanie górnego poziomego paska postępu (tzw. [kroków formularza](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/kroki-i-strony-formularza)). Jego ukrycie może być stosowane we wnioskach jednostronicowych lub uproszczonych procesach.

W sekcji można określić warunek widoczności belki kroków oraz wskazać elementy, które wzbudzają tę zmianę (tzw. nasłuchiwanie na elementy).

<figure><img src="/files/hYGyuD1740sjgmHHIvVx" alt=""><figcaption><p><em><strong>Ilustracja 6</strong></em><strong>.</strong> <em>Przykład zdefiniowanego warunku</em> <em>widoczności belki kroków</em></p></figcaption></figure>

<figure><img src="/files/UHTW5sa56hODOPAmAEvH" alt=""><figcaption><p><em><strong>Ilustracja 7</strong></em><strong>.</strong> <em>Przykład kroków na wniosku</em></p></figcaption></figure>

### **Widoczność paska/przycisku nawigacji**

**Widoczność paska nawigacji** umożliwia określenie, czy dolny pasek nawigacyjny (z przyciskami Cofnij/Dalej/Wyślij) ma być widoczny. Natomiast w sekcji **Widoczność przycisku nawigacji** określa się tylko warunek pokazywania przycisku Dalej/Wyślij. W obu sekcjach należy też pamiętać o wskazaniu elementów wzbudzających daną zmianę (tzw. nasłuchiwanie).

<figure><img src="/files/fn2MN0aFyIQMOUm3b4d3" alt=""><figcaption><p><em><strong>Ilustracja 8.</strong></em> <em>Sekcja</em> "<em>Widoczność przycisku nawigacji"</em></p></figcaption></figure>

{% hint style="warning" %}
Zmienna currentPageId nie jest obsługiwana. Dla poprawnego działania widoczności przycisku nawigacji powinna zostać użyta zmienna currentPageMid
{% endhint %}

### **Widoczność dodatkowego elementu nagłówka**

{% hint style="info" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

Umożliwia wyświetlania dodatkowego elementu na pierwszej pozycji nagłówka strony (np. ikony, przycisku propagującego akcję). Rodzaj wyświetlanego elementu może się różnić w zależności od wdrożenia i nie jest gwarantowane jego wystąpienie we wszystkich implementacjach.

### **Bottom Bar**

{% hint style="info" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

Decyduje o tym czy stopka formularza ma być prezentowana użytkownikowi. Może być ukryta warunkowo – np. na stronach z informacjami lub podsumowaniem.

### **Panic Button (FAB)**

{% hint style="info" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

Określa, czy przycisk pływający na stronie wniosku, otwierający dodatkowe okno (FAB – *Floating Action Button*) ma być widoczny na formularzu.

#### **Widoczność**

Widoczność przycisku ustala się w podsekcji **Widoczność**, gdzie określa się warunek pokazania przycisku oraz element, który ma tę zmianę wywoływać (*nasłuchiwanie*). Dzięki temu przycisk może być widoczny tylko w określonych sytuacjach, np. po zaznaczeniu pola lub w danym kroku wniosku.

#### **Maskowanie numeru telefonu**

W sekcji **Maskowanie** można zdefiniować, czy numer telefonu w okienku przycisku ma być maskowany (np. częściowo ukryty). Widoczność numeru określa się za pomocą warunku i nasłuchiwania na element wzbudzający zmianę.

#### **Dodatkowe ustawienia**

W podsekcji **Dodatkowe dane** można wskazać komponenty formularza, których wartości zostaną przekazane do konfiguracji przycisku - numer telefonu, id czy wersję konfiguracji. Opcja ta dostępna jest tylko w wybranych wdrożeniach.

<figure><img src="/files/NlnyLIfTFgKD3VMk9osZ" alt=""><figcaption><p><em><strong>Ilustracja 9</strong></em><strong>.</strong> <em>Widoczność sekcji "Panic Button" z ustawionymi warunkami i parametrami</em></p></figcaption></figure>

#### **Konfiguracja techniczna**

Rozmiar oraz położenie okna przeglądarki, a także adres witryny, do którego prowadzi definiowane są dla danej instalacji w pliku konfiguracyjnym webforms.xml. Przykładowe wartości:

```xml
<floatingActionButton>
    <windowPositionX>100</windowPositionX>
    <windowPositionY>100</windowPositionY>
    <windowSizeX>100</windowSizeX>
    <windowSizeY>100</windowSizeY>
    <actionLink>http://consdata.pl</actionLink>
</floatingActionButton>
```

**Parametry konfiguracyjne:**

* *windowPositionX* – odległość okna od lewej krawędzi (px)
* *windowPositionY* – odległość okna od góry (px)
* *windowSizeX* – szerokość okna (px)
* *windowSizeY* – wysokość okna (px)
* *actionLink* – adres witryny otwieranej w nowym oknie; może zawierać zmienne formularza dostępne podczas uruchamiania wniosku, np.:

```
<actionLink>http://consdata.pl?nazwawniosku=${formId}&numerwniosku=${formInstanceNumber}</actionLink>
```

#### **Tłumaczenia i klucze tekstowe**

Napisy na komponencie można dostosować, dodając tłumaczenia w głównym szablonie formularza:

<table><thead><tr><th width="423">Klucz tłumaczenia</th><th>Opis</th><th>Domyślna treść</th></tr></thead><tbody><tr><td><code>iew.fab.need.help</code></td><td>tytuł w popupie startowym</td><td>„Potrzebujesz pomocy?”</td></tr><tr><td><code>iew.fab.well.call.up</code></td><td>opis w popupie startowym</td><td>„Oddzwonimy do Ciebie jak najszybciej…”</td></tr><tr><td><code>iew.fab.order.call</code></td><td>treść buttona w popupie startowym</td><td>„Zamów kontakt”</td></tr><tr><td><code>iew.fab.thank.you.title</code></td><td>tytuł w popupie podziękowania</td><td>„Wkrótce do Ciebie oddzwonimy”</td></tr><tr><td><code>iew.fab.thank.you.desc</code></td><td>opis w popupie podziękowania</td><td><em>""</em></td></tr><tr><td><code>iew.fab.error.could.not.order.conversation.title</code></td><td>tytuł w popupie błędu</td><td>„Nie udało się zamówić rozmowy”</td></tr><tr><td><code>iew.fab.error.try.again.desc</code></td><td>opis w popupie błędu</td><td>„Spróbuj ponownie za chwilę”</td></tr></tbody></table>

{% hint style="info" %}
Wnioski demo: demoFab, demoFabZmienioneLitera
{% endhint %}

### **Styl postępu ładowania**

Definiuje sposób prezentacji wskaźnika ładowania podczas inicjalizacji formularza. Domyślna wartość to "preloader". Dostępne style mogą się różnić w zależności od szaty graficznej (np. pasek postępu, spinner, animacja logo).

### **Warunkowe tytuły wniosku**

Umożliwia zdefiniowanie różnych tytułów wyświetlanych w nagłówku formularza w zależności od spełnienia określonych warunków. Każdy tytuł posiada przypisany **warunek widoczności** (np. zależny od danych), dzięki czemu można dynamicznie zmieniać nagłówek w zależności od etapu wniosku czy roli użytkownika.

#### **Definicja tytułów**

Każda definicja tytułu jest prezentowana w osobnym wierszu tabeli. Dany wiersz zawiera:

* **Klucz tytułu** – identyfikator tłumaczenia lub tekst stały wyświetlany w nagłówku formularza,
* **Warunek widoczności** – wyrażenie logiczne określające, kiedy tytuł ma być użyty,
* **Elementy wzbudzające zmianę (nasłuchiwanie)** – lista komponentów lub zmiennych (oddzielonych przecinkami), których zmiana powoduje ponowną ocenę warunku,
* **Przyciski edycji i usunięcia** – umożliwiają modyfikację lub usunięcie wiersza definicji tytułu,
* **Przycisk zapisu** – widoczny w trakcie edycji wiersza; zapisuje wprowadzone zmiany,
* **Uchwyt do zmiany kolejności** – pozwala przeciągnąć tytuł i ustawić jego priorytet (kolejność sprawdzania warunków).

{% hint style="info" %}
Wiersze są przetwarzane **od góry do dołu**, więc jeśli kilka warunków jest spełnionych, wyświetli się tytuł z najwyższego wiersza.
{% endhint %}

<figure><img src="/files/1Qm0BT4Ftc9CZIYhzNeh" alt=""><figcaption><p><em><strong>Ilustracja 10.</strong> Przykład zdefiniowanych czterech warunkowych tytułów</em></p></figcaption></figure>

{% hint style="warning" %}
Jeśli zmiana tytułu wniosku zależy od przejścia między stronami, to w warunku używamy zmiennej *currentPageMid*. Pozwoli to na zmianę tytułu zarówno przy przejściu do następnej strony, jak i przy cofaniu się.
{% endhint %}

{% hint style="info" %}
Wniosek demo: demoFormTitles
{% endhint %}

{% hint style="info" %}
Wniosek demo: demoWlasciwosciSzablonuWniosku
{% endhint %}


# Zakładka Audyt, Naruszenia WCAG

{% hint style="info" %}
Więcej o WCAG w Eximee:

[♿ WCAG](/budowanie-aplikacji/interfejs-uzytkownika/wcag)
{% endhint %}


# WCAG - audyt

{% hint style="warning" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

## Audyt

Moduł **Audyt** umożliwia podgląd naruszeń zlokalizowanych na obecnie przetwarzanym wniosku. Naruszenia mogą dotyczyć zgodności wniosku z wymaganiami WCAG lub zgodności wniosku z funkcjonalnościami Eximee.

Zostały podzielone na 3 kategorie:

* **Naruszenia** - oznaczone **czerwoną** ikonką ostrzeżenia. Informują, że błąd wykryty na wniosku powoduje naruszenie reguł WCAG lub poprawnego wykorzystania funkcjonalności Eximee.
* **Sugestie** - oznaczone **niebieską** ikoną informacji. Ukazują wskazówki usprawniające utworzony wniosek, niekoniecznie będące błędem.
* **Przestarzałości** - oznaczone **niebieską** ikonką ostrzeżenia. Informują, że wykorzystywana funkcjonalność nie jest już wspierana i sugerują zastosowanie nowego, wspieranego rozwiązania Eximee.

{% hint style="warning" %}
Sama analiza wniosku bazuje na ostatniej zapisanej wersji draft, więc jeśli naniesiemy zmiany na wniosku i draft nie zdąży się zapisać, nasza analiza nie będzie zawierała dodanych modyfikacji!!
{% endhint %}

<figure><img src="/files/SkQnD0rfr2mHmraWybws" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong></em> <em>Lista naruszeń wniosku w trybie do odczytu</em></p></figcaption></figure>

## Naruszenia

### Naruszenie EXIMEE | Tooltip <a href="#title-text" id="title-text"></a>

**Poziom**: Przedawnienie

**Występowanie**: Pomoc kontekstowa (Tooltip)

**Dokumentacja komponentu:** [Pomoc kontekstowa (tooltip)](https://github.com/Consdata/eximee-docs/tree/main/budowanie-aplikacji/interfejs-uzytkownika/formularze/biblioteka-komponentow-bazowych/pomoc-kontekstowa-tooltipbutton.md)

**Powód**: Wykorzystanie atrybutu tooltipTextKey może powodować problemy z wyświetlaniem pomocy kontekstowej, jeśli jej widoczność jest określona warunkowo.

**Sposób walidacji:** Sprawdzenie czy atrybut tooltipTextKey jest uzupełniony, oraz czy klucz tłumaczeń do niego przypisany został zasilony w zakładce *Tłumaczenia* wniosku.

### Naruszenie WCAG 1.1.1 (A) | Obraz <a href="#title-text" id="title-text"></a>

**Poziom**: Naruszenie

**Występowanie**: Obraz (GesImage)

**Dokumentacja komponentu**: [Obraz - Image](https://github.com/Consdata/eximee-docs/tree/main/budowanie-aplikacji/interfejs-uzytkownika/formularze/biblioteka-komponentow-bazowych/obraz-image.md)

**Powód**: Alternatywa tekstowa - naruszenie. Wszelkie treści nietekstowe przedstawione użytkownikowi posiadają swoją tekstową alternatywę, która pełni tę samą funkcję. Każdy obraz powinien mieć uzupełniony atrybut alt, który jest odczytywany przez czytniki w momencie focusu.

**Sposób walidacji:** Sprawdzenie czy komponent ma sposób prezentacji "Informacyjna" oraz uzupełnioną wartość "Tekst do wyświetlenia, gdy url jest błędny" lub "Tekst do wyświetlenia, gdy url jest błędny (klucz)".<br>

### Naruszenie WCAG 1.3.1 (A) | Etykieta

**Poziom**: Naruszenie

**Występowanie**: Etykieta(GesText)

**Dokumentacja komponentu:** [Etykieta - Text](https://github.com/Consdata/eximee-docs/tree/main/budowanie-aplikacji/interfejs-uzytkownika/formularze/biblioteka-komponentow-bazowych/etykieta-text.md)

**Powód**: Informacje, struktura oraz relacje między treściami przekazywane poprzez prezentację mogą być odczytane przez program komputerowy lub istnieją w postaci tekstu. Każda etykieta powinna być powiązana z polem formularza lub zostać wyświetlona jako paragraf(\<p>\</p>) zamiast w postaci etykiety(\<label>\</label>)

**Sposób walidacji:** Sprawdzenie czy komponent ma zaznaczoną właściwość "Wyświetl jako paragraf" lub czy ma uzupełnione pole "Pole powiązane z etykietą".

### Naruszenie WCAG 1.4.13 (AA) | Tooltip <a href="#title-text" id="title-text"></a>

**Poziom**: Naruszenie

**Występowanie**: Pomoc kontekstowa (Tooltip)

**Dokumentacja komponentu:** [Pomoc kontekstowa (tooltip)](https://github.com/Consdata/eximee-docs/tree/main/budowanie-aplikacji/interfejs-uzytkownika/formularze/biblioteka-komponentow-bazowych/pomoc-kontekstowa-tooltipbutton.md)

**Powód**: Jeśli najechanie kursorem myszy może wywołać dodatkową zawartość, to kursor można przesunąć nad dodatkową zawartość bez jej zniknięcia. W naszym systemie taką funkcjonalność umożliwia interaktywna pomoc kontekstowa.

**Sposób walidacji:** Sprawdzenie czy komponent ma włączoną interaktywną pomoc kontekstową we właściwościach komponentu.


# WCAG - strona jako formularz

Na potrzeby dostosowania do WCAG we właściwościach strony (**Właściwości** → **WCAG**) powstał nowy parametr (**roleForm**="true" / roleForm="false"):

<figure><img src="/files/RtfvdE0LtuXfwEEIoPwe" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Parametr "Strona zawiera formularz" w Eximee Designer</em></p></figcaption></figure>

Jeśli parametr jest zaznaczony, strona wniosku ma nadaną rolę "form":

```
<div data-ex-e2e="form-presenter" class="form ex-grid ng-tns-c200-0 ng-star-inserted" id="demo" mid="demo" role="form">
            <div class="form-pages ng-tns-c200-0 ng-star-inserted">
```

Standardowo ten parametr jest włączony, ponieważ większość stron na wnioskach pełnią rolę formularza. Jeśli jednak chcielibyśmy zaprojektować stronę tak, żeby nie zawierała ona żadnego formularza, zgodnie ze standardami WCAG nie powinna ona takiej roli posiadać:

```
<div data-ex-e2e="form-presenter" class="form ex-grid ng-tns-c200-0 ng-star-inserted" id="demo" mid="demo">
            <div class="form-pages ng-tns-c200-0 ng-star-inserted">
```


# Strona podziękowania

Strona podziękowania to ostatnia strona formularza/procesu, wyświetlana po punkcie zapisu wniosku. Taka strona może zawierać: podziękowanie za wykonane działanie (np. "Dziękujemy za wypełnienie wniosku"), numer wniosku/zgłoszenia, informacje o dalszych krokach oraz linki (np. zachęta do skorzystania z innych usług).

<figure><img src="/files/IRHXvUEmKgoecnbAWrQk" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Przykładowy wygląd strony podziękowania</em></p></figcaption></figure>

### Są 2 opcje strony podziękowania:

* Platformowa strona podziękowania - czyli sytuacja, gdy wniosek nie zawiera żadnej strony po **Punkcie zapisu wniosku** ([Punkt zapisu wniosku - mechanizm ostatnich stron](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/punkt-zapisu-wniosku-i-mechanizm-ostatnich-stron#mechanizm-ostatnich-stron)).<br>

  <figure><img src="/files/Cz6noEd4K5j9w5alp2zJ" alt=""><figcaption><p><em><strong>Ilustracja 2.</strong> Przykładowa struktura wniosku (zakładka Kroki), po której klient zobaczy platformową stronę podziękowania</em><br><br></p></figcaption></figure>
* Dedykowana strona podziękowania - czyli strona/strony, które zostały dodane przez projektanta i są wyświetlane po **Punkcie zapisu wniosku** ([Punkt zapisu wniosku - mechanizm ostatnich stron](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/punkt-zapisu-wniosku-i-mechanizm-ostatnich-stron#mechanizm-ostatnich-stron)).

<figure><img src="/files/EXyf1zvOnxB53Rppa5pb" alt=""><figcaption><p><em><strong>Ilustracja 3.</strong> Przykładowa struktura wniosku (zakładka Kroki), po której klient zobaczy dedykowaną stronę podziękowania.</em></p></figcaption></figure>


# Strony błędów

Strony błędów możemy podzielić na błędy biznesowe i błędy platformowe.

### Błędy platformowe

Błędy platformowe to są błędy które pojawiają się w momencie kiedy na wniosku pojawi się błąd który jest domyślnie obsłużony w platformie np. błąd wygaśnięcia sesji.

W powyższej sytuacji wyświetlana jest strona błędu zawierająca textContent ustawiony w konfiguracji platformy **errorPagesConfiguration**

{% hint style="info" %}
Konfiguracja ustawiana jest odgórnie w platformie. Nie mamy możliwości aktualizowania jej low codowo w designerze. W przypadku potrzeby zmian należy kontaktować się z administratorami.
{% endhint %}

\
**Przykładowa konfiguracja:**

```xml
<code_default>
    <content>error_page_default-*</content>
</code_default>
<code_serverSessionExpired>
    <content>error_page_serverSessionExpired-*</content>
    <retryButtonAvailable>true</retryButtonAvailable>
    <styleName>spider-night</styleName>
</code_serverSessionExpired>
<code_formLimitExceeded>
    <content>error_page_formLimitExceeded-*</content>
</code_formLimitExceeded>
```

### Błędy biznesowe

**Błąd biznesowy** to sytuacja, w której działanie użytkownika, proces systemowy lub interakcja z zewnętrznym systemem narusza przyjęte reguły biznesowe - mimo, że z technicznego punktu widzenia operacja mogłaby zostać wykonana.

Przykłady:

* Próba wypłaty kwoty przekraczającej dostępne środki.
* Złożenie wniosku przy nieaktywnym koncie klienta.
* Wejście na wniosek jako użytkownik niezalogowany, mimo że wymagane jest zalogowanie

#### Jak wywołać?

**Błąd biznesowy** można wywołać w serwisach skryptowych oraz walidatorach skryptowych. Najlepiej użyć do tego metody **throwBusinessException** i **getErrorPageDefinitionBuilder**.

Metody, które można wywołać w obiekcie context:

```javascript
context.getErrorPageDefinitionBuilder()
.body(string)
.styleName(string);
.msg(string)
.pageTitle(string)
.pageTitleKey(string)
.sidebarSlot2TextContent(string);
.sidebarSlot2(string);
.sidebarSlot1TextContent(string);
.sidebarSlot1(string);
.retryButtonAvailable(string)
.retryButtonAvailable(boolean);
.logobarTitle(string);
.logobarTitleKey(string)
.logobarDescription(string);
.bodyTextContent(string);
.parameter(String key, String value)
.cause(Throwable cause)
.redirectUrl(string)
.redirectDelayInMillis(string)
.businessFormIdentifier(string)
```

{% hint style="danger" %}
W obiekcie context nie należy wywoływać metody `build()`
{% endhint %}

{% hint style="info" %}
Dobrą praktyką jest używanie metody `.msg` przy wywołaniu błędu biznesowego. Należy przekazywać w niej czytelny komunikat biznesowy - np. `.msg("Wniosek niedostępny")`. Zdefiniowany komunikat zostanie wypisany w logach, co ułatwia analizę i identyfikację błędów.
{% endhint %}

Przykładowy skrypt z opisami:

```javascript
function callService(context) {
    let option = context.getFirstParameter('option');
 
    if (!option) {
        return []
    }
 
    let builder = context.getErrorPageDefinitionBuilder() // Metoda przygotowuje ekran błędu, który ma być wyświetlony
 
    switch (option) {
        case "1": // Ekran błędu, który pokazuje artefakt Treści 'error_page_default'
            builder.bodyTextContent("error_page_default-*")
            builder.msg("Wniosek niedostępny") // Komunikat błędu, który zostanie wypisany w logach
            break;
        case "2": // Ekran błędu dodany za pomocą treści podanej w body
            builder.body("Domyślne body w obiekcie")
            builder.parameter("type", "info")
            builder.msg("Wniosek niedostępny")
            break;
        case "3": // Ekran błędu, który pokazuje artefakt Treści 'error_page_noAuthorization'
            builder.bodyTextContent("error_page_noAuthorization-*")
            builder.pageTitle("Tytuł strony")
            builder.logobarTitle("Logo tytuł")
            builder.retryButtonAvailable(true);
            builder.msg("Wniosek niedostępny")
            break;
        default: // Domyślny ekran błędu wyświetlony w wyniku błędu w skrypcie
            throw "Script exception"
 
    }
    context.throwBusinessException(builder); // Rzucenie ekranu błędu z przygotowanym obiektem builder
 
 
    return [{ 'output': '' }];
}

```


# Tłumaczenia

## Zakładka „Tłumaczenia”

Zakładka **Tłumaczenia**, dostępna w edytorze wniosku, umożliwia dodawanie tłumaczeń dla wniosku, komponentów złożonych oraz komponentów biznesowych. W tym miejscu można również dodawać klucze nadpisujące domyślne treści wniosku (szczegóły w rozdziale *Platformowe klucze tłumaczeń*).

Zakładka ta pozwala także na dodawanie lub modyfikację komunikatów walidatorów powiązanych z komponentami (szczegóły w rozdziałach [*Walidacje złożone*](/budowanie-aplikacji/interfejs-uzytkownika/formularze/praca-z-komponentami-bazowymi/walidacja-wartosci-komponentow/walidacje-zlozone-wlasne) i [*Walidatory skryptowe*](/budowanie-aplikacji/logika-biznesowa/scriptcode/walidatory-skryptowe-validationscript)).

<figure><img src="/files/MPiJMR58TryFesKjzoW0" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Okno edytora wniosku - zakładka "Tłumaczenia"</em></p></figcaption></figure>

***

### Edycja klucza i wartości

Po wybraniu komórki w tabeli można edytować zarówno klucz, jak i wartości tłumaczeń dla poszczególnych języków.

W przypadku wartości wielolinijkowych pole edycji automatycznie rozszerzy się, aby pokazać całą zawartość.

<figure><img src="/files/JYK3wFXPZ7BWOasUEtVj" alt=""><figcaption><p><em><strong>Ilustracja 2.</strong> Edycja tłumaczeń</em></p></figcaption></figure>

***

### Usuwanie klucza

Aby usunąć cały wiersz tłumaczenia, należy kliknąć ikonę znajdującą się po prawej stronie danego klucza.

<figure><img src="/files/OWNImOUxisDDmdTcBxoQ" alt=""><figcaption><p><em><strong>Ilustracja 3.</strong> Usuwanie klucza tłumaczeń</em></p></figcaption></figure>

Po usunięciu klucza w dolnej części ekranu pojawi się powiadomienie z możliwością cofnięcia operacji.

<figure><img src="/files/zoMayi77jr4PVqhIpoWn" alt=""><figcaption><p><em><strong>Ilustracja 4.</strong> Powiadomienie z opcją cofnięcia usunięcia klucza</em></p></figcaption></figure>

***

### Dodawanie klucza

Możliwe jest dodanie tłumaczenia dla każdego elementu wniosku wyświetlającego tekst – tytułów, opisów, etykiet, komunikatów walidacyjnych oraz treści zwracanych przez usługi zewnętrzne.

Klucze odpowiadające komunikatom błędów walidacyjnych dodawane są automatycznie po dodaniu walidatora. Wyjątek stanowią **walidatory skryptowe**, dla których klucz należy dodać ręcznie.

Aby dodać nowy klucz, używamy przycisku **Dodaj klucz** znajdującego się nad kolumnami języków\.4

<figure><img src="/files/cnQyhG2QaC4lyPDZRIgd" alt=""><figcaption><p><em><strong>Ilustracja 5.</strong> Przycisk służący do dodania nowego klucza tłumaczeń</em></p></figcaption></figure>

Kliknięcie dodaje pusty wiersz, w którym należy uzupełnić co najmniej nazwę klucza (kolumna *KLUCZ*).\
Jeśli pole pozostanie puste, system automatycznie nada nazwę:

* `pusty`
* `pusty.kopia`
* `pusty.kopia1`\
  i kolejne, w razie potrzeby.

<figure><img src="/files/B5pPe8fImCwQ8po9k67L" alt=""><figcaption><p><em><strong>Ilustracja 6.</strong> Wiersz po dodaniu klucza i nieuzupełnieniu jego nazwy</em></p></figcaption></figure>

***

### Wybór domyślnego języka (taga)

Domyślnego języka można dokonać w nagłówku tabeli. Opcja ta jest dostępna wyłącznie w trakcie edycji procesu.

Domyślnie ustawionym językiem jest **polski**.

Aby ustawić język jako domyślny, należy kliknąć ikonę gwiazdki obok kodu języka. ![](/files/0tlm6D1De8LPrfYgsBav)\
Żółta gwiazdka oznacza aktualnie wybrany domyślny język. ![](/files/C97ppmdmbQCgKVIRbFT9)

<figure><img src="/files/lwTPeJBUflle52GvKym4" alt=""><figcaption><p><em><strong>Ilustracja 7.</strong> Wybór języka tłumaczeń</em></p></figcaption></figure>

***

### Filtrowanie pustych tłumaczeń

Aby ukryć klucze pozbawione tłumaczeń, należy kliknąć ikonę znajdującą się w kolumnie **KLUCZ**.

Aktywny filtr jest oznaczony przekreślonym symbolem „oczka” ![](/files/lLS4JpDp3eob6y7pY5WO). Dodatkowo wyświetlana jest informacja o liczbie ukrytych kluczy ![](/files/FNhMHSfhgbFFunPhCsHj).

***

### Wyszukiwanie tłumaczeń

Wyszukiwarka działa zarówno po nazwach kluczy, jak i po wartościach tłumaczeń.

<figure><img src="/files/aq2VUpm3ywyFNplSV9UR" alt=""><figcaption><p><em><strong>Ilustracja 8.</strong> Wyszukiwanie tłumaczeń</em></p></figcaption></figure>

Jeśli nie znaleziono wyników, wyświetlany jest komunikat:

```
Nie znaleźliśmy klucza lub tłumaczenia: ${szukanyTekst}
```

W tym momencie użytkownik otrzymuje również propozycję dodania nowego klucza.\
Po dodaniu klucza pole wyszukiwania zostaje automatycznie wyczyszczone.

***

### Dodawanie i edycja języków

Aby dodać nowy język, należy kliknąć przycisk dodawania nowej kolumny znajdujący się po prawej stronie tabeli.

<figure><img src="/files/df7gQ9PlyPhw703cxSiE" alt=""><figcaption><p><em><strong>Ilustracja 9.</strong> Przycisk dodawania nowego języka tłumaczeń</em></p></figcaption></figure>

Nazwa (tag) języka może zostać zmieniona poprzez kliknięcie w jego nagłówek.

**Kod języka** powinien być zgodny ze standardem **ISO 639**, zapisany małymi literami.\
Lista obsługiwanych kodów dostępna jest pod adresem:\
<https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html>

***

## Ustalanie języka obowiązującego podczas otwierania wniosku

Przy podjęciu wniosku do wypełnienia system ustala język w następującej kolejności:

#### 1. Parametr „locale” w URL

Jeśli w adresie wejściowym znajduje się parametr `locale`, a szablon zawiera tłumaczenia dla podanego języka, to właśnie ten język zostanie użyty.

**Przykład:**

```
https://url.eximee/webforms/ek/index.html?locale=en
```

***

#### 2. Akceptowane języki przeglądarki (Accept-Language)

Jeśli parametr URL nie jest dostępny, a w konfiguracji Webforms parametr:

```
server/locale/browserLocaleAllowed = true
```

to system pobierze język z nagłówka `Accept-Language`, pod warunkiem że szablon posiada odpowiednie tłumaczenia.

**Przykład:**

```
https://url.eximee/webforms/ek/index.html
Accept-Language: pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7,en-gb;q=0.6,fr-FR;q=0.4,fr;q=0.3,es-CO;q=0.2,es;q=0.1
```

***

#### 3. Domyślny język szablonu

Jeśli żaden z powyższych warunków nie zostanie spełniony, stosowany jest **domyślny język szablonu**, ustawiony w Eximee Designer.


# Platformowe klucze tłumaczeń

## Klucze tłumaczeń

### Czym są klucze tłumaczeń?

Klucze tłumaczeń służą do **nadpisywania domyślnych treści** wyświetlanych we wniosku — takich jak etykiety, opisy, komunikaty walidacyjne czy treści komponentów.

Warto pamiętać, że **zmiana klucza na poziomie wniosku wpływa na cały szablon**, ponieważ klucz jest interpretowany globalnie w obrębie danego szablonu.

{% hint style="danger" %}
Dostępność kluczy tłumaczeń zależy od posiadanej licencji i może różnić się pomiędzy wdrożeniami.
{% endhint %}

***

### Gdzie ustawia się lub dodaje klucze tłumaczeń?

Klucze tłumaczeń oraz literały dodaje się w zakładce **Tłumaczenia** dostępnej w edytorze wniosku.\
Szczegółowy opis tego obszaru znajduje się w rozdziale: **Zakładka Tłumaczenia edytora wniosku**.

***

### Skąd wczytywane są klucze tłumaczeń?

Klucze tłumaczeń wczytywane są z trzech źródeł, w ściśle określonej kolejności:

#### 1. Klucze podstawowe (najniższy priorytet)

Zestaw kluczy umieszczony w:

```
eximee-webforms/webforms-server/src/main/resources/navigation/navigation.localization
```

Są to klucze dostarczane standardowo wraz z platformą.

***

#### 2. Klucze z zasobów zewnętrznych

Następnie wczytywane są klucze z lokalizacji:

```
external-resources/navigation/navigation.localization
```

Ścieżka do katalogu `external-resources` jest określana parametrem startowym:

```
-Dwebforms.resources
```

Pozwala to klientom na dostarczenie własnej warstwy tłumaczeń bez modyfikowania binariów.

***

#### 3. Klucze zdefiniowane we wniosku (najwyższy priorytet)

Na końcu ładowane są klucze zadeklarowane bezpośrednio we wniosku.\
To właśnie one **nadpisują wszystkie wcześniejsze wartości**, dzięki czemu stanowią najwyższą warstwę priorytetu.

***

### Dlaczego kolejność ma znaczenie?

Ładowanie kluczy odbywa się warstwowo: kolejne źródła mogą nadpisywać klucze wczytane wcześniej.\
Oznacza to:

* klucze z `resources/navigation/navigation.localization` mają **najniższy priorytet**,
* klucze z `external-resources` mogą je **nadpisywać**,
* klucze zdefiniowane w samym wniosku **mają najwyższy priorytet**.

W efekcie, jeśli ten sam klucz występuje w wielu miejscach, decydująca jest jego **ostatnia** wczytana definicja.

### **Często używane klucze platformowe**

|                                                                                                                                                                                                                                                                                                                                                                                             |                                                           |                                                                                                                                                                                                        |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| form.title                                                                                                                                                                                                                                                                                                                                                                                  | nazwa artefaktu                                           | Nazwa wniosku                                                                                                                                                                                          |
| iew\.navigation.required                                                                                                                                                                                                                                                                                                                                                                    | "Pole wymagane"                                           | Komunikat wyświetlający się pod polami wymaganymi. Jego zmiana wpłynie na wszystkie komponenty wniosku.                                                                                                |
| iew\.navigation.submit                                                                                                                                                                                                                                                                                                                                                                      | "Wyślij"/"Wyślij wniosek/Zapisz"                          | Tekst na przycisku na ostatniej stronie wniosku                                                                                                                                                        |
| iew\.navigation.next                                                                                                                                                                                                                                                                                                                                                                        | "Dalej"                                                   | Tekst na przycisku przejścia na kolejną stronę wniosku                                                                                                                                                 |
| iew\.navigation.prev                                                                                                                                                                                                                                                                                                                                                                        | "Wstecz"/"Powrót"/"Cofnij"                                | Tekst na przycisku przejścia na poprzednią stronę wniosku                                                                                                                                              |
| iew\.finishPage.description                                                                                                                                                                                                                                                                                                                                                                 | zależna od wdrożenia                                      | Tekst na stronie po wysłaniu wniosku                                                                                                                                                                   |
| iew\.navigation.cancel.button                                                                                                                                                                                                                                                                                                                                                               | Anuluj / Cancel                                           | Tekst na przycisku Anuluj                                                                                                                                                                              |
| iew\.navigation.print.button                                                                                                                                                                                                                                                                                                                                                                | Drukuj / Print                                            | Tekst na przycisku drukowania                                                                                                                                                                          |
| <p>iew\.statements.fold - Zwiń treść zgód</p><p>iew\.statements.unfold - Rozwiń treść zgód</p><p>iew\.statements.item.unfold - Pełna treść zgody</p><p>iew\.statements.item.fold - Zwiń treść zgody</p><p>iew\.statements.header.fold - Zwiń treść</p><p>iew\.statements.header.unfold - Rozwiń treść</p><p>iew\.statements.item.fold - Zwiń</p><p>iew\.statements.item.unfold - Rozwiń</p> | wartość domyślna zależy od wdrożenia oraz typu oświadczeń | <p>Klucze tłumaczeń dla oświadczeń</p><p>Więcej kluczy w: <a href="https://wiki.consdata.pl/pages/viewpage.action?pageId=387948640">Oświadczenia - dodatkowe właściwości</a>/Klucze dla Oświadczeń</p> |
| iew\.upload.addFile                                                                                                                                                                                                                                                                                                                                                                         | zależna od wdrożenia                                      | Tekst na przycisku dodawania załącznika                                                                                                                                                                |

### Pełna lista kluczy platformowych

<details>

<summary>Ogólne</summary>

Klucze Ogólne

|                                                             |                                                                                                                                                                                            |
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| iew\.validator.required                                     | Pole wymagane                                                                                                                                                                              |
| iew\.autocompleter.valueRestored                            | Informacja, że zmiana wartości pola z autouzupełnianiem została wycofana.                                                                                                                  |
| iew\.required.validator.message                             | Pole wymagane                                                                                                                                                                              |
| iew\.accesskey.button\_name                                 | Klawisz dostępu                                                                                                                                                                            |
| iew\.accesskey.command                                      | Naciśnij                                                                                                                                                                                   |
| AuthorizationValidator.invalid.mobile                       | Nieudana autoryzacja                                                                                                                                                                       |
| iew\.challenge.response.token.label                         | Podaj kod z tokena                                                                                                                                                                         |
| iew\.challenge.response.token.left.label                    | Obrazek bezpieczeństwa                                                                                                                                                                     |
| iew\.challenge.response.token.visibleMask                   | 99999999                                                                                                                                                                                   |
| iew\.challenge.response.token.mask                          | \d\d\d\d\d\d\d\d                                                                                                                                                                           |
| iew\.cookie.disclosure.message                              | W celu zachowania najwyższej jakości usług wykorzystujemy informacje przechowywane w plikach cookies. Zmiany zasad korzystania z plików cookies można dokonać w ustawieniach przeglądarki. |
| iew\.cookie.link.text                                       | Dowiedz się więcej                                                                                                                                                                         |
| iew\.product.active.title                                   | Wybrana karta:                                                                                                                                                                             |
| iew\.resignation.title                                      | Pytanie                                                                                                                                                                                    |
| iew\.resignation.question                                   | Wprowadzone dane zostaną utracone. Czy chcesz opuścić wniosek?                                                                                                                             |
| iew\.sessionExpirationPanel.message                         | Twoja sesja wygaśnie za                                                                                                                                                                    |
| iew\.sessionExpirationPanel.button\_text                    | Przedłuż sesję                                                                                                                                                                             |
| iew\.mobile.authorization.label                             | Powiadomienie autoryzacji zostało wysłane do urządzenia mobilnego.                                                                                                                         |
| iew\.mobile.authorization.longTimeLeft                      | Pozostań na tej stronie i potwierdź operację w aplikacji mobilnej.                                                                                                                         |
| iew\.mobile.authorization.shortTimeLeft                     | Oczekiwanie na podpis aplikacją mobilną.                                                                                                                                                   |
| iew\.navigation.dialogParkConfirmation                      | Wniosek został tymczasowo zapisany w systemie.                                                                                                                                             |
| iew\.navigation.dialogParkConfirmation.linkDescription      | W celu powrotu do wniosku prosimy o skorzystanie z podanego linku.                                                                                                                         |
| iew\.navigation.dialogParkConfirmation.autopark             | Autozapis                                                                                                                                                                                  |
| iew\.navigation.dialogSubmitSuccessInformation              | Wniosek został poprawnie zapisany w systemie.                                                                                                                                              |
| iew\.navigation.dialogInternalFatalError                    | Niestety nie można w tym momencie dokończyć wypełniania wniosku. Proszę spróbować później.                                                                                                 |
| iew\.navigation.dialogNavigationNotAllowed                  | Nawigacja do podanej strony nie jest możliwa!                                                                                                                                              |
| iew\.navigation.dialogSubmitFailureInformation              | Wniosek nie został poprawnie zapisany w systemie.                                                                                                                                          |
| iew\.navigation.dialogResignationFailureInformation         | Wystąpił błąd podczas rezygnacji z wniosku.                                                                                                                                                |
| iew\.csvFileUpload.undetectableDelimiterTitle               | Niepoprawny separator                                                                                                                                                                      |
| iew\.csvFileUpload.undetectableDelimiterMessage             | Nie wykryto separatorów w wysłanym pliku CSV. Proszę wskazać poprawny plik.                                                                                                                |
| iew\.onexit.popup.header                                    | Czy na pewno chcesz przerwać składanie wniosku?                                                                                                                                            |
| iew\.notvlaid.popup.button                                  | OK                                                                                                                                                                                         |
| iew\.cookie.accept.message                                  | Akceptuję ciasteczka na tej stronie                                                                                                                                                        |
| iew\.cookie.close                                           | Nie pokazuj tej informacji ponownie                                                                                                                                                        |
| iew\.confirmation.deleted                                   | Usunięto                                                                                                                                                                                   |
| iew\.confirmation.empty.label                               | BRAK                                                                                                                                                                                       |
| iew\.notvlaid.popup.title                                   | Błąd walidacji                                                                                                                                                                             |
| iew\.confirmation.mandatory                                 | Musisz zatwierdzić sekcję przed kontynuowaniem                                                                                                                                             |
| iew\.notvlaid.popup.message                                 | Formularz zawiera błędy walidacji.                                                                                                                                                         |
| iew\.finishPage.description                                 | Dziękujemy za zainteresowanie naszą ofertą i złożenie wniosku                                                                                                                              |
| iew\.finishPage.header                                      | Dziękujemy za złożenie wniosku                                                                                                                                                             |
| iew\.finishPage.title                                       | Zakończenie                                                                                                                                                                                |
| iew\.summaryPage.title                                      | Podsumowanie                                                                                                                                                                               |
| iew\.challenge.response.token.maskError                     | Wprowadzona wartość jest niepoprawna                                                                                                                                                       |
| AuthorizationValidator.invalid.challengeResponseToken       | Nieudana autoryzacja                                                                                                                                                                       |
| badTokenResponse.challengeResponseToken                     | Niepoprawny kod z tokena                                                                                                                                                                   |
| iew\.noscript.title                                         | Błąd przeglądarki                                                                                                                                                                          |
| iew\.noscript.content                                       | Aby poprawnie wyświetlić tę stronę musisz mieć aktywną obsługę JavaScript w przeglądarce.                                                                                                  |
| iew\.validation.external.internal.noWidgetForLocalValue     | Wystąpił wewnętrzny problem walidacji                                                                                                                                                      |
| iew\.validation.external.validatorIsUnavailable             | Zewnętrzny walidator jest niedostępny                                                                                                                                                      |
| iew\.navigation.formNotValidErrorMessage                    | Nie można zapisać wniosku z powodu błędów walidacji                                                                                                                                        |
| iew\.navigation.stepProgressText                            | Krok %d z %d                                                                                                                                                                               |
| iew\.navigation.globalPageProgressText                      | Strona globalna %d z %d                                                                                                                                                                    |
| iew\.navigation.localPageProgressText                       | Strona %d z %d                                                                                                                                                                             |
| iew\.park.popup.password                                    | Hasło                                                                                                                                                                                      |
| iew\.park.popup.repeatPassword                              | Powtórz hasło                                                                                                                                                                              |
| iew\.park.popup.email                                       | Email                                                                                                                                                                                      |
| iew\.error.page.title                                       | Błąd systemu                                                                                                                                                                               |
| iew\.error.page.message                                     | Nastąpił błąd systemu wnioskowego. Spróbuj zalogować się ponownie. Identyfikator błędu:                                                                                                    |
| iew\.error.page.hash.message                                | Identyfikator błędu:                                                                                                                                                                       |
| iew\.park.popup.validation.samePassword                     | Hasło musi być takie samo                                                                                                                                                                  |
| iew\.park.popup.validation.passwordTooShort                 | Hasło musi zawierać co najmniej 4 znaki                                                                                                                                                    |
| iew\.park.popup.dialogParkInformation.line1                 | Wniosek jest zapisywany na okres 30 dni.                                                                                                                                                   |
| iew\.park.popup.dialogParkInformation.line2                 | Instrukcje powrotu do wniosku otrzymasz na podany adres email.                                                                                                                             |
| iew\.park.popup.passwordHint                                | UWAGA: Hasło powinno posiadać minimum 4 znaki.                                                                                                                                             |
| iew\.park.popup.title                                       | Tymczasowy zapis wniosku                                                                                                                                                                   |
| iew\.unpark.popup.password                                  | Hasło                                                                                                                                                                                      |
| iew\.unpark.popup.email                                     | Email                                                                                                                                                                                      |
| iew\.unpark.popup.dataRequiredToUnparkApplication           | Wpisz dane podane podczas zapisu wniosku o nr: %s                                                                                                                                          |
| iew\.unpark.popup.applicationUnparkedError                  | Nie można odparkować wniosku o numerze %s                                                                                                                                                  |
| iew\.unpark.popup.applicationUnparkedError.title            | Powrót do wniosku                                                                                                                                                                          |
| iew\.unpark.mobile.returnToForm                             | Powrót do wniosku nr                                                                                                                                                                       |
| iew\.unpark.popup.noSpecifiedApplicationNumber              | Brak numeru wniosku                                                                                                                                                                        |
| iew\.unpark.popup.title                                     | Powrót do wniosku                                                                                                                                                                          |
| iew\.email.validator.wrongFormat                            | Pole musi posiadać poprawny format email                                                                                                                                                   |
| iew\.navigation.personalDataProcessingAgreementCheckbox     | Oświadczam, iż wyrażam zgodę na przetwarzanie moich danych osobowych                                                                                                                       |
| iew\.page.validation.errors.message                         | Strona zawiera błędy walidacji                                                                                                                                                             |
| iew\.confirmation.delete.description                        | Wybranie tej opcji spowoduje usunięcie {0}                                                                                                                                                 |
| iew\.confirmation.delete.blank.text                         | Brak tekstu do usunięcia                                                                                                                                                                   |
| iew\.validator.length.tooLong                               | Zbyt wiele znaków                                                                                                                                                                          |
| iew\.validator.length.tooShort                              | Zbyt mało znaków                                                                                                                                                                           |
| iew\.camera.noAccessMessage                                 | Brak dostępu do kamery                                                                                                                                                                     |
| iew\.validation.popup.title                                 | Niepoprawne dane                                                                                                                                                                           |
| iew\.validation.popup.cancelButton                          | Anuluj                                                                                                                                                                                     |
| iew\.validation.popup.changeValueButton                     | Dalej                                                                                                                                                                                      |
| iew\.unpark.otp.popup.title                                 | Wpisz kod SMS                                                                                                                                                                              |
| iew\.unpark.otp.popup.message                               | Na podany przez Ciebie numer telefonu wysłaliśmy kod SMS potrzebny do wejścia na wniosek. Wpisz go w polu poniżej.                                                                         |
| iew\.unpark.otp.popup.unparkErrorMessage                    | Wpisany przez Ciebie kod jest nieprawidłowy. Spróbuj ponownie.                                                                                                                             |
| iew\.unpark.otp.popup.sendSmsErrorMessage                   | Nie udało się wysłać wiadomości SMS z kodem. Spróbuj ponownie za chwilę.                                                                                                                   |
| iew\.unpark.otp.popup.code                                  | Kod SMS                                                                                                                                                                                    |
| iew\.navigation.unpark.otp                                  | OK                                                                                                                                                                                         |
| iew\.navigation.unpark.tooManyTries                         | Przekroczono limit prób wpisania kodu                                                                                                                                                      |
| iew\.navigation.unpark.otp.return.label                     | Powrót do strony głównej                                                                                                                                                                   |
| iew\.navigation.unpark.otp.return.url                       | undefined                                                                                                                                                                                  |
| iew\.navigation.resume.popup.case.message                   | Podaj numer sprawy                                                                                                                                                                         |
| iew\.navigation.resume.popup.title                          | Wznów sprawę                                                                                                                                                                               |
| iew\.navigation.resume.popup.otp.message                    | Na podany przez Ciebie numer telefonu wysłaliśmy kod SMS potrzebny do wejścia na wniosek. Wpisz go w polu poniżej.                                                                         |
| iew\.navigation.resume.popup.button                         | OK                                                                                                                                                                                         |
| iew\.navigation.resume.error                                | Wystąpił błąd podczas wznawiania sprawy                                                                                                                                                    |
| iew\.navigation.resume.validation.error.message             | Wpisany przez Ciebie kod jest nieprawidłowy. Spróbuj ponownie.                                                                                                                             |
| iew\.popup.onexit.message                                   | Kontakt telefoniczny ze strony banku w sprawie konta                                                                                                                                       |
| iew\.popup.thankyou.message                                 | Dziękujemy. Zadzwonimy w ciągu 24 godzin.                                                                                                                                                  |
| iew\.popup.doradca.message                                  | Potrzebujesz pomocy? Masz pytania?                                                                                                                                                         |
| iew\.popup.doradca.actionsHeader.videoOnly                  | Rozpocznij rozmowę klikając w przycisk Wideo.                                                                                                                                              |
| iew\.popup.doradca.actionsHeader                            | Aby połączyć, wybierz rodzaj rozmowy.                                                                                                                                                      |
| iew\.popup.doradca.description                              | undefined                                                                                                                                                                                  |
| iew\.popup.doradca.back                                     | Wróć do wniosku                                                                                                                                                                            |
| iew\.popup.doradca.channel.audio                            | Audio                                                                                                                                                                                      |
| iew\.popup.doradca.channel.video                            | Wideo                                                                                                                                                                                      |
| iew\.popup.doradca.channel.chat                             | Chat                                                                                                                                                                                       |
| iew\.navigation.resume.retry                                | Wyślij ponownie                                                                                                                                                                            |
| iew\.tealium.form.title                                     | Złożono wniosek ${formInstanceNumber}                                                                                                                                                      |
| iew\.tealium.finish.url                                     | /success/${formInstanceNumber}                                                                                                                                                             |
| iew\.resign.confirmation.question                           | Na pewno anulować?                                                                                                                                                                         |
| iew\.resign.confirmation.yes                                | Tak                                                                                                                                                                                        |
| iew\.resign.confirmation.no                                 | Nie                                                                                                                                                                                        |
| iew\.resign.confirmation.message                            | Dziękujemy za zainteresowanie naszą ofertą. W przypadku rezygnacji z oferty, nie będzie już możliwości kontynuowania wniosku. Czy na pewno chcesz zrezygnować?                             |
| iew\.resign.confirmation.title                              | Rezygnacja                                                                                                                                                                                 |
| iew\.navigation.dialogPark.parkSuccess                      | Robocza wersja wniosku został zapisana. Na Twój adres email wysłaliśmy wiadomość z instrukcją powrotu do wypełniania wniosku.                                                              |
| iew\.navigation.dialogPark.parkFailure                      | Nie udało się zapisać roboczej wersji wniosku.                                                                                                                                             |
| iew\.concurrentFormParking.otp.invalid                      | Nieprawidłowy kod                                                                                                                                                                          |
| iew\.navigation.concurrentFormParking.transferToClient      | przekaż do klienta                                                                                                                                                                         |
| iew\.navigation.concurrentFormParking.transferToAdvisor     | przekaż do doradcy                                                                                                                                                                         |
| iew\.navigation.dialogConcurrentFormTransferred.ok          | OK                                                                                                                                                                                         |
| iew\.navigation.dialogConcurrentFormTransferred.description | Twój wniosek został przekazany                                                                                                                                                             |
| iew\.park.popup.phoneNumber                                 | Numer telefonu                                                                                                                                                                             |
| iew\.park.popup.validation.phoneNumber.mask                 | Należy wprowadzić 9 cyfr.                                                                                                                                                                  |
| iew\.park.popup.validation.emailAddress.mask                | Nieprawidłowy adres e-mail.                                                                                                                                                                |
| iew\.successpage.nativeapi.status.text                      | Dziękujemy za złożenie wniosku                                                                                                                                                             |
| iew\.successpage.nativeapi.status.action.text               | Zamknij                                                                                                                                                                                    |
| iew\.nativeapi.errorpage.noconnection.header                | Brak połączenia z internetem                                                                                                                                                               |
| iew\.nativeapi.errorpage.noconnection.text                  | Operacja nie może być zrealizowana. Przejdź do ustawień telefonu, żeby włączyć transmisję danych lub połączyć się z siecią Wi-Fi.                                                          |
| iew\.navigation.thankYouPage.redirect                       | Zakończ                                                                                                                                                                                    |
| iew\.goodbye.popup.message                                  | undefined                                                                                                                                                                                  |
| iew\.goodbye.popup.phone.label                              | Numer telefonu:                                                                                                                                                                            |
| iew\.goodbye.popup.phone.validation                         | Podano błędny numer telefonu. Poprawny format: (000-000-000)                                                                                                                               |
| iew\.goodbye.popup.prefix.validation                        | Podano błędny prefix. Poprawny format: (+00)                                                                                                                                               |
| iew\.security.validator.max.length                          | Wartość pola przekroczyła maksymalny limit znaków, przywróciliśmy poprzednią wartość pola                                                                                                  |
| iew\.security.validator.character.whitelist                 | Wartość zawierała niedozwolone znaki, przywróciliśmy poprzednią wartość pola                                                                                                               |
| iew\.switch                                                 | Zmień                                                                                                                                                                                      |
| iew\.switch.confirmation.message                            | Czy na pewno chcesz zmienić wniosek?                                                                                                                                                       |
| iew\.switch.confirmation.yes                                | Tak                                                                                                                                                                                        |
| iew\.switch.confirmation.no                                 | Nie                                                                                                                                                                                        |
| iew\.switch.confirmation.finish.later                       | Zapisz i zmień                                                                                                                                                                             |
| iew\.spinner.text                                           | Prosimy o chwilę cierpliwości...                                                                                                                                                           |
| iew\.navigation.back.main.page                              | Wróć do strony głównej                                                                                                                                                                     |
| iew\.unpark.title                                           | Powrót do wniosku                                                                                                                                                                          |
| iew\.onexit.popup.page2.message                             | W dowolnym momencie możesz go wznowić.                                                                                                                                                     |
| iew\.onexit.popup.page2.success.info                        | Wniosek został zapisany                                                                                                                                                                    |
| iew\.onexit.popup.save                                      | Zapisz wniosek                                                                                                                                                                             |
| iew\.onexit.popup.continue                                  | Kontynuuj wniosek                                                                                                                                                                          |
| iew\.onexit.popup.page2.message.mobile                      | W dowolnym momencie możesz go wznowić.                                                                                                                                                     |
| iew\.onexit.popup.page2.success.info.mobile                 | Wniosek został zapisany                                                                                                                                                                    |
| iew\.onexit.popup.page1.return.mobile                       | ANULUJ WNIOSEK                                                                                                                                                                             |
| iew\.onexit.popup.save.mobile                               | KONTYNUUJĘ                                                                                                                                                                                 |
| iew\.onexit.popup.continue.mobile                           | KONTYNUUJ                                                                                                                                                                                  |
| iew\.navigation.confirm                                     | zatwierdź                                                                                                                                                                                  |
| iew\.upload.fileLimit                                       | undefined                                                                                                                                                                                  |
| iew\.upload.description.bottom                              | undefined                                                                                                                                                                                  |
| iew\.epg.phone.register.send.again.desc                     | Wysłaliśmy ponownie kod SMS na Twój numer {0}                                                                                                                                              |
| iew\.epg.phone.register.confirm.desc                        | Zweryfikowaliśmy Twój numer telefonu {0}                                                                                                                                                   |
| iew\.unsupportedBrowser.firstLine                           | Przeglądarka internetowa której używasz nie jest wspierana lub wymaga aktualizacji                                                                                                         |
| iew\.unsupportedBrowser.secondLine                          | Niektóre funkcjonalności formularza mogą działać niepoprawnie w tej przeglądarce                                                                                                           |
| iew\.auth.component.otpNotFound                             | Nie znaleziono OTP w sesji.                                                                                                                                                                |
| iew\.auth.component.otpValidationError                      | Podano błędny kod autoryzacji.                                                                                                                                                             |
| iew\.auth.component.maxOtpNumberError                       | Przekroczyłeś liczbę dostępnych smsKodów. Proszę wypełnić wniosek ponownie.                                                                                                                |
| iew\.unsupportedBrowser.linkDescription                     | Skopiuj poniższy link a następnie wklej go w pasku adresu przeglądarki Google Chrome                                                                                                       |
| iew\.authorization.nopush                                   | Nie dostałeś powiadomienia autoryzacyjnego? Nic nie szkodzi - zaloguj się do aplikacji i zatwierdź operację.                                                                               |
| iew\.unpark.message                                         | Wpisz kod SMS wysłany na numer {0}, aby powrócić do wniosku.                                                                                                                               |
| iew\.unpark.input.label                                     | Kod SMS                                                                                                                                                                                    |
| iew\.unpark.input.description                               | SMS nie dotarł?                                                                                                                                                                            |
| iew\.unpark.input.resend                                    | Wyślij ponownie                                                                                                                                                                            |
| iew\.unpark.input.invalidCode                               | Kod jest nieprawidłowy                                                                                                                                                                     |
| iew\.unpark.sent.again.code.popup.message                   | Wysłaliśmy ponownie kod SMS na Twój numer                                                                                                                                                  |
| iew\.unpark.sent.again.code.popup.close                     | Dalej                                                                                                                                                                                      |
| iew\.resign.confirmation.button.finish.later                | Zapisz i dokończ później                                                                                                                                                                   |
| iew\.value.sanitized                                        | Usunęliśmy znaki niedozwolone: {0}                                                                                                                                                         |
| iew\.payment.verification.spinnerDescription                | Czekamy na potwierdzenie płatności                                                                                                                                                         |
| iew\.autopark.bottombar.message.parameters.changed          | Warunki tego produktu zmieniły się od momentu, gdy ostatnio wypełniałeś wniosek. Podaj dane od początku, aby się z nimi zapoznać.                                                          |
| iew\.autopark.bottombar.message.unpark.availability         | Pamiętaj, że jeśli nie ukończysz składania wniosku to możesz do niego wrócić. Dane, które wypełnisz będą dostępne przez 30 dni.                                                            |
| iew\.autoUnpark.popup.tittle                                | Nie trać czasu, wypełniaj dalej                                                                                                                                                            |
| iew\.autoUnpark.popup.message                               | undefined                                                                                                                                                                                  |
| iew\.autoUnpark.popup.button.unpark.form                    | wypełniam dalej                                                                                                                                                                            |
| iew\.autoUnpark.popup.button.new\.form                      | zaczynam od nowa                                                                                                                                                                           |

</details>

<details>

<summary>Nawigacyjne</summary>

Klucze nawigacyjne

|                                               |                                           |
| --------------------------------------------- | ----------------------------------------- |
| iew\.navigation.localPageText                 | Strona                                    |
| iew\.navigation.ok                            | OK                                        |
| iew\.navigation.dialogParkConfirmation.ok     | OK                                        |
| iew\.navigation.dialogSubmitSuccessButtonText | ZAMKNIJ                                   |
| iew\.navigation.dialogSubmitFailureButtonText | ZAMKNIJ                                   |
| iew\.navigation.dialogParkConfirmButton       | Zapisz                                    |
| iew\.navigation.cancel.button                 | Anuluj                                    |
| iew\.navigation.cancel.confirmation.question  | Na pewno anulować?                        |
| iew\.navigation.prev.firstPage                | Wróć                                      |
| iew\.navigation.confirmation.yes              | Tak                                       |
| iew\.navigation.confirmation.no               | Nie                                       |
| iew\.navigation.print.button                  | Drukuj                                    |
| iew\.resignation.cancel.button                | Anuluj                                    |
| iew\.navigation.cancel                        | Anuluj                                    |
| iew\.upload.addFile                           | Dodaj załącznik                           |
| iew\.confirmation.edit                        | Edytuj                                    |
| iew\.confirmation.modify                      | Modyfikuj                                 |
| iew\.confirmation.delete                      | Usuń                                      |
| iew\.navigation.goToDesktop                   | Przejdź do pulpitu                        |
| iew\.tansms.sms.button.label                  | Akceptuję                                 |
| iew\.navigation.goToDesktop                   | Wróć do pulpitu                           |
| iew\.confirmation.submit                      | Zatwierdź                                 |
| iew\.confirmation.cancel                      | Anuluj                                    |
| iew\.navigation.park                          | Zapisz wniosek do późniejszej modyfikacji |
| iew\.navigation.unpark                        | Dalej                                     |
| iew\.navigation.close                         | Zamknij                                   |
| iew\.rollable.roll                            | Zwiń                                      |
| iew\.rollable.show\.more                      | Pokaż więcej                              |
| iew\.numberAbbreviation                       | undefined                                 |
| iew\.resignation.confirm.button               | Ok                                        |
| iew\.navigation.parkShort                     | Zapisz                                    |
| iew\.global.globalNavbarResignShort           | Rezygnuj                                  |
| iew\.global.globalNavbarLogoutShort           | Wyloguj                                   |
| iew\.global.globalNavbarFinishShort           | Zakończ                                   |
| iew\.global.globalNavbarSignShort             | Podpisz                                   |
| iew\.global.globalNavbarResign                | Rezygnuj z wniosku                        |
| iew\.global.globalNavbarFinish                | Zakończ wniosek                           |
| iew\.global.retryForm                         | Wypełnij wniosek ponownie                 |
| iew\.navigation.prev.mbwhite                  | cofnij                                    |
| iew\.navigation.prev                          | Cofnij                                    |
| iew\.navigation.next                          | Dalej                                     |
| iew\.navigation.finish                        | Zakończ                                   |
| iew\.navigation.summary                       | Podsumowanie                              |
| iew\.navigation.option                        | ...                                       |
| iew\.tooltip.dialog.title                     | Pomoc                                     |
| iew\.navigation.submit                        | Wyślij wniosek                            |

</details>

<details>

<summary>Komponenty</summary>

Sekcja powtarzalna - RepeatableSection

|                                        |                        |
| -------------------------------------- | ---------------------- |
| iew\.repeatablesection.addRow          | Dodaj                  |
| iew\.repeatablesection.removeRow       | Usuń                   |
| iew\.repeatablesection.removeRow\.aria | Usuń wiersz numer {0}. |

Tabela - Table

|                                                      |                                                                                                                                |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| iew\.table.simpleValidationError                     | Wprowadzono niepoprawne dane                                                                                                   |
| iew\.table.expandable.cell.save                      | Zapisz                                                                                                                         |
| iew\.table.expandable.cell.cancel                    | Anuluj                                                                                                                         |
| iew\.table.emptyRequired                             | (brak)                                                                                                                         |
| iew\.table.maskErrorDefault                          | Niepoprawny format                                                                                                             |
| iew\.tableHeader.columnsVisibleOnlyInEditModeMessage | Tabela ma kolumny widoczne tylko w trybie edycji                                                                               |
| tokenBlocked.challengeResponseToken                  | Token jest zablokowany                                                                                                         |
| iew\.table.editPopup.copy                            | Kopiuj                                                                                                                         |
| iew\.table.unique.row\.msg                           | Wiersz o podanej treści już istnieje!                                                                                          |
| iew\.table.unique.header.msg                         | Duplikaty:                                                                                                                     |
| iew\.table.unique.table.msg                          | Tabela zawiera duplikaty!                                                                                                      |
| iew\.table.editPopup.paste                           | Wklej                                                                                                                          |
| iew\.table.editPopup.close                           | Zamknij                                                                                                                        |
| iew\.table.editPopup.checkAll                        | Zaznacz wszystkie                                                                                                              |
| iew\.table.editPopup.uncheckAll                      | Odznacz wszystkie                                                                                                              |
| iew\.table.deletedItems.label                        | Elementy usunięte                                                                                                              |
| iew\.table.previewPopup.open                         | Pokaż wszystkie                                                                                                                |
| iew\.table.previewPopup.openPreview                  | Podgląd                                                                                                                        |
| iew\.csvFileUpload.importLabel                       | Importuj                                                                                                                       |
| iew\.csvFileUpload.importTooltip                     | undefined                                                                                                                      |
| iew\.csvFileUpload.sizeLimitExceededTitle            | Niedozwolony rozmiar pliku                                                                                                     |
| iew\.csvFileUpload.sizeLimitExceededMessage          | Wybrany plik jest za duży. Maksymalny dopuszczalny rozmiar pliku wynosi: {0} kB                                                |
| iew\.csvFileUpload.unsupportedBrowserTitle           | Nieobsługiwana przeglądarka                                                                                                    |
| iew\.csvFileUpload.unsupportedBrowserMessage         | Przeglądarka, której używasz, nie obsługuje importu danych z pliku CSV. Prosimy o korzystanie z najnowszej wersji przeglądarki |
| iew\.csvFileUpload.missingQuotes                     | Niepoprawny format CSV - brak cudzysłowu.                                                                                      |
| iew\.csvFileUpload.invalidFormat                     | Niepoprawny format CSV.                                                                                                        |
| iew\.table.editPopup.open                            | Edytuj                                                                                                                         |
| iew\.table.pagination.of                             | z                                                                                                                              |
| iew\.table.editPopup.save                            | Zapisz                                                                                                                         |

Szablon karty - PictureCard

|                                                    |                                                                                                              |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| iew\.pictureCard.required                          | Zapisz wybraną kartę lub anuluj zmiany                                                                       |
| iew\.pictureCard.noImage                           | Wybierz obraz z galerii lub załaduj własny obraz. Następnie przejdź dalej.                                   |
| iew\.pictureCard.uploadedPictureLimitExceeded      | Wybrany plik jest za duży. Maksymalny dopuszczalny rozmiar pliku wynosi: {0} kB                              |
| iew\.pictureCard.uploadedPictureLimitExceededTitle | Niedozwolony rozmiar pliku                                                                                   |
| iew\.pictureCard.uploadedPictureBroken             | Wybrany plik ma niepoprawny format bądź jest uszkodzony. Proszę wybrać plik obrazu w formacie jpg lub png.   |
| iew\.pictureCard.uploadedPictureBrokenTitle        | Niepoprawny plik                                                                                             |
| iew\.pictureCard.uploadPicture                     | Załaduj obraz                                                                                                |
| iew\.pictureCard.selectFromGallery                 | Wybierz z galerii                                                                                            |
| iew\.pictureCard.editCard                          | Edytuj kartę                                                                                                 |
| iew\.pictureCard.saveAndExit                       | Zapisz i zamknij                                                                                             |
| iew\.pictureCard.saveAndExitShort                  | Zapisz                                                                                                       |
| iew\.pictureCard.cancel                            | Anuluj                                                                                                       |
| iew\.pictureCard.replaceImage                      | Zmień obraz                                                                                                  |
| iew\.pictureCard.fileUploadNotSupported.part1      | UWAGA! Przeglądarka, której używasz, nie obsługuje dodawania własnych obrazów.                               |
| iew\.pictureCard.fileUploadNotSupported.part2      | Prosimy o korzystanie z najnowszej wersji przeglądarki                                                       |
| iew\.pictureCard.rotateRight                       | Obrót w kierunku zgodnym z ruchem wskazówek zegara                                                           |
| iew\.pictureCard.rotateLeft                        | Obrót w kierunku przeciwnym do ruchu wskazówek zegara                                                        |
| iew\.pictureCard.enlarge                           | Powiększenie obrazka                                                                                         |
| iew\.pictureCard.minimize                          | Zmniejszenie obrazka                                                                                         |
| iew\.pictureCard.canvasReadMode                    | Obszar podglądu karty                                                                                        |
| iew\.pictureCard.canvasEditMode                    | Obszar edycji karty                                                                                          |
| iew\.pictureCard.selectFromGallery                 | Wybieram z galerii                                                                                           |
| iew\.pictureCard.addOwnImage                       | Dodaję własny obraz                                                                                          |
| iew\.pictureCard.noImagesInGallery                 | Ups…w tej galerii nie ma jeszcze obrazów. Wybierz inną galerię lub załaduj własny obraz.                     |
| iew\.imgcompress.header                            | Przekroczono maksymalny dozwolony rozmiar załącznika                                                         |
| iew\.imgcompress.message                           | Załączony plik jest zbyt duży. Czy chcesz poddać go procesowi automatycznej optymalizacji (podgląd poniżej)? |
| iew\.imgcompress.yes                               | Tak                                                                                                          |
| iew\.imgcompress.no                                | Nie                                                                                                          |

TanSMS

|                                       |                                                          |
| ------------------------------------- | -------------------------------------------------------- |
| iew\.tansms.sms.label                 | Hasło SMS                                                |
| iew\.tansms.sms.sendagain.label       | Wyślij ponownie                                          |
| iew\.tansms.sms.sendpassword.label    | Nowe hasło                                               |
| iew\.tansms.sms.format                | (nr %s z dnia %s)                                        |
| iew\.tansms.tan.label                 | Hasło jednorazowe                                        |
| iew\.tansms.tan.format                | (nr %s z listy nr %s)                                    |
| iew\.tansms.token.label               | TOKEN                                                    |
| iew\.tansms.token.format              | (aktualny token)                                         |
| iew\.tansms.sms.mask                  | \d\d\d\d\d\d\d\d                                         |
| iew\.tansms.password.sms.mask         | \\{\\"password\\":\\".{0,30}\\",\\"sms\\":\\"\d{6}\\"\\} |
| iew\.tansms.sms.visibleMask           | 99999999                                                 |
| iew\.tansms.sms.maskError             | Kod SMS składa się z 8 cyfr                              |
| iew\.tansms.tan.mask                  | \d\d\d\d\d                                               |
| iew\.tansms.tan.visibleMask           | 99999                                                    |
| iew\.tansms.tan.maskError             | Kod TAN składa się z 5 cyfr                              |
| iew\.tansms.token.mask                | \d\d\d\d\d                                               |
| iew\.tansms.token.visibleMask         | 99999                                                    |
| iew\.tansms.token.maskError           | TOKEN składa się z 5 cyfr                                |
| iew\.tansms.password.sms.label        | Hasło                                                    |
| TanSmsCodeValidator.invalidCode.sms   | Niepoprawny kod SMS                                      |
| TanSmsCodeValidator.invalidCode.tan   | Niepoprawny kod TAN                                      |
| TanSmsCodeValidator.invalidCode.token | Niepoprawny TOKEN                                        |
| iew\.tansms.sms.notlogged.label       | Wpisz kod SMS                                            |
| iew\.tansms.sms.notreceived.label     | SMS nie dotarł?                                          |
| iew\.tansms.sms.notlogged.mask        | \d\d\d\d                                                 |
| iew\.tansms.sms.notlogged.visibleMask | 9999                                                     |
| iew\.tansms.sms.notlogged.maskError   | Kod SMS składa się z 4 cyfr                              |

Panic Button (Fab)

|                                                   |                                                                                        |
| ------------------------------------------------- | -------------------------------------------------------------------------------------- |
| iew\.fab.error.try.again.desc                     | Spróbuj ponownie za chwilę                                                             |
| iew\.fab.error.could.not.order.conversation.title | Nie udało się zamówić rozmowy                                                          |
| iew\.fab.thank.you.title                          | Wkrótce do Ciebie oddzwonimy                                                           |
| iew\.fab.thank.you.desc                           | undefined                                                                              |
| iew\.fab.thank.you.already.ordered.title          | Rozmowa została już zamówiona                                                          |
| iew\.fab.thank.you.already.ordered.alt.title      | Wkrótce do Ciebie oddzwonimy                                                           |
| iew\.fab.need.help                                | Potrzebujesz pomocy?                                                                   |
| iew\.fab.well.call.up                             | undefined                                                                              |
| iew\.fab.phone.number                             | Numer telefonu                                                                         |
| iew\.fab.order.call                               | Zamów kontakt                                                                          |
| iew\.fab.statement.link.text                      | Zapoznaj się z pełną informacją o przetwarzaniu danych osobowych.                      |
| iew\.fab.incorrect.number                         | Niepoprawny numer telefonu                                                             |
| iew\.fab.teaser.title                             | Potrzebujesz pomocy?                                                                   |
| iew\.fab.teaser.description                       | Nasz konsultant pomoże Ci dokończyć Twój wniosek. Zamów kontakt, oddzwonimy bezpłatnie |

Komponent NPS

|                                               |                      |
| --------------------------------------------- | -------------------- |
| iew\.nps.very.bad.score.text                  | Bardzo źle           |
| iew\.nps.very.good.score.text                 | Świetnie!            |
| iew\.nps.other.score.text                     | undefined            |
| iew\.nps.score.text.1                         | Bardzo źle           |
| iew\.nps.score.text.2                         | Źle                  |
| iew\.nps.score.text.3                         | Średnio              |
| iew\.nps.score.text.4                         | Dobrze               |
| iew\.nps.score.text.5                         | Świetnie!            |
| iew\.nps.score.thank.you.page.text.header.bad | Dziękujemy za ocenę! |
| iew\.nps.score.thank.you.page.header.good     | Dziękujemy!          |
| iew\.nps.score.thank.you.page.text.good       | Twoja ocena to       |
| iew\.nps.additional.question.rate.text        | Twoja ocena to       |

Captcha

|                                                        |                                       |
| ------------------------------------------------------ | ------------------------------------- |
| iew\.validation.captcha.verifyError                    | Błąd weryfikacji CAPTCHA              |
| iew\.validation.captcha.requiredError                  | Pole wymagane                         |
| iew\.validation.captcha.internal.noWidgetForLocalValue | Wystąpił wewnętrzny problem walidacji |
| iew\.validation.captcha.internal.sessiontimeout        | Wystąpił wewnętrzny problem walidacji |

Załączniki - UploadFile

|                                                        |                                                                                                                                      |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| iew\.upload.description.placeholder                    | Opis załącznika                                                                                                                      |
| iew\.gwtupload.total\_size\_limit                      | Nie można załączyć pliku, przekroczono dozwolony maksymalny rozmiar załączonych plików {1} KB                                        |
| iew\.gwtupload.empty\_file                             | Załączony plik jest pusty                                                                                                            |
| iew\.uploader.camera.add.photo                         | Dodaj zdjęcie                                                                                                                        |
| iew\.uploader.camera.take.photo                        | Zrób zdjęcie                                                                                                                         |
| iew\.uploader.camera.button                            | Zrób zdjęcie                                                                                                                         |
| iew\.uploader.camera.filename                          | Zdjęcie z kamery                                                                                                                     |
| iew\.uploader.camera.ok                                | Ok                                                                                                                                   |
| iew\.uploader.camera.take.photo.again                  | Popraw zdjęcie                                                                                                                       |
| iew\.uploader.camera.popup.title                       | Zrób zdjęcie                                                                                                                         |
| iew\.uploader.camera.not.access.to.camera.error        | Nie udało się uzyskać dostępu do obrazu z kamery. Możliwe, że dostęp blokowany jest przez przeglądarkę.                              |
| iew\.gwtupload.uploaderActiveUpload                    | Proces wgrywanie właśnie trwa, spróbuj później.                                                                                      |
| iew\.gwtupload.uploaderAlreadyDone                     | Ten plik został już wczytany                                                                                                         |
| iew\.gwtupload.uploaderBlobstoreError                  | Błąd wczytywania pliku                                                                                                               |
| iew\.gwtupload.uploaderInvalidExtension                | Nieprawidłowe rozszerzenie pliku, dozwolone są następujące rozszerzenia:                                                             |
| iew\.gwtupload.uploaderSend                            | Wysyłanie                                                                                                                            |
| iew\.gwtupload.uploaderServerError                     | Błąd odpowiedzi serwera.                                                                                                             |
| iew\.gwtupload.uploaderAntivirusValidationServiceError | Wystąpił błąd podczas skanowania antywirusowego pliku.                                                                               |
| iew\.gwtupload.uploaderServerValidationContentError    | Niepoprawny format pliku.                                                                                                            |
| iew\.gwtupload.uploaderServerValidationAntivirusError  | Plik jest zawirusowany.                                                                                                              |
| iew\.gwtupload.uploaderServerUnavailable               | Błąd komunikacji z serwerem                                                                                                          |
| iew\.gwtupload.uploaderTimeout                         | Przekroczono czas wysyłania pliku                                                                                                    |
| iew\.gwtupload.uploadCancel                            | Usuń                                                                                                                                 |
| iew\.gwtupload.uploadStatusCanceled                    | Anulowany                                                                                                                            |
| iew\.gwtupload.uploadStatusCanceling                   | Anulowanie ...                                                                                                                       |
| iew\.gwtupload.uploadStatusDeleted                     | Usunięty                                                                                                                             |
| iew\.gwtupload.uploadStatusError                       | Błąd                                                                                                                                 |
| iew\.gwtupload.uploadStatusInProgress                  | Wysyłanie                                                                                                                            |
| iew\.gwtupload.uploadStatusQueued                      | Trwa ładowanie pliku                                                                                                                 |
| iew\.gwtupload.uploadStatusSubmitting                  | Wysyłanie pliku ...                                                                                                                  |
| iew\.gwtupload.uploadStatusSuccess                     | Gotowe                                                                                                                               |
| iew\.gwtupload.server\_invalid\_response               | Wgrywanie pliku zostało przerwane z powodu błędnej odpowiedzi z serwera                                                              |
| iew\.gwtupload.server\_error                           | Wgrywanie pliku zostało przerwane z powodu błędu na serwerze. Treść komunikatu błędu: {0}                                            |
| iew\.gwtupload.size\_limit                             | Nie można załączyć pliku, dozwolony rozmiar {1} KB został przekroczony                                                               |
| iew\.gwtupload.busy                                    | Żądanie zostało odrzucone ponieważ serwer aktualnie obsługuje inne żądania                                                           |
| iew\.gwtupload.no\_file                                | Wysyłanie pliku {0} zakończyło się niepowodzeniem. Proszę sprawdzić czy plik istnieje oraz czy użytkownik ma odpowiednie uprawnienia |
| iew\.gwtupload.no\_data                                | Błąd, przeglądarka nie wysłała żadnych danych. Proszę spróbować ponownie                                                             |
| iew\.gwtupload.already\_uploaded                       | Plik o tej samej nazwie został już dodany wcześniej. Proszę zmienić nazwę pliku i spróbować ponownie                                 |
| iew\.gwtupload.invalid\_filename                       | Dodawany plik posiada nieprawidłową nazwę. Proszę zmienić nazwę pliku i spróbować ponownie                                           |
| iew\.gwtupload.label\_extensions\_maxsize              | Dopuszczalne formaty załączników: {0} (max. {1})                                                                                     |
| iew\.gwtupload.uploaderInvalidExtensionWithList        | Nieprawidłowe rozszerzenie pliku, dozwolone są następujące rozszerzenia: {0}                                                         |
| iew\.attachments.show                                  | Zobacz PDF                                                                                                                           |
| iew\.gwtupload.no\_size                                | Nie można załączyć pliku, plik jest pusty                                                                                            |

Komponent wielokrotnego wyboru - MultiChoice

|                                              |                  |
| -------------------------------------------- | ---------------- |
| iew\.multiChoice.chips.selectAllBtnLabel     | Zaznacz wszystko |
| iew\.multiChoice.chips.unselectAllBtnLabel   | Odznacz wszystko |
| iew\.multiChoice.select                      | Wybierz          |
| iew\.multiChoice.selected                    | Wybrano          |
| iew\.multiChoice.all                         | Wszystkie        |
| iew\.multiChoice.dropdown.search             | Szukaj           |
| iew\.multiChoice.summary.deleted.items.label | Usunięto         |

Oświadczenia - Statements

|                                                           |                                                                                                          |
| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| iew\.statements.item.edit                                 | Edytuj dane                                                                                              |
| iew\.statements.fold                                      | Zwiń treść oświadczeń                                                                                    |
| iew\.statements.unfold                                    | Rozwiń treść oświadczeń                                                                                  |
| iew\.statements.item.fold                                 | Zwiń                                                                                                     |
| iew\.statements.item.unfold                               | Rozwiń                                                                                                   |
| iew\.statements.item.requiredNotSelected                  | Pole wymagane                                                                                            |
| iew\.statement.acceptSomeText                             | Akceptuję wybrane oświadczenia                                                                           |
| iew\.statementPopup.title                                 | Oświadczenia                                                                                             |
| iew\.statementPopup.closeLabel                            | Zapisz i zamknij                                                                                         |
| iew\.statementPopup.label.acceptedAll.prefix              | Akceptuję wszystkie                                                                                      |
| iew\.statementPopup.label.acceptedAll.link                | oświadczenia                                                                                             |
| iew\.statementPopup.label.acceptedAll.suffix              | .                                                                                                        |
| iew\.statementPopup.label.acceptedSome.prefix             | Akceptuję wybrane                                                                                        |
| iew\.statementPopup.label.acceptedSome.link               | oświadczenia                                                                                             |
| iew\.statementPopup.label.acceptedSome.suffix             | .                                                                                                        |
| iew\.statementPopup.item.yes                              | Tak                                                                                                      |
| iew\.statementPopup.item.no                               | Nie                                                                                                      |
| iew\.statementPopup.button.label                          | Pokaż oświadczenia                                                                                       |
| iew\.statementPopup.error.someUnknown                     | Nie dokonałeś wyboru przy wszystkich oświadczeniach, uzupełnij wymagane informacje w sekcji oświadczenia |
| iew\.statementPopup.error.notAllRequiredSelectedWithCount | Nie wyraziłeś zgody na wymagane oświadczenia.                                                            |
| iew\.statementPopup.error.oneUnknown                      | Nie dokonałeś wyboru                                                                                     |
| iew\.statementPopup.error.notOneRequiredSelected          | Pole wymagane                                                                                            |
| iew\.statement.showMore                                   | Pełna treść                                                                                              |
| iew\.statement.hideMore                                   | Zwiń                                                                                                     |
| iew\.statement.showMore                                   | Pełna treść oświadczenia                                                                                 |
| iew\.statement.hideMore                                   | Zwiń                                                                                                     |
| iew\.statements.coapplicant.label.acceptAll               | Zapoznaliśmy się z poniższymi oświadczeniami i akceptujemy je wszystkie.                                 |

Popup

|                        |        |
| ---------------------- | ------ |
| iew\.popup.saveLabel   | Zapisz |
| iew\.popup.cancelLabel | Anuluj |

Treść formatowana - TextContent

|                         |        |
| ----------------------- | ------ |
| iew\.textContent.fold   | Zwiń   |
| iew\.textContent.unfold | Rozwiń |

Pole tekstowe - Textfield

|                                    |                |
| ---------------------------------- | -------------- |
| iew\.validator.required.text.field | Uzupełnij pole |

Pole wyboru wartości z listy - Combobox

|                                  |                   |
| -------------------------------- | ----------------- |
| iew\.navigation.combochoose      | Wybierz...        |
| iew\.navigation.combo.noResult   | Brak dopasowań... |
| iew\.validator.required.combobox | Wybierz opcję     |

Checkbox

|                                  |               |
| -------------------------------- | ------------- |
| iew\.validator.required.checkbox | Zaznacz opcję |

Slider

|                                            |                        |
| ------------------------------------------ | ---------------------- |
| iew\.slider.legend.min.prefix              | min.                   |
| iew\.slider.legend.max.prefix              | maks.                  |
| iew\.slider.tiles.out.of.range.max.message | Maksymalna wartość to: |
| iew\.slider.tiles.out.of.range.min.message | Minimalna wartość to:  |

Sekcja powtarzalna - RepeatableSection

|                                                              |                                                   |
| ------------------------------------------------------------ | ------------------------------------------------- |
| iew\.navigation.repeatablesection.add.error                  | Wystąpił błąd przy dodawaniu sekcji powtarzalnej. |
| iew\.navigation.repeatablesection.remove.error               | Wystąpił błąd przy usuwaniu sekcji powtarzalnej.  |
| iew\.navigation.repeatablesection.element.error              | Sekcja zawiera niepoprawnie wypełnione pola       |
| iew\.navigation.repeatablesection.delayedRemoveMessageFormat | Usunięto                                          |
| iew\.navigation.repeatablesection.cancelMessageFormat        | Cofnij                                            |

Data - DatePicker

|                                               |                                                 |
| --------------------------------------------- | ----------------------------------------------- |
| iew\.validator.date.disabled                  | Wybrana data jest niedostępna                   |
| iew\.validator.date.ranges                    | Wybrana data jest niedostępna                   |
| iew\.datepicker.confirm                       | OK                                              |
| iew\.datepicker.cancel                        | Anuluj                                          |
| iew\.validator.date.range                     | Data końcowa musi być późniejsza niż początkowa |
| iew\.navigation.noDataAvailable               | Brak danych!                                    |
| iew\.datePicker.dateFormat                    | dd-MM-yyyy                                      |
| iew\.datePicker.dateTimeFormat                | dd-MM-yyyy HH:mm                                |
| iew\.datepicker.month.standalone.january      | Styczeń                                         |
| iew\.datepicker.month.standalone.february     | Luty                                            |
| iew\.datepicker.month.standalone.march        | Marzec                                          |
| iew\.datepicker.month.standalone.april        | Kwiecień                                        |
| iew\.datepicker.month.standalone.may          | Maj                                             |
| iew\.datepicker.month.standalone.june         | Czerwiec                                        |
| iew\.datepicker.month.standalone.july         | Lipiec                                          |
| iew\.datepicker.month.standalone.august       | Sierpień                                        |
| iew\.datepicker.month.standalone.september    | Wrzesień                                        |
| iew\.datepicker.month.standalone.october      | Październik                                     |
| iew\.datepicker.month.standalone.november     | Listopad                                        |
| iew\.datepicker.month.standalone.december     | Grudzień                                        |
| iew\.datepicker.month.january                 | Stycznia                                        |
| iew\.datepicker.month.february                | Lutego                                          |
| iew\.datepicker.month.march                   | Marca                                           |
| iew\.datepicker.month.april                   | Kwietnia                                        |
| iew\.datepicker.month.may                     | Maja                                            |
| iew\.datepicker.month.june                    | Czerwca                                         |
| iew\.datepicker.month.july                    | Lipca                                           |
| iew\.datepicker.month.august                  | Sierpnia                                        |
| iew\.datepicker.month.september               | Września                                        |
| iew\.datepicker.month.october                 | Października                                    |
| iew\.datepicker.month.november                | Listopada                                       |
| iew\.datepicker.month.december                | Grudnia                                         |
| iew\.datepicker.month.short.january           | Sty                                             |
| iew\.datepicker.month.short.february          | Lut                                             |
| iew\.datepicker.month.short.march             | Mar                                             |
| iew\.datepicker.month.short.april             | Kwi                                             |
| iew\.datepicker.month.short.may               | Maj                                             |
| iew\.datepicker.month.short.june              | Cze                                             |
| iew\.datepicker.month.short.july              | Lip                                             |
| iew\.datepicker.month.short.august            | Sie                                             |
| iew\.datepicker.month.short.september         | Wrz                                             |
| iew\.datepicker.month.short.october           | Paź                                             |
| iew\.datepicker.month.short.november          | Lis                                             |
| iew\.datepicker.month.short.december          | Gru                                             |
| iew\.datepicker.weekdays.narrow\.monday       | PN                                              |
| iew\.datepicker.weekdays.narrow\.tuesday      | WT                                              |
| iew\.datepicker.weekdays.narrow\.wednesday    | ŚR                                              |
| iew\.datepicker.weekdays.narrow\.thursday     | CZW                                             |
| iew\.datepicker.weekdays.narrow\.friday       | PT                                              |
| iew\.datepicker.weekdays.narrow\.saturday     | SB                                              |
| iew\.datepicker.weekdays.narrow\.sunday       | ND                                              |
| iew\.datepicker.weekdays.monday               | Poniedziałek                                    |
| iew\.datepicker.weekdays.tuesday              | Wtorek                                          |
| iew\.datepicker.weekdays.wednesday            | Środa                                           |
| iew\.datepicker.weekdays.thursday             | Czwartek                                        |
| iew\.datepicker.weekdays.friday               | Piątek                                          |
| iew\.datepicker.weekdays.saturday             | Sobota                                          |
| iew\.datepicker.weekdays.sunday               | Niedziela                                       |
| iew\.datepicker.weekdays.short.monday         | Pn                                              |
| iew\.datepicker.weekdays.short.tuesday        | Wt                                              |
| iew\.datepicker.weekdays.short.wednesday      | Śr                                              |
| iew\.datepicker.weekdays.short.thursday       | Cz                                              |
| iew\.datepicker.weekdays.short.friday         | Pt                                              |
| iew\.datepicker.weekdays.short.saturday       | Sb                                              |
| iew\.datepicker.weekdays.short.sunday         | Nd                                              |
| iew\.datepicker.mobile.setDateButtonLabel     | Ustaw datę                                      |
| iew\.datepicker.mobile.setDurationButtonLabel | Ustaw okres                                     |
| iew\.datepicker.mobile.calTodayButtonLabel    | Dzisiaj                                         |
| iew\.datepicker.mobile.titleDateDialogLabel   | Wybierz datę                                    |
| iew\.datepicker.mobile.titleTimeDialogLabel   | Wybierz czas                                    |
| iew\.datepicker.mobile.tooltip                | Otwórz wybór daty                               |
| iew\.datepicker.mobile.nextMonth              | Następny miesiąc                                |
| iew\.datepicker.mobile.prevMonth              | Poprzedni miesiąc                               |
| iew\.datepicker.mobile.clearButton            | Wyczyść                                         |
| iew\.datepicker.mobile.calDateListLabel       | Inne daty                                       |
| iew\.datepicker.mobile.durationLabel.days     | Dni                                             |
| iew\.datepicker.mobile.durationLabel.hours    | Godziny                                         |
| iew\.datepicker.mobile.durationLabel.minutes  | Minuty                                          |
| iew\.datepicker.mobile.durationLabel.seconds  | Sekundy                                         |
| iew\.datepicker.mobile.durationDays.day       | Dzień                                           |
| iew\.datepicker.mobile.durationDays.days      | Dni                                             |
| iew\.datepicker.valueChanged                  | Data została zmieniona.                         |

Obszar tekstu - TextArea

|                                        |                                                                             |
| -------------------------------------- | --------------------------------------------------------------------------- |
| iew\.validator.textarea.length.tooLong | Osiągnięto maksymalny rozmiar pola i jego zawartość została obcięta         |
| iew\.validator.textarea.tooManyRows    | Osiągnięto maksymalny limit wierszy w polu i jego zawartość została obcięta |

Radio grupa produktów - GesProductRadioGroup

|                                 |                      |
| ------------------------------- | -------------------- |
| iew\.productRadioGroup.toggle   | Informacje dodatkowe |
| iew\.productRadioGroup.select   | Wybierz              |
| iew\.productRadioGroup.selected | Wybrana oferta       |

Numer telefonu - PhoneInput

|                                                  |                              |
| ------------------------------------------------ | ---------------------------- |
| iew\.phone.input.default.prefix.label            | Prefiks:                     |
| iew\.phone.input.default.mask.validation.error   | Nieprawidłowy numer telefonu |
| iew\.phone.input.default.prefix.validation.error | Prefiks: błędny              |

Nowa Tabela - InlineTable

|                                             |                                                                           |
| ------------------------------------------- | ------------------------------------------------------------------------- |
| iew\.inlineTable.summary.deleted.rows.label | Elementy usunięte                                                         |
| iew\.inlinetable.row\.duplicate             | Wiersz z wprowadzonymi danymi już istnieje. Zmień dane lub usuń duplikat. |
| iew\.inlinetable.addRow\.label              | Dodaj nowy wiersz                                                         |
| iew\.inlinetable.search.label               | Wyszukaj                                                                  |
| iew\.inlinetable.expand.label               | Rozwiń tabelę                                                             |
| iew\.inlinetable.collapse.label             | Zwiń tabelę                                                               |
| iew\.inlineTable.search.placeholder         | Wpisz frazę                                                               |

</details>


# Statystyki GTM

## Wprowadzenie

Funkcjonalność Google Tag Manager dostępna jest dla:

* komponentów,
* zmiennych sesyjnych.

Każdy wspierany komponent dostępny w Eximee Designer posiada możliwość skonfigurowania funkcjonalności Google Tag Manager. Funkcjonalność w pierwszej kolejności należy uruchomić na wniosku, a następnie na poszczególnych komponentach zgodnie z poniższymi sekcjami.

## Konfiguracja GTM dla komponentu

Konfiguracja tagu GTM polega na zaznaczeniu opcji **Aktywowanie GTM** w sekcji **Pozostałe** właściwości danego komponentu (domyślnie właściwość jest odznaczona). Dostępna jest również możliwość zmiany domyślnej nazwy taga na własną nazwę w polu Tag GTM. Gdy pole Tag GTM jest puste, to nazwa taga jest taka sama jak w polu mid. Konfiguracja dla wszystkich komponentów jest identyczna.

## Konfiguracja GTM dla zmiennych sesyjnych

Konfiguracja GTM dla zmiennych sesyjnych polega na ustawieniu zmiennej sesyjnej jako **Exposed** oraz włączeniu opcji **Gtm** (aktywowanej po kliknięciu **Exposed**). Możliwa jest zmiana nazwy tagu w polu Tag GTM. Domyślną nazwą taga jest mid zmiennej sesyjnej.

## Komponenty wspierające Google Tag Manager

* Trigger (Button)
* Checkbox
* Sekcja z checkboxem (CheckboxSection)
* Pole wyboru wartości z listy (Combobox)
* Data (DatePicker)
* ExternalSection
* Plus minus
* Radio grupa (RadioGroup)
* Oświadczenia na warstwie (StatementPopup)
* Step slider
* Obszar tekstu (TextArea)
* Pole tekstowe (TextField)
* Slider

## Informacje integracji z GTM

Zmiany na wniosku zostają one wysłane do Google Tag Managera i tam za pomocą warstwy danych GTM (webformsDataLayer) można je wykorzystać do tworzenia reguł i tagów, które następnie mogą zostać wykorzystane do śledzenia zachowania użytkowników na wniosku (na przykład za pomocą takich platform jak GA4).

W wyniku zmiany wartości komponentu, któremu zezwolono na wysyłanie taga do Google Tag Managera, w warstwie danych GTM (webformsDataLayer) pojawiają się dwa wpisy:

* **event** - którego wartość odpowiada polu gtmTagName komponentu wniosku. Jeśli wartość tego pola jest pusta, a właściwość pushTagsToGtm jest zaznaczona wtedy event przyjmuje wartość pola mid komponentu,
* **eventValue** - którego wartość odpowiada nowej wartości komponentu.

W wyniku wejścia na wniosek w warstwie danych GTM (webformsDataLayer) pojawiają się wpisy:

* **formName** - nazwa wniosku.


# Zapis tymczasowy

W **Eximee Designer** dostępna jest funkcjonalność parkowania oraz odparkowywania wniosków. W sekcji **Zapis tymczasowy** znajdują się podsekcje dotyczące różnych wariantów zapisu/parkowania wniosku.


# Autozapis i Pola kontaktowe

W sekcji **Autozapis** można włączyć automatyczne parkowanie wniosku np. w momencie wygaśnięcia sesji WEB. Opcja autozapisu może być włączana niezależnie dla klienta zalogowanego oraz niezalogowanego. Dodatkowo można sprecyzować warunek automatycznego parkowania wniosku dla każdego z kanałów.

{% hint style="warning" %}
**Uwaga!**\
Automatycznie parkowanie wniosków dla klienta niezalogowanego działa tylko jeśli warunek automatycznego parkowania jest spełniony oraz w sekcji **Pola kontaktowe** został wskazany numer kontaktowy.
{% endhint %}

<figure><img src="/files/ktO6BXkENX4mAslm55Yj" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Sekcja autozapisu z warunkiem dla zalogowanego użytkownika</em></p></figcaption></figure>

<figure><img src="/files/paYphTF0wAnUjna05we5" alt=""><figcaption><p><em><strong>Ilustracja 2.</strong> Sekcja autozapisu z warunkiem dla niezalogowanego użytkownika wraz z uzupełnionymi polami kontaktowymi</em></p></figcaption></figure>

### Parkowanie współbieżne (przemienne doradcy i klienta)

{% hint style="info" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

Sekcja **Parkowanie przemienne doradcy i klienta** zawiera ustawienia dla “scenariusza współbieżnego”, w którym wniosek mogą wypełniać dwie osoby. Opcja przekazania polega na tym samym, co parkowanie dla innej osoby. W sekcji możemy wskazać artefakt z powiadomieniami email oraz oświadczeniami dla klienta i doradcy.


# Mechanizm blokowania statusów

{% hint style="info" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

Podczas parkowania i odparkowywania mogą zadziałać reguły FormStore'a, które będą chciały zmienić status wniosku. Mogłyby istnieć wtedy 2 wnioski o tym samym numerze, ale innych statusach (np. PARKED i ABANDON). Aby temu zapobiec, powstał **mechanizm blokowania statusów**.

## Blokowanie zmiany statusów

Blokowanie zmiany statusów odbywa się przy odparkowywaniu wniosku. W szczególnych przypadkach również przy parkowaniu. Ustawiana jest wtedy wartość **flagi blokującej (unparked) na "true" (zablokowano)**. Informuje ona o tym, że jakiekolwiek zmiany statusu **nie mają się zadziać**. Wniosek jest wtedy przetrzymywany w aktualnym stanie.

## Odblokowywanie zmiany statusów

Odblokowywanie zmiany statusów odbywa się przy parkowaniu (również automatycznym) wniosku. W szczególnych przypadkach dzieje się tak tylko przy jego "przekazaniu". **Flaga blokująca (unparked) jest ustawiana na "false" (odblokowano)**. Informuje ona o tym, że zmiany statusów są aktywne.

## Automatyczne odblokowanie zmian statusów

Automatyczne odblokowanie zmian statusów jest potrzebne w przypadku zawieszenia się wniosku (np. poprzez awarię serwera). Sprawdzane jest wtedy, czy ostatnia modyfikacja wniosku była co najmniej 1 dzień wcześniej. Jeśli tak, jest to powód do odblokowania zmian statusów. Dzieje się to w dwóch przypadkach.

### Aktywacja reguły odblokowującej

Reguła przechodzi po wszystkich wnioskach z zablokowanym statusem. Jeśli spełnia warunek odblokowania - wniosek ten ma odblokowaną zmianę statusów.

### Aktywacja reguł zmieniających stan

Reguły zmieniające stan przechodzą tak, jak dotychczas, przez wszystkie wnioski, które spełniają ich warunki. W momencie kiedy wniosek ma zablokowany status, ale nie spełnia wymogów automatycznego odblokowania - status pozostaje bez zmian.

Jeśli wniosek ma zablokowany status, ale spełnia warunek automatycznego odblokowania albo wniosek ma odblokowany status (standardowe zachowanie) - wniosek zostaje odblokowany na zmianę statusów, a następnie zachodzą zmiany, które zostały ustalone w regule.

## Flaga blokująca

Flaga blokująca to zmienna "unparked" w metadanych wniosku. Jej stan można zobaczyć w FormStore w **JSON (Ilustracja 1)** bądź w **XML (Ilustracja 2)**.

<figure><img src="/files/51SWYzxtsegq8DTh2kLT" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> FormStore podgląd wniosku - JSON</em></p></figcaption></figure>

<figure><img src="/files/Ntyrablbuepjx4ZvPoqY" alt=""><figcaption><p><em><strong>Ilustracja 2.</strong> FormStore podgląd wniosku - XML</em></p></figcaption></figure>


# Parkowanie i odparkowanie wnioskow

## Wprowadzenie

Parkowanie wniosku polega na zapisaniu jego aktualnego stanu (wszystkich wypełnionych pól wniosku) z wyłączeniem dodanych załączników, w celu późniejszego powrotu do tego stanu podczas odparkowania wniosku.

{% hint style="warning" %}
**Uwaga!**\
Aby po odparkowaniu wniosek działał poprawnie należy uzupełnić listę pól, które nie mogą być odparkowywane.

W szczególności są to pola:

* związane z aktualną sesją użytkownika (np. zmienne sesyjne przechowujące **sessionKey** oraz wszystkie zmienne wynikające z mapowania parametrów wejściowych komponentów złożonych itp.),
* związane z danymi, których nie chcemy przechowywać do następnej sesji, np. dane tokenu sms, który zmieni się przy kolejnym uruchomieniu wniosku,
* związane z danymi aktywnymi czasowo, np. promocje,
* związane z powyższymi, ale wynikające z mapowania parametrów wejściowych komponentów złożonych itp.
  {% endhint %}

## Ustawienia

W tej sekcji możemy skonfigurować możliwość zapisu tymczasowego przez użytkownika.

<figure><img src="/files/F9jLZjVcx79AaKGXf7v0" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Zapis tymczasowy w zakładce Właściwości w Eximee Designer</em></p></figcaption></figure>

<figure><img src="/files/aFQzV5wp0jEvqXtity6R" alt=""><figcaption><p><em><strong>Ilustracja 2.</strong> Włączenie opcji parkowania wniosku</em></p></figcaption></figure>

Dla tak skonfigurowanego, a następnie opublikowanego szablonu, podczas wypełniania bazującego na nim wniosku na ekranie pojawia sekcja odpowiedzialna za parkowanie z przyciskiem.

## Odtwarzanie wartości (biała/czarna lista pól)

W sekcji **Odtwarzanie wartości** możemy określić:

* które pola nie powinny zostać odparkowane przy odparkowywaniu wniosku przy użyciu **Blacklist**,
* które pola powinny zostać odparkowane przy odparkowywaniu wniosku przy użyciu **Whitelist** (pusta lista oznacza, że nic nie zostanie odparkowane).

Nie można jednocześnie używać białej listy jak i czarnej. W celu wybrania jednej listy (Whitelist lub Blacklist) używamy listy znajdującej się w zakładce **Właściwości** w sekcji **Zapis tymczasowy** i podsekcji **Odtwarzanie wartości**:

<figure><img src="/files/RXNfv4zpKBPqYz5Vwcuc" alt=""><figcaption><p><em><strong>Ilustracja 3.</strong> Przykład wybrania czarnej listy przy odparkowaniu</em></p></figcaption></figure>

W celu zdefiniowania pól należy je dodać do listy.

### Przykłady zastosowania

**Przykład 1** - promocja, która powinna wygasnąć po odparkowaniu:

* mamy promocję "xmas",
* dla wniosków uruchomionych z parametrem promotion=xmas mamy lepsze warunki,
* promocja kończy się w piątek,
* w piątek publikujemy szablon wniosku, który już nie obsługuje promocji "xmas",
* w szablonie wpisujemy "promotion" (i wszystkie zmienne do których przepisywana jest wartość zmiennej promotion np. poprzez Parametry wejściowe komponentów złożonych) na czarną listę,
* wniosek zaparkowany w czwartek i odparkowany w sobotę **nie będzie** zawierał pola promotion=xmas (chyba, że została ona ponownie przekazana jako parametr wejścia na wniosek).

**Przykład 2** - promocja, którą chcemy odparkowywać, ale z możliwością nadpisania odpowiednim parametrem:

* dla promocji "xmas" z powyższego przykładu chcemy zmienić typ promocji na promotion=xxx,
* w przypadku braku podania parametru chcemy użyć promocji z jaką klient wszedł na wniosek za pierwszym razem,
* w szablonie wpisujemy wszystkie zmienne do których przepisywana jest wartość zmiennej promotion np. poprzez Parametry wejściowe komponentów złożonych na czarną listę, jednak zmiennej promotion nie dodajemy do czarnej listy,
* klient po odparkowaniu z parametrem promotion=xxx **będzie** miał aktywną promocję xxx,
* klient po odparkowaniu bez parametru promotion, **będzie** miał aktywną tę samą promocję z jaką wniosek został zaparkowany.

## Parkowanie wniosku

Parkowanie wniosku polega na zapisaniu jego aktualnego stanu (wszystkich wypełnionych pól wniosku) z wyłączeniem dodanych załączników, w celu późniejszego powrotu do tego stanu.

### Klient niezalogowany

Proces parkowania rozpoczynamy przez naciśnięcie przycisku "**Zapisz**", w wyniku którego pojawia się okno dialogowe. W oknie tym **System** prosi nas o wprowadzenie danych autentykacyjnych, na podstawie których dokonana zostanie identyfikacja użytkownika w procesie odparkowywania danego wniosku.

<figure><img src="/files/nvAyJk0FRYviP1KqryxN" alt=""><figcaption><p><em><strong>Ilustracja 4.</strong> Okno wprowadzania danych autentykacyjnych</em></p></figcaption></figure>

Po zatwierdzeniu danych przyciskiem "**Zapisz**" wniosek zostanie zapisany wraz z wprowadzonymi danymi identyfikacyjnymi oraz unikalnym, nadanym mu numerem, w repozytorium. Potwierdza to wyświetlając następujące okno dialogowe:

<figure><img src="/files/CbIHNbSSpUQ66xDn3lSY" alt=""><figcaption><p><em><strong>Ilustracja 5.</strong> Okno potwierdzenia zaparkowania wniosku</em></p></figcaption></figure>

W ten sposób zaparkowany wniosek jest gotowy do odparkowania.

{% hint style="info" %}
**Uwaga!**\
Wpisywane hasła są sprawdzane pod kątem bezpieczeństwa według zaleceń agencji National Institute of Standards and Technology. Konfiguracja domyślna będzie zawierała taką politykę, aby hasło składało się z:

* jednej dużej litery,
* jednej małej,
* cyfry oraz znaku specjalnego,
* musi mieć co najmniej 8 znaków.

Konfiguracja jest niezależna dla każdego klienta i można ją zmienić w ***webforms.xml*** pod kluczem: **`<passwordPolicy>`** (jest to regex). Dodatkowo będzie możliwa modyfikacja komunikatu zwracanego w przypadku wpisania hasła niespełniającego wymogów bezpieczeństwa - tym razem w ***navigation.localization*** dla każdego klienta. Klucz ***iew\.form.password.policyInfo*** odpowiada komunikatowi, jakie wymogi powinno spełniać hasło, a ***iew\.form.password.policyViolation*** to klucz od komunikatu wyświetlanego w przypadku próby wpisania hasła niespełniającego wymogów bezpieczeństwa.
{% endhint %}

### Klient zalogowany

W przypadku klienta zalogowanego po naciśnięciu przycisku "**Zapisz**" wniosek zostanie zapisany w systemie bez konieczności podawania danych uwierzytelniających. Mechanizm wykorzystuje identyfikator klienta pobrany z sesji. Po pomyślnym zaparkowaniu zostanie wyświetlony komunikat potwierdzający zakończenie operacji.

Należy pamiętać, że użytkownik może mieć zaparkowaną tylko jedną instancję wniosku danego typu.

## Odparkowanie wniosku

Odparkowywanie wniosku to funkcjonalność umożliwiająca odczytanie wcześniej zaparkowanego wniosku (wraz ze wszystkimi polami wypełnionymi w momencie parkowania, ale z wyłączeniem załączników dodanych do parkowanego wniosku).

### Klient niezalogowany

Aby rozpocząć proces odparkowywania, należy przejść do strony, do której link otrzymujemy w oknie dialogowym potwierdzającym pomyślne zaparkowanie wniosku ***(Ilustracja 5)*** lub w mailu otrzymanym po zaparkowaniu (na adres wskazany podczas parkowania).

Po wyświetleniu w przeglądarce strony znajdującej się pod wskazanym linkiem, pokaże się okno dialogowe, w którym **System** zażąda potwierdzenia danych identyfikujących osobę, która dokonała parkowania wniosku:

<figure><img src="/files/9AEWXiTKgSrQ6qKeWzGI" alt=""><figcaption><p><em><strong>Ilustracja 6.</strong> Okno odparkowania wniosku</em></p></figcaption></figure>

Odparkowanie wniosku jest możliwe tylko po prawidłowym wprowadzeniu danych identyfikacyjnych (email oraz hasło) zapisanych w procesie parkowania. Po naciśnięciu przycisku "OK" zostaniemy przekierowani do strony wniosku ze stanem pól z momentu jego zaparkowania.

### Klient zalogowany

Odparkowywanie wcześniej zapisanego wniosku w przypadku klienta zalogowanego może się odbyć na dwa sposoby:

#### Sposób pierwszy

Wywołanie akcji ***load.html*** - żądanie **POST** na adres [*https://eximee-dmz:8080/webforms/wnioski/NAZWA\_WNIOSKU/load.html*](https://eximee-dmz:8080/webforms/wnioski/NAZWA_WNIOSKU/load.html)

gdzie: `NAZWA_WNIOSKU` - nazwa wniosku do odparkowania

Po wywołaniu akcji zostaniemy przekierowani do strony wniosku ze stanem pól z momentu jego zaparkowania.

#### Sposób drugi

{% hint style="info" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

Wywołanie akcji ***getFormTemplate*** - żądanie **POST** na adres [*https://eximee-dmz:8080/webforms/api/formService/getFormTemplate*](https://eximee-dmz:8080/webforms/api/formService/getFormTemplate)

Jeśli wniosek został wcześniej zaparkowany, akcja zwróci wniosek ze stanem pól z momentu jego zaparkowania.

### Serwisy uruchamiane przy odparkowaniu

Dla wniosku można zdefiniować serwisy, które zostaną wywołane w momencie odparkowania wniosku. Sposób ich dodawania opisany został w [**Serwisy przy wznowieniu**](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/zapis-tymczasowy/serwisy-przy-wznowieniu).

Serwisy wywoływane są przed **entry service** i mogą nadpisywać wartości znajdujące się na wniosku.

{% hint style="warning" %}
Jeżeli na wartość komponentów lub zmiennych sesyjnych wpływają inne komponenty, lub zmienne sesyjne zasilane za pomocą **UnparkEntryService** to komponenty te zachowają się jak podczas standardowego wejścia na wniosek, na przykład:
{% endhint %}

<figure><img src="/files/xeAxl64KwfJ1AqS24yKM" alt=""><figcaption><p><em><strong>Ilustracja 7.</strong> Przepływ danych</em></p></figcaption></figure>

W tym przypadku `TextField1` jest zasilany za pomocą **UnparkEntryService**. Wpływa on na wartość pola `TextField2` (poprzez **PageService**, np. *EchoService).* Ponieważ usługi **UnparkEntryService** wykonywane są przed usługami **EntryService** oraz na pole `TextField2` wpływa pole zasilane przez **UnparkEntryService** to ostatecznie wartości pola `TextField2` będzie odpowiadała wartości zmiennej sesyjnej **SessionVariable** zasilonej za pomocą **EntryService**.

### Powiadomienia

Powiadomienia wysyłane po zaparkowaniu wniosku realizowane są za pomocą mechanizmu notyfikacji opisanego tutaj: [**Autozapis i Pola kontaktowe**](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/zapis-tymczasowy/autozapis-i-pola-kontaktowe).

### Odparkowanie wniosku przez wejście na link z powiadomienia

Do powiadomień może być dołączany link do odparkowania wniosku.

Wejście na link wysłany w powiadomieniu pozwala na odparkowanie wniosków zaparkowanych przez użytkownika zalogowanego oraz wniosków zaparkowanych przez użytkownika niezalogowanego.

Jeżeli wniosek był zaparkowany przez **użytkownika zalogowanego**, po wejściu na link zawarty w powiadomieniu następuje przekierowanie na stronę logowania. Jeżeli klient się uwierzytelni, zostanie dalej przekierowany na przygotowany do dalszej edycji, ostatni zaparkowany przez niego wniosek danego typu.

Jeżeli wniosek był zaparkowany przez **użytkownika niezalogowanego**, po wejściu na link zawarty w powiadomieniu następuje przekierowanie na stronę weryfikacji hasła jednorazowego dostępu. Podczas wejścia na tę stronę, na numer telefonu zapisany we wniosku zostaje wysłany SMSem jednorazowy kod dostępu do wniosku. Aby uruchomić zaparkowany wniosek, użytkownik musi potwierdzić swoją tożsamość przez wpisanie otrzymanego hasła. Treść wiadomości SMS z jednorazowym kodem dostępu pochodzi z szablonu wiadomości email, podanego w konfiguracji aplikacji webforms, w pliku */etc/eximee/webforms.xml* na serwerze dmz. Poniżej przykład konfiguracji (należy podać nazwę i wersję szablonu wiadomości email z repozytorium):

```xml
<webforms>
...
...
...
...
    <server>
    ...
    ...
    ...
        <unparkOtp>
            <smsContentArtifact>otpSmsContentDefaultTemplate-*</smsContentArtifact>
            ...
            ...
        </unparkOtp>
    ...
    ...
    </server>
</webforms>
```

{% hint style="warning" %}
W treści szablonu email (sic! tak się nazywa typ artefaktu w repozytorium - szablony te służą również do definicji treści wiadomości SMS) podanego w konfiguracji jako szablon z treścią wiadomości SMS z jednorazowym kodem dostępu do zaparkowanego wniosku **musi** zawierać znacznik: **${SMS\_CODE}** - zostanie on zastąpiony wygenerowanym kodem dostępu do zaparkowanego wniosku.
{% endhint %}

### Warunkowe odparkowanie wniosku

{% hint style="info" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

Dla wniosku można zdefiniować warunek, który zostanie sprawdzony w momencie odparkowania wniosku. Gdy warunek zostanie spełniony, wniosek zostanie odparkowany i pokazany użytkownikowi. W przeciwnym wypadku tworzony jest nowy formularz.

<figure><img src="/files/KVMpGZUOWAHBy1E1lYqW" alt=""><figcaption><p><em><strong>Ilustracja 8.</strong> Sekcja Odparkowanie wniosku z warunkiem do spełnienia</em></p></figcaption></figure>

Informacje o tym jak definiować warunki znajdują się na stronie: [**Język wyrażeń definiowania warunków (warunki z getValue)**](/budowanie-aplikacji/logika-biznesowa/jezyk-wyrazen-definiowania-warunkow-warunki-z-getvalue).

Funkcjonalność warunkowego odparkowania wniosku rozszerza metodę `_getValue('componentId')_` języka wyrażeń o dwie nowe funkcjonalności:

* możliwość uzyskania dostępu do wartości komponentu po jego MID,
* możliwość przyjęcia argumentu z prefixem ***parked***. Prefix ten umożliwia uzyskanie dostępu do zaparkowanych wartości wniosku.

**Przykładowy warunek odparkowania na podstawie MID**

```javascript
getValue('parked:usernameFieldMid') == 'parkedValue'
```

**Przykładowy warunek odparkowania na podstawie ID**

```javascript
getValue('parked:GesTextField1') == 'parkedValue'
```

**Przykładowy warunek odparkowania z wykorzystaniem injectableFields**

```javascript
getValue('parked:nazwazmiennej') == getValue('injected:nazwazmiennej')
```

{% hint style="info" %}
**Uwaga!**\
Może wystąpić sytuacja, że kiedy odparkowujemy wniosek mogą pojawić się inne strony, które wcześniej nie były widoczne.

Powinniśmy wtedy wejść na pierwszą stronę, która wcześniej nie została odwiedzona.
{% endhint %}

{% hint style="info" %}
**Uwaga!**\
Podczas odparkowania uaktywnia się *mechanizm blokowania statusu wniosku*. Oznacza on tyle, że dopóki wniosek jest odparkowany, nie może on zmienić swojego statusu (np. na wniosek porzucony). Wnioski takie są odblokowywane przy parkowaniu (również automatycznym parkowaniu), zapisywaniu lub po 1 dniu od ostatniej modyfikacji (ochrona przed zawieszaniem się wniosków przez system).

Więcej na temat tego mechanizmu znajdziesz tutaj: [**Mechanizm blokowania statusów**](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/zapis-tymczasowy/mechanizm-blokowania-statusow)
{% endhint %}


# Serwisy przy wznowieniu

Usługi uruchamiane na odparkowanie wniosku mają za zadanie wywołać się w momencie kiedy wniosek zostanie odparkowany. Serwisy te definiuje się w sekcji **Serwisy przy wznowieniu**. Po dodaniu serwisu (przycisk **Dodaj serwis**) można zdefiniować warunek wywołania go (w polu **Dodaj warunek**) oraz parametry wejściowe i wyjściowe (po kliknięciu przycisku **Pokaż szczegóły**).

<figure><img src="/files/xEkY2Eu6yknyPwLikAK3" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Okno z dodanym serwisem oraz parametrami wyjściowymi</em></p></figcaption></figure>


# Zmienna sesyjna wasParked

Aby sprawdzić na wniosku, czy wniosek został uprzednio zapisany tymczasowo, do zmiennych sesyjnych dodajemy ***wasParked*** (ta zmienna ma ustawianą wartość automatycznie przez platformę, w momencie podejmowania wniosku):

<figure><img src="/files/9A6fGAk74nX7mVOu3kvR" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Zmienna wasParked w Eximee Designer</em></p></figcaption></figure>

## Mechanizm działania *wasParked*

Na wniosku dodana została następująca etykieta:

<figure><img src="/files/B0g9sUzXAmAzY0WmWsSt" alt=""><figcaption><p><em><strong>Ilustracja 2.</strong> Etykieta ze zmienną wasParked w Eximee Designer</em></p></figcaption></figure>

Na jej przykładzie można zobaczyć, jak działa wartość zmiennej *wasParked*.

Przy pierwszym wejściu na wniosek zmienna *wasParked* jest pusta:

<figure><img src="/files/p1UrUtFfpMsTLwcdoo3v" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/8c2z5YNaaYeRYImSVCUN" alt=""><figcaption><p><em><strong>Ilustracje 3 i 4.</strong> Etykieta z pustą zmienną wasParked na wniosku</em></p></figcaption></figure>

Po zapisaniu wniosku i ponownym wejściu na niego widać, że zmienna została automatycznie wypełniona:

<figure><img src="/files/yAJZPyDfIQxOT1fZex6r" alt=""><figcaption><p><em><strong>Ilustracja 5.</strong> Etykieta ze zmienną wasParked na wniosku (po ponownym wejściu na wniosek)</em></p></figcaption></figure>

## Jak używać zmiennej *wasParked*?

Na wniosku dodano etykietę:

<figure><img src="/files/e7qIFOKAO5aoZb1r8kpm" alt=""><figcaption><p><em><strong>Ilustracja 6.</strong> Etykieta ze zmienną wasParked w Eximee Designer</em></p></figcaption></figure>

Warunek widoczności ustawiony na tej etykiecie:

```java
getValue("wasParked")=="true"
```

Przy pierwszym wejściu na wniosek nie jest ona widoczna:

<figure><img src="/files/sIFNlSq8QrZKvGmswSRv" alt=""><figcaption><p><em><strong>Ilustracja 7.</strong> Brak widocznej etykiety przy pierwszym wejściu na wniosek</em></p></figcaption></figure>

Natomiast gdy wniosek zostanie zapisany, przy ponownym wejściu etykieta się pojawia:

<figure><img src="/files/iYDd5ZprGGXdCX2Pu7xd" alt=""><figcaption><p><em><strong>Ilustracja 8.</strong> Widoczna etykieta przy ponownym wejściu na wniosek</em></p></figcaption></figure>

## Zmiana sesyjna *wasParked*, a usługi

Działanie usługi również może być uzależnione od stanu zmiennej *wasParked*. Aby tak się stało, należy pamiętać o dodaniu warunku wywołania:

```java
getValue("wasParked")=="true"
```

<figure><img src="/files/cZC4ZSsdIqPxeVmqhNvK" alt=""><figcaption><p><em><strong>Ilustracja 9.</strong> Przykładowa usługa z warunkiem wywołania</em></p></figcaption></figure>

Po podpięciu etykiety i przy pierwszym wejściu na wniosku, serwis nie wywołuje się:

<figure><img src="/files/p1UrUtFfpMsTLwcdoo3v" alt=""><figcaption><p><em><strong>Ilustracja 10.</strong> Niezmieniona etykieta - serwis nie został wywołany przy pierwszym wejściu na wniosek</em></p></figcaption></figure>

Po zapisaniu wniosku i ponownym wejściu:

<figure><img src="/files/ygh6fzyB7gHxAoCh5jGB" alt=""><figcaption><p><em><strong>Ilustracja 11.</strong> Zmieniona etykieta - serwis został wywołany przy ponownym wejściu na wniosek</em></p></figcaption></figure>


# Dynamiczność formularza

Platforma Eximee umożliwia projektowanie formularzy **dynamicznych** – reagujących na dane wprowadzane przez użytkownika i automatycznie dostosowujących swój wygląd oraz działanie w trakcie wypełniania. Dynamiczność formularza opiera się na mechanizmach pozwalających definiować zależności i warunki między polami. (Szczegóły implementacyjne – np. składnia języka wyrażeń czy konfiguracja atrybutów – są opisane w dedykowanych rozdziałach [**Język wyrażeń**](/budowanie-aplikacji/interfejs-uzytkownika/formularze/dynamicznosc-formularza/jezyk-wyrazen) oraz [**Nasłuchiwanie i czyszczenie**](/budowanie-aplikacji/interfejs-uzytkownika/formularze/dynamicznosc-formularza/nasluchiwanie-i-czyszczenie)**,** poniżej przedstawiono ogólne wprowadzenie.)

### Mechanizmy dynamicznego formularza

Najważniejsze elementy odpowiadające za dynamiczne zachowanie formularza to:

* **Warunki widoczności, aktywności i wymagalności** – definiowane za pomocą specjalnego języka wyrażeń (składnia oparta o JavaScript, rozszerzona m.in. o metody `getValue()` i `isVisible()` do odczytu stanu komponentów). Pozwalają one uzależnić, czy dany komponent jest wyświetlany, aktywny do edycji oraz wymagany, od wartości innych pól lub zmiennych. *Uwaga:* Warunki odwołujące się do innych pól wymagają poprawnego ustawienia nasłuchiwania tych pól, aby zmiany ich wartości powodowały ponowną ocenę warunku.
* **Nasłuchiwanie (ListeningOn)** – atrybut wskazujący listę komponentów lub zmiennych, na które dany komponent „nasłuchuje”. Zmiana wartości nasłuchiwanych komponentów lub zmiennych wywoła ponowne przeliczenie zdefiniowanych warunków. Dzięki mechanizmowi nasłuchiwania formularz dynamicznie reaguje na zmiany – np. modyfikacja pola A automatycznie wpływa na pole B (powoduje ponowne przeliczenie wartości, zmianę widoczności/wymagalności, itp.).
* **Czyszczenie (ClearOn)** – atrybut określający listę komponentów lub zmiennych, których zmiana wartości spowoduje automatyczne *wyczyszczenie* (reset) wartości danego pola. Mechanizm czyszczenia usuwa dane, które stały się nieaktualne lub niepożądane po zmianie innego pola – np. gdy użytkownik zmieni wybór w polu nadrzędnym, zależne pola z ustawionym ClearOn zostaną opróżnione (przywrócone do stanu pustego).
* **Reguły warunkowe** – dodatkowe reguły logiki wykonywane tylko po spełnieniu określonych warunków, pozwalające realizować bardziej złożone scenariusze dynamiczne wykraczające poza pojedyncze pola. Mamy do dyspozycji szereg możliwości warunkowania działań aplikacji tak aby działała ona zgodnie z założeniami biznesowymi m.in.:
  * warunki wyświetlania kroków lub stron formularzy
  * warunki wywołania usług
  * warunki przejścia określoną ścieżką procesu (reguły biznesowe)

### Zastosowania dynamicznych formularzy

Dynamiczne zachowanie pól formularza jest najczęściej wykorzystywane w sytuacjach, gdy interakcje użytkownika powinny wpływać na inne elementy formularza. Typowe scenariusze to m.in.:

* **Ukrywanie i pokazywanie elementów formularza** – dynamiczne wyświetlanie lub ukrywanie określonych kroków, stron, sekcji czy pól na podstawie wcześniejszych wyborów użytkownika, danych uzyskanych z usług lub parametrów wywołania. Na przykład dodatkowe pytanie pojawia się dopiero po wybraniu przez użytkownika opcji „Tak”. Podobnie można dynamicznie wyłączać bądź włączać możliwość edycji pola (atrybut edytowalności) zależnie od spełnienia warunku.
* **Dynamiczne przeliczanie wartości** – automatyczne obliczanie lub aktualizacja wartości jednego pola na podstawie wartości innych pól. Przykładowo suma w polu "Łączny dochód" może być wyliczana z wartości w polach "Dochód 1" i "Dochód 2". Mechanizm nasłuchiwania gwarantuje natychmiastowe wywołanie skonfigurowanych skryptów przy każdej zmianie danych wejściowych.
* **Resetowanie zależnych pól** – czyszczenie (resetowanie) wartości pól zależnych po zmianie danych we wskazanym komponencie. Zapobiega to pozostawieniu w formularzu nieaktualnych lub sprzecznych danych. Przykład: jeśli pole "Kraj" zostanie zmienione, pola "Województwo" i "Miasto" mogą zostać automatycznie wyczyszczone, ponieważ ich poprzednie wartości były powiązane z wcześniej wybranym krajem.
* **Walidacja warunkowa** – sprawdzanie poprawności lub wymagalności pól tylko w określonych sytuacjach. Na przykład pole "Numer konta" może być oznaczone jako wymagane (i zweryfikowane przez walidator numeru) tylko wtedy, gdy użytkownik wybierze opcję wypłaty *przelewem*. W przeciwnym razie to pole pozostaje opcjonalne. Tego typu warunki zapobiegają pojawianiu się błędów walidacji w sytuacjach, gdy określone pole nie jest w danym scenariuszu wymagane do uzupełnienia.


# Język wyrażeń

**Język wyrażeń warunkowych w Eximee** pozwala definiować logikę warunkową (np. widoczność, aktywność, wymagalność pól) za pomocą składni JavaScript rozszerzonej o określone metody. Warunki są zapisywane jako wyrażenia, które platforma **Eximee** sprawdza w trakcie działania aplikacji. Poniżej opisano składnię, dostępne metody i atrybuty, a także narzędzia ułatwiające tworzenie i testowanie warunków.

## Wyrażenia warunkowe w Eximee

* **JavaScript w warunkach:** Wszystkie warunki w szablonie wniosku można opisać wyrażeniami języka JavaScript. Oznacza to, że w polu warunku możemy używać standardowych operatorów (`==`, `!=`, `>`, `<`, `&&`, `||`, `!`) oraz funkcji JavaScript. Składnia pozwala definiować m.in. negację (`!warunek`), koniunkcję (`warunek1 && warunek2`) oraz alternatywę warunków (`warunek1 || warunek2`).
* **Dostęp do wartości komponentów:** Do pobierania aktualnych wartości pól należy używać funkcji **`getValue("ID_KOMPONENTU")`**, gdzie *ID\_KOMPONENTU* to identyfikator pola, zmiennej sesyjnej lub komponentu w formularzu. [Jest to zalecany sposób uzyskania wartości komponentu (inne metody mogą powodować problemy z wydajnością). ](#user-content-fn-1)[^1]Przykładowo wywołanie `getValue("PoleTekst1")` zwróci bieżący tekst wpisany w polu tekstowym o ID = PoleTekst1.
* **Dostęp do innych atrybutów:** Poza wartością, komponenty posiadają też inne właściwości, do których można się odwołać. Służy do tego funkcja **`getData("ID_KOMPONENTU", "ATRYBUT")`**, zwracająca wartość zadanego atrybutu komponentu. Na przykład `getData("Checkbox1", "visible")` zwróci informację o widoczności pola **Checkbox1** (analogicznie do użycia `isVisible("Checkbox1")`). Lista dostępnych atrybutów dla poszczególnych typów komponentów jest przedstawiona w dokumentacji komponentów i częściowo omówiona w dalszej sekcji.
* **Typy danych w warunkach:** Wszystkie wartości pobrane z pól są traktowane jako tekst (łańcuch znaków) w momencie obliczania warunku. Dlatego przy porównaniach liczbowych lub logicznych należy samodzielnie konwertować typy danych. Można korzystać ze standardowych funkcji JavaScript, takich jak `parseInt()` (konwersja na liczbę całkowitą) czy `parseFloat()` (konwersja na liczbę zmiennoprzecinkową). Dla wartości logicznych warto pamiętać, że string `"true"`/`"false"` należy porównać jako ciąg znaków lub konwertować na typ boolean.
* **Stałe:** W wyrażeniach można używać stałych tekstowych (ujmowanych w cudzysłów), liczbowych (pisanych wprost) oraz logicznych (`true`/`false` bez cudzysłowu).
* **Zmienne sesyjne w warunkach:** Jeżeli chcemy użyć w warunku zmiennej sesyjnej (globalnej dla wniosku), możemy odwołać się do niej przez `getValue("NAZWA_ZMIENNEJ")`. W niektórych przypadkach (np. wewnątrz komponentów złożonych) należy poprzedzić nazwę zmiennej znakiem `@`. Przykładowo, wyrażenie `getValue("@zmienna1")=="Y"` sprawdzi, czy zmienna sesyjna `zmienna1` ma wartość "Y". Uwaga: Predefiniowane zmienne systemowe (jeśli występują) mogą nie wymagać tego prefixu. Zaleca się jednak stosowanie `@` przed nazwami własnych zmiennych w złożonych kontekstach, aby uniknąć niejednoznaczności.
* **Warunki złożone i zależności:** Można budować złożone wyrażenia, łącząc kilka porównań logicznymi operatorami. Np. wyrażenie `getValue("Pole1") != "" && parseInt(getValue("Pole2")) > 100.` Wyrażenie zwróci `true` tylko wtedy, gdy *Pole1* nie jest puste **i jednocześnie** wartość liczbowa *Pola2* jest większa od 100. W definiowaniu warunków, które zależą od wartości innych pól, **należy pamiętać o zdefiniowaniu nasłuchiwania** – więcej na ten temat w dalszej części (mechanizm [**ListeningOn**](#user-content-fn-2)[^2]).

## Atrybuty komponentów

Każdy komponent formularza posiada zestaw standardowych atrybutów opisujących jego stan. Najważniejsze wspólne atrybuty to:

* **`value`** – bieżąca *wewnętrzna* wartość komponentu (np. tekst wpisany w pole, zaznaczenie checkboxa, wybrana opcja listy).
* **`displayValue`** – wartość *wyświetlana* użytkownikowi. Często pokrywa się z `value`, ale dla niektórych pól może się różnić (np. w Comboboxie `value` to kod/ID wybranej opcji, a `displayValue` to tekst etykiety).
* **`visible`** – informacja o widoczności komponentu (`"true"` lub `"false"`). W warunkach można też użyć funkcji `isVisible("ID")` pełniącej podobną rolę.
* **`enabled`** – informacja o aktywności (edytowalności) komponentu, przyjmuje wartość `"true"` gdy pole jest aktywne lub `"false"` gdy jest wyłączone (nieedytowalne). Ten atrybut decyduje o tym, czy użytkownik może wchodzić w interakcje z danym polem.

Inne atrybuty mogą być specyficzne dla typu komponentu. Np. komponent listy rozwijanej (Combobox) udostępnia atrybuty **`label`** (tekst wybranej opcji), **`description`** (dodatkowy opis) czy **`size`** (liczba dostępnych opcji). Komponent *Oświadczenia* posiada kolekcję pozycji `statementsItemControl` reprezentujących poszczególne oświadczenia. Szczegółowy wykaz atrybutów znajduje się w dokumentacji każdego rodzaju komponentu.

|                                         |                                                                                                                        |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Pole tekstowe                           | <p>value<br>displayValue<br>visible</p>                                                                                |
| Obszar tekstu                           | <p>value<br>displayValue<br>visible</p>                                                                                |
| Data                                    | <p>value<br>displayValue<br>visible</p>                                                                                |
| Zakres dat                              | <p>value<br>displayValue<br>visible</p>                                                                                |
| Plus minus                              | <p>value<br>displayValue<br>visible</p>                                                                                |
| Treść formatowana (i zwijana)           | <p>value<br>displayValue<br>visible</p>                                                                                |
| Pole wyboru wartości z listy (Combobox) | <p>label - tekst wybranej wartości<br>description - description wybranej wartości<br>size - długość listy wartości</p> |
| Wybór rachunku                          | <p>value<br>displayValue<br>visible</p>                                                                                |
| Checkbox                                | <p>moreInfoButtonClicked<br>value<br>displayValue<br>visible</p>                                                       |
| Radio                                   | <p>value<br>displayValue<br>visible</p>                                                                                |
| Grupa radio                             | <p>value<br>displayValue<br>visible</p>                                                                                |
| Grupa kafli                             | <p>content - zwróci displayValue<br>value<br>displayValue<br>visible</p>                                               |
| Kafel                                   | visible                                                                                                                |
| Oświadczenia                            | <p>statementsItemControl<br>value<br>displayValue<br>visible</p>                                                       |
| Slider                                  | <p>sliderValue<br>value - (defaultValue)<br>displayValue<br>visible</p>                                                |
| Step Slider                             | <p>sliderValue - value<br>value - (defaultValue)<br>displayValue<br>visible</p>                                        |
| Slider podwójnego zakresu               | <p>value<br>displayValue<br>visible</p>                                                                                |
| Sekcja                                  | folded                                                                                                                 |
| Sekcja checkbox                         | <p>value<br>displayValue<br>visible</p>                                                                                |
| Sekcja powtarzalna                      | folded                                                                                                                 |
| Pomoc kontekstowa                       | <p>value<br>displayValue<br>visible</p>                                                                                |
| Wybór produktu                          | <p>variantId<br>productId<br>value<br>displayValue<br>visible</p>                                                      |
| Picture card                            | <p>value<br>displayValue<br>visible</p>                                                                                |
| Załączniki                              | <p>totalFilesSize<br>fileNames<br>externalIds<br>value<br>displayValue<br>visible</p>                                  |
| Komponent potwierdzenia danych          | <p>wasEdited<br>value<br>displayValue<br>visible</p>                                                                   |
| Skaner kodów QR                         | <p>value<br>displayValue<br>visible</p>                                                                                |
| Mapa                                    | <p>value<br>displayValue<br>visible</p>                                                                                |
| Komponent specjalizowany                | <p>value<br>displayValue<br>visible</p>                                                                                |
| Frontend component                      | <p>value<br>displayValue<br>visible</p>                                                                                |

**Odwoływanie się do atrybutów w warunkach:** Jak wspomniano, do odczytu atrybutu służy `getData(id, "atrybut")`. Jednak w praktyce większość warunków sprawdza po prostu wartość pola (`value`) lub jego widoczność/aktywność. Dla wygody platforma Eximee udostępnia dedykowane metody API:

* **`getValue("ID")`** – zwraca `value` komponentu o wskazanym ID (najczęściej używane).
* **`isVisible("ID")`** – zwraca informację o widoczności komponentu (ciąg `"true"`/`"false"`).

*(Niektóre komponenty specjalne posiadają dodatkowe metody, np. do obsługi grup oświadczeń – opisane dalej.)*

> *Przykład:* Jeśli pole tekstowe *AdresEmail* ma identyfikator `GesTextField5`, wówczas:
>
> * `getValue("GesTextField5")` zwróci wpisany adres e-mail,
> * `isVisible("GesTextField5")` zwróci `"true"` jeśli pole jest widoczne lub `"false"` jeśli zostało ukryte.

**Atrybuty specjalne – komponent Oświadczenia:** Dla komponentów typu *Oświadczenia* (lista zgód/akceptacji) dostępne są funkcje pozwalające sprawdzić, czy konkretne oświadczenie zostało zaznaczone. Metoda **`getStatementValue("ID_KOMPONENTU", "MID_OŚWIADCZENIA")`** zwraca wartość danego oświadczenia (zgody) na tym komponencie. W nowszych wersjach funkcja ta może być dostępna pod nazwą `getStatementItem`. Użycie jest następujące: np. `getStatementValue("Zgody1", "newsletter") == "true"` zwróci `true`, jeśli w komponencie o ID *Zgody1,* oświadczenie o identyfikatorze (MID) *newsletter* jest zaakceptowane przez użytkownika.

## Zaawansowany edytor warunków

Eximee Designer udostępnia **zaawansowany edytor warunków**, który ułatwia tworzenie, edycję i weryfikację wyrażeń warunkowych. Edytor ten został wyposażony w następujące funkcje:

* **Kolorowanie składni:** składnia wyrażeń JavaScript jest podświetlana kolorami, co zwiększa czytelność złożonych warunków.
* **Automatyczne podpowiedzi:** podczas edycji warunku wyświetlane są podpowiedzi dostępnych zmiennych i pól formularza, a także podpowiedzi elementów API Eximee oraz często używanych metod JS.
* **Obsługa prefiksu "`js:"`:** nie ma potrzeby ręcznie wpisywać przed warunkiem prefiksu `"js:"` – edytor sam go pomija w widoku i automatycznie dodaje w kodzie źródłowym przy zapisie warunku. Dzięki temu użytkownik wpisuje tylko właściwe wyrażenie, a platforma dba o poprawny format.

**Gdzie używany jest edytor warunków:** Zaawansowany edytor jest wykorzystywany w polach na właściwości komponentu takie jak: **warunek widoczności**, **warunek aktywności (edycji)** oraz **warunek wymagalności**. Te trzy właściwości każdego komponentu formularza korzystają z opisywanego edytora i pozwalają na wpisanie formuły decydującej odpowiednio o tym, czy komponent jest widoczny, aktywny (odblokowany) oraz czy jest wymagany do wypełnienia.

<figure><img src="/files/pWSG1ZJk0zlbcsY1bBul" alt=""><figcaption></figcaption></figure>

**Podpowiedzi składni w edytorze:** W trybie edycji warunku można skorzystać z podpowiedzi, naciskając klawisze **Ctrl + Spacja**. Spowoduje to wyświetlenie listy dostępnych elementów do użycia. Wśród podpowiedzi znajdują się m.in.:

* *Standardowe funkcje i właściwości JavaScript:* `parseInt()`, `parseFloat()`, właściwość `.length` (długość tekstu) czy `size` (rozmiar listy), a także inne często używane konstrukcje (np. słowo kluczowe `empty` do sprawdzania pustych wartości).
* *API Eximee:* funkcje dostarczane przez platformę, takie jak `getValue()`, `getData()`, `isVisible()` czy `getStatementValue()`, pojawią się na liście podpowiedzi, przypominając o ich dostępności.
* *Identyfikatory pól i zmiennych:* edytor automatycznie podpowiada **MIDy komponentów** dostępnych w danym formularzu (wraz z ich technicznym ID w nawiasie) oraz nazwy zmiennych sesyjnych używanych we wniosku. Dzięki temu można szybko wstawić referencję do konkretnego pola bez konieczności pamiętania jego dokładnego identyfikatora.

<figure><img src="/files/RMIoMcaC7ypsVNl0h8Ex" alt=""><figcaption></figcaption></figure>

> **Tip:** W przypadku dużej liczby pól, aby szybko znaleźć na liście podpowiedź dla konkretnego komponentu, zacznij pisać jego nazwę (MID) – lista zostanie przefiltrowana. Podpowiedzi pomagają unikać literówek w ID oraz umożliwiają poznanie dostępnych funkcji.

## Przykłady użycia wyrażeń warunkowych

Poniżej znajduje się kilka przykładowych wyrażeń warunkowych wraz z opisem ich działania. Każdy przykład pokazuje fragment kodu użytego w definicji warunku oraz wyjaśnienie:

* ```js
  parseInt(getValue("GesTextField3")) > 5
  ```

  – porównanie całkowitoliczbowe: sprawdza, czy wartość liczbowa wpisana w polu tekstowym `GesTextField3` jest większa od 5.
* ```js
  parseFloat(getValue("GesTextField5")) < 200.001
  ```

  – porównanie zmiennoprzecinkowe: sprawdza, czy wartość z pola tekstowego `GesTextField5` (np. kwota lub liczba z miejscami po przecinku) jest mniejsza od 200.001.
* ```js
  getValue("GesCheckbox1") == "true"
  ```

  – porównanie logiczne (równość): sprawdza, czy pole typu *Checkbox* o ID `GesCheckbox1` jest zaznaczone (ma wartość `"true"`).
* ```js
  getValue("GesCheckbox1") != "true"
  ```

  – porównanie logiczne (różność): sprawdza, czy ten sam checkbox **nie** jest zaznaczony (czyli wartość różna od `"true"` – w praktyce `"false"` lub brak wartości).
* ```js
  getValue("GesRadioGroup1") == "audi"
  ```

  – porównanie tekstowe: sprawdza, czy w grupie przycisków Radio o ID `GesRadioGroup1` wybrano opcję o wartości `"audi"` (np. jedna z marek samochodów).
* ```js
  !!getValue("nazwiskoZew")
  ```

  – podwójna negacja: sprawdza, czy dana wartość nie jest pusta. Dwa wykrzykniki konwertują wartość na typ boolean – wyrażenie zwróci `true`, jeśli zmienna lub pole `nazwiskoZew` posiada niepustą wartość (np. użytkownik wpisał nazwisko), a `false` w przeciwnym razie.
* ```js
  !getValue("nazwiskoZew")
  ```

  – negacja: sprawdza, czy wartość jest pusta. Zwróci `true`, jeśli pole/zmienna `nazwiskoZew` **nie ma wartości** (np. użytkownik nic nie wpisał), co w JavaScript jest równoznaczne z wartością *falsy* (np. pusty string `""`).
* ```js
  getStatementItem("GesStatementPopup1", "oswiadczenie1") == "true"
  ```

  – warunek dla komponentu typu *Oświadczenia*: sprawdza, czy w komponencie o ID `GesStatementPopup1` zaznaczono oświadczenie o identyfikatorze (MID) `oswiadczenie1` (czyli czy użytkownik zaakceptował to oświadczenie).
* ```js
  getStatementItem("@GesStatementFlat5", "zdrowotne") == "false"
  ```

  – podobny warunek dla *Oświadczenia* wewnątrz komponentu złożonego: sprawdza, czy oświadczenie `zdrowotne` w komponencie o ID `GesStatementFlat5` (osadzonym w komponencie złożonym, stąd prefiks `@`) **nie zostało** zaznaczone przez użytkownika.
* ```js
  !!!(getValue("@GesTextField13") || getValue("@GesTextField8"))
  ```

  – przykład warunku wymagalności: potrójna negacja przed wyrażeniem w nawiasie sprawdza, czy *oba* pola tekstowe `GesTextField13` oraz `GesTextField8` są puste. Wewnątrz nawiasu operator `||` zwróci pierwszą niepustą wartość (lub pustą, jeśli obie wartości są puste). Zastosowanie `!` odwraca wynik, a `!!` konwertuje go do booleana. Efektem całości jest `true` tylko wtedy, gdy **oba pola są puste** (wtedy np. inne pole staje się wymagane). Gdy którekolwiek pole ma wartość, wyrażenie zwróci `false` (czyli warunek wymagalności nie jest spełniony, więc np. dane pole nie musi być wymagane).
* ```js
  getValue("@GesCombobox1") != 2 && getValue("@GesCombobox1") > 0
  ```

  – złożony warunek dla listy wyboru (Combobox): sprawdza dwie rzeczy jednocześnie – czy wartość wybrana w polu Combobox `GesCombobox1` **nie jest równa 2** oraz czy jest **większa od 0**. Taki warunek mógłby służyć np. do weryfikacji wyboru innego niż domyślny (zakładając, że wartość `0` oznacza brak wyboru, a `2` to jakaś opcja wykluczona).
* ```js
  isVisible("@GesTextField1") == "true"
  ```

  – sprawdzenie stanu widoczności: warunek zwróci `true`, jeśli komponent o ID `GesTextField1` jest aktualnie widoczny (np. inny warunek go nie ukrył). Można to wykorzystać, aby uzależnić działanie od tego, czy inne pole jest na ekranie.
* ```js
  getValue("GesTextField5").length == 10
  ```

  – sprawdzenie długości tekstu: warunek zwraca `true`, jeśli w polu tekstowym `GesTextField5` wpisano dokładnie 10 znaków. Może to służyć np. do walidacji formatu (sprawdzenie czy numer ma wymaganą długość).

*(W powyższych przykładach użyto przykładowych identyfikatorów wygenerowanych przez system, takich jak **GesTextField5**. W rzeczywistym projekcie zaleca się nadawanie polom czytelnych identyfikatorów biznesowych (MID), co ułatwia późniejsze odwoływanie się do nich w warunkach)*

### Wyrażenia warunkowe w komponentach złożonych i biznesowych

* Wewnątrz komponentu złożonego/biznesowego, aby jednoznacznie wskazać zmienną/pole z tego komponentu, poprzedź nazwę znakiem `@`:
  * `getValue("@nazwaZmiennej")`
  * Przykład: `getValue("@walutaDomyślna") == "USD"`.
  * Dlaczego? w trakcie ewaluacji warunku `@` rozwija się do identyfikatora komponentu, np. `getValue("@nazwaZmiennej")` → `getValue("GesComplexComponent1.nazwaZmiennej")`, co eliminuje kolizje nazw z formularzem głównym, na którym umieszczono komponent.
* Gdy istnieje kolizja nazw (ta sama zmienna/pole w głównym wniosku i w komponencie) lub chcesz być precyzyjny — użyj `@` nawet jeśli warunek działa bez niego.
* Dobra praktyka: w komponentach złożonych/biznesowych zawsze poprzedzaj nazwy zmiennych/pól znakiem `@` w wyrażeniach warunkowych, chyba że umyślnie chcesz się odwołać do zmiennej/pola z formularza głównego - wtedy pomiń `@`
* Uwaga: zmienne predefiniowane przez system umieszczane są na głównym formularzu, odwołujemy się zatem do nich bezpośrednio po nazwie pomijając znak `@`.

Przykłady:

* Główny formularz: `getValue("walutaDomyślna") == "USD"`.
* Wewnątrz komponentu (precyzyjnie do zmiennej z tego komponentu): `getValue("@walutaDomyślna") == "USD"`.

## FAQ – Najczęstsze pytania

**Jak ustawić, żeby komponent wyświetlał się warunkowo (np. po zaznaczeniu checkboxa)?**\
Należy skorzystać z właściwości **Warunek widoczności (visibleCondition)** dostępnej w panelu właściwości komponentu. W pole warunku wpisujemy wyrażenie, które ma zwracać `true` gdy komponent ma być widoczny. Przykładowo: jeżeli pole *SekcjaDodatkowa* ma pokazywać się po zaznaczeniu checkboxa *PokazSekcje (id=GesCheckbox7)*, to ustawiamy warunek widoczności: `getValue("GesCheckbox7") == "true"`. Gdy użytkownik zaznaczy dany checkbox, warunek zostanie spełniony i *SekcjaDodatkowa* stanie się widoczna.

**Warunek nie odświeża się po zmianie innego pola – co robię źle?**\
Prawdopodobnie brakuje ustawienia **nasłuchiwania**. Aby komponent reagował na zmiany wartości innego pola używanego w wyrażeniu, trzeba ustawić dla niego atrybut **ListeningOn** (Nasłuchiwanie) wskazujący na to pole. Innymi słowy, komponent z warunkiem musi "nasłuchiwać" komponentu, od którego zależy warunek. W Eximee Designer zrobisz to w sekcji **Interakcje** właściwości komponentu – dodaj na liście Nasłuchiwanie identyfikator zależnego pola. Po poprawnym ustawieniu nasłuchiwania, zmiana wartości jednego pola automatycznie spowoduje ponowną ewaluację warunku w drugim polu.

**Jak sprawdzić w warunku, czy pole jest puste lub wypełnione?**\
Można to zrobić na kilka sposobów. Najprostszym jest wykorzystanie faktu, że pusty string w JavaScript jest wartością *falsy* (nieprawdziwą). Przykładowo: wyrażenie `!getValue("PoleX")` zwróci `true`, gdy *PoleX* jest puste (negacja pustego stringa da true). Odwrotnie, wyrażenie `!!getValue("PoleX")` zwróci `true`, tylko jeśli *PoleX* ma jakąś wartość (podwójna negacja konwertuje wartość na typ boolean zachowując jej "prawdę"). Alternatywnie można porównać bezpośrednio do pustego ciągu: `getValue("PoleX") == ""` (puste) lub `getValue("PoleX") != ""` (wypełnione).

**Czy w wyrażeniu warunkowym muszę dodawać przedrostek `js:`?**\
Nie. W edytorze Eximee Designer wpisujemy tylko samo wyrażenie warunkowe, bez żadnych prefixów. Prefiks `"js:"` jest dodawany automatycznie w kodzie źródłowym i służy wewnętrznie do oznaczenia, że warunek należy interpretować jako skrypt JavaScript. Jeśli podejrzysz konfigurację XML wniosku, zobaczysz tam `condition="js:...twoje_wyrażenie..."`, ale w interfejsie Designer nie trzeba (ani nie powinno się) tego pisać samodzielnie.

**Jak zdefiniować warunek, który jest zawsze spełniony (zawsze prawdziwy)?**\
Jeśli chcemy, by dana akcja/warunek był *zawsze* prawdziwy (np. aby element był zawsze widoczny lub jakaś akcja zawsze się wykonywała), możemy jako wyrażenie wpisać stałą prawdziwą. W praktyce wystarczy wpisać wartość **`true`**. Edytor doda odpowiedni prefix i warunek będzie traktowany jako zawsze spełniony. Alternatywnie, można wpisać **`js:true`** w surowej konfiguracji – efekt będzie taki sam. Podobnie, warunek zawsze fałszywy można uzyskać wpisując `false` (co spowoduje np. że dany komponent nigdy nie będzie widoczny sam z siebie).

**Czy mogę używać dowolnych funkcji JavaScript w warunkach?**\
Obsługiwane są podstawowe funkcje i operatory JavaScript, zwłaszcza te podpowiadane przez edytor (jak `parseInt`, `parseFloat`, operatory logiczne itp.). Należy jednak pamiętać, że warunek jest wykonywany w kontekście przeglądarki użytkownika, więc nie powinien zawierać wywołań, które mogą być niezrozumiałe lub niedostępne. Dobrą praktyką jest ograniczenie się do prostych operacji i korzystanie z API udostępnianego przez platformę Eximee (np. `getValue`, `getData`, itp.) dla spójności i wydajności. Bezpośrednie odwoływanie się do elementów DOM czy zmiennych globalnych nie jest wspierane i może powodować błędy. Jeśli potrzebujesz skomplikowanej logiki, rozważ umieszczenie jej w kodzie walidatora lub usługi.

[^1]: Ja bym chyba nie naprowadzal czytających na inne metody tym bardziej że moga one powodować problemy z wydajnością.

[^2]: przydałby sie tu link


# Nasłuchiwanie i czyszczenie

* **Nasłuchiwanie i czyszczenie** to mechanizmy umożliwiające definiowanie dynamicznego zachowania komponentów formularza oraz powiązanych z nimi zmiennych. Dzięki nim zmiany w jednym polu mogą automatycznie wpływać na inne pola, komponenty lub wartości w formularzu.
* **Atrybut Nasłuchiwanie (ListeningOn)** – pozwala określić, na które inne komponenty lub zmienne dany komponent „nasłuchuje”. Oznacza to, że zmiana wartości wskazanego komponentu albo zmiennej spowoduje reakcję komponentu nasłuchującego – np. jego ponowne przeliczenie wartości lub odświeżenie widoczności.
* **Atrybut Wyczyszczenie pola (ClearOn)** – definiuje, które zmiany w innych komponentach lub zmiennych wywołają automatyczne wyczyszczenie (usunięcie) wartości danego komponentu. Innymi słowy, jeśli wskazane powiązane pole lub zmienna zmieni swoją wartość, komponent z ustawionym czyszczeniem usunie własną bieżącą wartość (wyczyści pole).
* Oba powyższe atrybuty dostępne są w sekcji **Interakcje** panelu właściwości wybranego komponentu. Konfiguracja odbywa się za pomocą specjalnego okna – należy kliknąć przycisk **Lista** obok pola *Nasłuchiwanie* lub *Wyczyszczenie pola*, co otworzy popup do edycji tych ustawień.

<figure><img src="/files/Gkt1kJmt4VSOfIzU5IWt" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Sekcja "Interakcje"</em></p></figcaption></figure>

* W oknie **Elementy wzbudzające zmianę** (otwieranym przyciskiem **Lista**) wyświetlana jest lista komponentów, na które nasłuchuje dana kontrolka. Listę można zawęzić za pomocą pola filtrowania (**Filtruj...**) u góry okna. Obok każdego dodanego elementu znajduje się ikona kosza – pojawia się po najechaniu kursorem – umożliwiająca usunięcie tego elementu z listy nasłuchiwanych.

<figure><img src="/files/fzdSXqzOGWaCkGNwKdhr" alt=""><figcaption><p><em><strong>Ilustracja 2.</strong> Okno wyboru elementów do nasłuchiwania</em></p></figcaption></figure>

* Aby dodać nowy element do nasłuchiwania, użyj pola **Dodaj MID** na dole okna. Pole to podpowiada wszystkie dostępne identyfikatory (MID/ID) komponentów oraz zmiennych, na które można nasłuchiwać. Wybierz żądany komponent z listy podpowiedzi (klikając go lub poprzez zatwierdzenie klawiszem Enter). Wybrany element zostanie dodany do listy, a w opisie atrybutu Nasłuchiwanie w panelu właściwości pojawi się informacja o liczbie elementów nasłuchiwanych (np. *Nasłuchiwania: 1*).

<figure><img src="/files/yhUAmWLTleOUVyO65jv9" alt=""><figcaption><p><em><strong>Ilustracja 3.</strong> Wskazywanie elementu do dodania</em></p></figcaption></figure>

* *Uwaga:* Jeśli w logice komponentu używane są walidatory, usługi lub warunki (widoczności, aktywności, wymagalności) odwołujące się do wartości innych pól bądź zmiennych, należy **prawidłowo ustawić Nasłuchiwanie (oraz ewentualnie Wyczyszczenie pola)** dla tych zależności. W przeciwnym razie zmiany w powiązanych polach nie będą automatycznie uwzględniane przez dany komponent.

### Przykłady zastosowania

* **Automatyczne przeliczenie pola** – Pole obliczeniowe (np. suma dwóch wartości) nasłuchuje na zmiany pól źródłowych. Jeśli użytkownik zmieni wartość w którymś z pól składowych, pole sumy automatycznie przeliczy swoją wartość na nowo.
* **Dynamiczna widoczność sekcji** – Sekcja formularza wyświetlana warunkowo (np. dodatkowe szczegóły pokazywane po zaznaczeniu checkboxa *„Pokaż więcej”*) powinna nasłuchiwać na to pole wyboru. Dzięki temu zmiana stanu checkboxa od razu spowoduje ponowną ocenę warunku i ukrycie lub pokazanie sekcji zgodnie z jego definicją.
* **Resetowanie wartości pola zależnego** – Pole które powinno zostać wyczyszczone po zmianie innego wyboru korzysta z atrybutu *Wyczyszczenie pola*. Przykładowo, pole *„Model samochodu”* może nasłuchiwać na pole *„Marka samochodu”* oraz mieć ustawione czyszczenie względem niego. Zmiana marki spowoduje automatyczne usunięcie wybranej wcześniej wartości modelu, aby użytkownik wybrał nowy model pasujący do zmienionej marki.
* **Odświeżanie listy dokumentów po zmianie strony** – Komponent *Lista dokumentów* (DocumentList) może nasłuchiwać na zmienną `currentPageMid` (identyfikator bieżącej strony formularza). Powoduje to, że przy przejściu do innej strony wniosku komponent ponownie załaduje/odświeży swoje dane. Dzięki temu unikniemy sytuacji, w której wyświetlany jest nieaktualny zestaw dokumentów (np. wydruków) po zmianie strony.

### FAQ

* **P:** Czym się różnią atrybuty *Nasłuchiwanie* i *Wyczyszczenie pola*?\
  **O:** *Nasłuchiwanie* powoduje, że komponent reaguje (przelicza się lub odświeża) w odpowiedzi na zmianę wartości określonego innego pola lub zmiennej. Natomiast *Wyczyszczenie pola* powoduje automatyczne wymazanie bieżącej wartości komponentu, gdy zmieni się wskazane powiązane pole lub zmienna.
* **P:** Czy muszę ustawić nasłuchiwanie, jeśli mój komponent wykorzystuje warunek lub walidator odwołujący się do innego pola?\
  **O:** Tak. Jeżeli logika komponentu (np. warunek widoczności lub wymagalności, skrypt walidatora, itp.) korzysta z wartości innego pola bądź zmiennej, to komponent **musi nasłuchiwać** na ten element. W przeciwnym razie zmiany wartości tamtego pola nie będą uwzględniane na bieżąco – warunek czy walidacja nie zareaguje na zmienione dane.
* **P:** Ustawiłem atrybut *Wyczyszczenie pola*, ale pole nie usuwa wartości przy zmianie powiązanego komponentu – dlaczego?\
  **O:** Najprawdopodobniej brakuje atrybutu nasłuchiwania. Aby czyszczenie pola zadziałało poprawnie, komponent docelowy musi **również nasłuchiwać** na wskazany element wyzwalający zmianę. Innymi słowy, w konfiguracji komponentu należy dodać *Nasłuchiwanie* **wraz z** *Wyczyszczeniem pola* odnosząc je do tego samego komponentu, którego zmiana ma czyścić wartość.
* **P:** Jak dodać lub usunąć element na liście nasłuchiwanych dla danego komponentu?\
  **O:** Należy otworzyć okno konfiguracji nasłuchiwania – w panelu właściwości kliknąć **Lista** obok atrybutu *Nasłuchiwanie*. W oknie **Elementy wzbudzające zmianę** nowy element dodajemy poprzez pole **Dodaj MID** (wpisując lub wybierając z listy odpowiedni komponent/zmienną i zatwierdzając Enterem). Aby usunąć element z listy nasłuchiwania, wystarczy najechać kursorem na jego nazwę w tym oknie i kliknąć ikonę kosza obok niej.
* **P:** Na jakie elementy można nasłuchiwać?\
  **O:** Komponent formularza może nasłuchiwać na zmiany **innych komponentów** (pól formularza) oraz na **zmienne sesyjne** powiązane z formularzem. Podczas konfiguracji w oknie nasłuchiwania dostępna jest pełna lista ID/MID wszystkich pól i zmiennych, które można wybrać jako źródła nasłuchu.


# Wstawki JavaScript

## Obsługa dynamicznej treści (wstawki JavaScript)

System umożliwia wstawianie dynamicznej treści za pomocą wstawek JavaScript. Mogą one być używane w następujących miejscach:

* w komponentach **Treść formatowana (TextContent)**,
* w komponentach **Etykieta**,
* we właściwości **Etykieta** dostępnej w innych komponentach.

{% hint style="warning" %}
Funkcjonalność *nie obejmuje* komponentu **Treść formatowana (TextContent)** umieszczonego w obszarze **Footera**.
{% endhint %}

### Format wstawki JavaScript

Wstawki mają postać:

```js
<?js: return "wartość"; /** przykładowy kod JS zwracający wartość */ ?>
```

Treść wstawki musi zawsze zwracać wartość (np. string).

***

### Przykłady użycia

#### 1. Zwracanie wartości w zależności od pola formularza

Poniższa wstawka zwróci tekst *"m1. "* tylko wtedy, gdy pole o identyfikatorze `GesTextField1` zostało wypełnione:

```js
<?js: return getValue("GesTextField1") ? "m1. " : ""; ?>
```

***

#### 2. Obsługa wartości domyślnej i własnej (zmienne sesyjne)

W przykładzie poniżej, jeśli zmienna `etykietaWlasna` jest pusta lub ma wartość `null`, zostanie użyta wartość z `etykietaDomyslna`.\
Obie wartości są dostępne jako zmienne sesyjne:

```js
<?js: return (getValue("etykietaWlasna") == "" || getValue("etykietaWlasna") == null)
    ? "${etykietaDomyslna}"
    : "${etykietaWlasna}"; ?>
```

***

#### 3. Wstawka z formatowaniem HTML

W zależności od wartości pola `channel` dynamicznie zwracana jest treść zawierająca HTML:

```js
<?js:
  return getValue("channel") == "mobile"
    ? "<b>Zgoda na kontakt telefoniczny w celu marketingowym.</b> <span class='optional' style='color:#bec2c3;'>(opcjonalne)</span>"
    : "Zgoda na kontakt telefoniczny w celu marketingowym. <span class='optional' style='color:#bec2c3;'>(opcjonalne)</span>";
?>
```

***

### Dostępne metody JavaScript

W ramach wstawek można korzystać z metod opisanych w sekcji:

[**Język wyrażeń definiowania warunków**](/budowanie-aplikacji/logika-biznesowa/jezyk-wyrazen-definiowania-warunkow-warunki-z-getvalue)

Pozwala to m.in. na odwoływanie się do wartości pól, porównania, sprawdzanie pustych wartości itp.

***

### Ważna uwaga dotycząca identyfikatorów

W treści wstawek **nie poprzedzamy identyfikatorów komponentów ani nazw zmiennych symbolem `@`**.\
Przykład poprawny:

```js
getValue("GesTextField1")
```

Przykład niepoprawny:

```js
getValue("@GesTextField1")
```


# Praca z komponentami bazowymi


# Dodawanie i parametryzowanie komponentów

### Dodawanie nowego komponentu

Nowy komponent można dodać w trybie edycji używając palety komponentów znajdującej się z lewej strony. Należy w tym celu przeciągnąć wybrany komponent z palety i upuścić go w odpowiednim miejscu na wniosku.

![Ilustracja 1. Paleta komponentów prostych](/files/ecb821971a27669cb4e64a53a56cb24cc71f5f1f)

### Tryb edycji i przenoszenie komponentu

Aby komfortowo przenosić komponenty po przestrzeni wniosku warto włączyć tryb siatki layoutu przyciskiem **Siatka layoutu** ![](/files/2d8e2b9ca1c7c8db458143fb2e48f8178866322d) znajdującym się w lewym dolnym rogu wniosku. Po jego kliknięciu na wniosku pojawi się siatka, która ułatwi umiejscowienie i dostosowanie rozmiaru komponentów ([Siatka layoutu / szata](/budowanie-aplikacji/interfejs-uzytkownika/formularze/tworzenie-formularza/siatka-layoutu-szata)).

Aby przenieść komponent, należy przytrzymać nad nim przycisk myszki i upuścić w żądanym miejscu. Nad podniesionym komponentem będą zapalać się pola w dwóch kolorach:

* zielonym: oznaczenie prawidłowego miejsca dla wstawianego komponentu,
* czerwonym: nieprawidłowe miejsce (np. próbujemy umieścić jeden komponent na drugim lub umieścić komponent w osadzonym komponencie złożonym lub radio grupie).

Jeżeli chcemy upuścić komponent w nowej linii, należy najechać na przestrzeń pomiędzy komponentami. Przestrzeń ta zostanie powiększona, co ułatwi upuszczenie komponentu.

Po przeniesieniu ostatniego komponentu z danego wiersza, wiersz ten zostanie automatycznie usunięty.

![Ilustracja 2. Wstawianie komponentu](/files/806c7ef2750a8c873722c97d361237b4c43c03a3)

### Możliwe operacje przenoszenia komponentów

| Miejsce źródłowe komponentu | Miejsce docelowe komponentu | Typ komponentu | Możliwe                                                     |
| --------------------------- | --------------------------- | -------------- | ----------------------------------------------------------- |
| strona                      | strona                      | wszystkie      | ![(tick)](/files/a0f423787c241a2a3b96814867735e112689e1d4)  |
| strona                      | sekcja                      | wszystkie      | ![(tick)](/files/a0f423787c241a2a3b96814867735e112689e1d4)  |
| sekcja                      | strona                      | wszystkie      | ![(tick)](/files/a0f423787c241a2a3b96814867735e112689e1d4)  |
| sekcja                      | sekcja                      | wszystkie      | ![(tick)](/files/a0f423787c241a2a3b96814867735e112689e1d4)  |
| komponent złożony           | gdziekolwiek                | wszystkie      | ![(tick)](/files/a0f423787c241a2a3b96814867735e112689e1d4)  |
| gdziekolwiek                | komponent złożony           | wszystkie      | ![(error)](/files/abc626231af3e8376039e4585f4fa90076b9ec2f) |
| grupa checkbox              | gdziekolwiek                | checkbox       | ![(error)](/files/abc626231af3e8376039e4585f4fa90076b9ec2f) |
| radio grupa                 | gdziekolwiek                | radio          | ![(error)](/files/abc626231af3e8376039e4585f4fa90076b9ec2f) |
| grupa kafli                 | gdziekolwiek                | kafel          | ![(error)](/files/abc626231af3e8376039e4585f4fa90076b9ec2f) |

### Zmiana szerokości komponentu

[Zmiana szerokości komponentów (layout)](/budowanie-aplikacji/interfejs-uzytkownika/formularze/praca-z-komponentami-bazowymi/zmiana-szerokosci-komponentow)

### Przejście do edytora treści umieszczonej na wniosku/w komponencie

W menu kontekstowym komponentu treści formatowanej dostępna jest opcja otwarcia powiązanego artefaktu w edytorze treści.

Wybranie **Przejdź do źródła treści** przenosi użytkownika do edytora treści w bibliotece.

Opcja **Przejdź do źródła treści** jest dostępna jedynie gdy do komponentu podpięty jest artefakt w formacie nazwa-wersja.

![Ilustracja 3. Akcje menu kontekstowego komponentu treści formatowanej](/files/13e9b511d0b333268ac631fefd5dc915b5eb7faa)

### Przejście do edytora źródła komponentu złożonego/biznesowego

W menu kontekstowym osadzonego komponentu złożonego/biznesowego dostępna jest opcja otworzenia podpiętego artefaktu w edytorze komponentów.

Wybranie **Przejdź do źródła komponentu** przeniesie użytkownika do edytora komponentów złożonych/biznesowych w bibliotece.

![Ilustracja 4. Akcje menu kontekstowego komponentu złożonego/biznesowego](/files/7246f41b90bc36cd644d12ac15cf39d49b886545)

### Panel właściwości komponentu

Po kliknięciu w komponent umieszczony w obszarze roboczym otwiera się panel edycji atrybutów danego komponentu (wybrany komponent oznaczony jest przerywaną ramką).

Aby przejść do wyświetlania parametrów dla komponentu złożonego lub biznesowego należy zaznaczyć go klikając uchwyt pojawiający się nad komponentem po lewej stronie.

<figure><img src="/files/LXgtziOmOp14iytS1bjb" alt=""><figcaption><p align="center"><em><strong>Ilustracja 5.</strong> Prezentacja zaznaczonego komponentu złożonego na formularzu.</em></p></figcaption></figure>

Właściwości pogrupowane są na sekcje. Kliknięcie w miejsce nie zajmowane przez żaden komponent lub poza obszar strony umożliwia podgląd właściwości całej strony.

![Ilustracja 6. Panel właściwości komponentu Etykieta](/files/96cbd62d4d93e44491bef9d3cb53f31ce9c96635)

#### Dziedziczenie liczby kolumn

Komponenty kompozytowe (np. grupa kafli, radio grupa) posiadają możliwość włączenia właściwości **Dziedziczenie liczby kolumn**. Powoduje ona, że szerokości kolumn w komponencie będą takie same, jak w jego rodzicu. Jest to osiągane poprzez zapewnienie, że szerokość komponentu zawsze będzie odpowiadać liczbie jego kolumn. Podczas zmiany szerokości takiego komponentu, kolumny będą odpowiednio dodawane lub odejmowane. Z uwagi na to, można zmniejszyć szerokość komponentu tylko wtedy, gdy zawiera puste kolumny.

![Ilustracja 7. Właściwości dotyczące liczby kolumn](/files/6f58eb61efde6a8a0c5d3a469188f25e24c1be7a)

Opcja włączenia dziedziczenia liczby kolumn jest aktywna tylko, gdy szerokość komponentu jest taka sama jak liczba kolumn. Zmiana liczby kolumn z poziomu edytora atrybutów powoduje wyłączenie omawianej właściwości.

![Ilustracja 8. Komponent Radio grupa z wyłączoną właściwością "Dziedziczenie liczby kolumn"](/files/7b56541e31928d55eb335dd1e687d8db9dfc9aa6)

Przykład użycia:

Rozważmy przypadek rozszerzania o 3 komórki komponentu kompozytowego, którego szerokość i liczba kolumn są równe 3.

Komponent z właściwością "Dziedziczenie liczby kolumn"

| Przed zmianą                                         | Po zmianie                                           |
| ---------------------------------------------------- | ---------------------------------------------------- |
| ![](/files/536065ecd192bf522aeeb413c730196d5ed598ff) | ![](/files/d35f4d02b3e00192ef654eda748b1bfd505aade0) |

Po rozszerzeniu liczba kolumn wciąż jest równa szerokości. Utworzone zostały 3 dodatkowe, puste kolumny.

Komponent bez właściwości "Dziedziczenie liczby kolumn"

| Przed zmianą                                         | Po zmianie                                           |
| ---------------------------------------------------- | ---------------------------------------------------- |
| ![](/files/6423b17e5b2206dc0a448f51315d58367b622894) | ![](/files/1f46cb2e45ae167c31cab8d16e223f7c665da6ae) |

Rozszerzenie nie spowodowało zmiany liczby kolumn w komponencie i wciąż są 3. Szerokość komponentu została zwiększona do 6. Każda kolumna komponentu rozciągnięta jest teraz na dwie komórki strony.

#### Mapowanie wartości na pole zewnętrznego modelu danych

{% hint style="info" %}
Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.
{% endhint %}

Pole zewnętrznego modelu danych, na które będzie zmapowana wartość komponentu, można wybrać na dwa sposoby:

* z pola wyboru,
* z drzewa.

Zdefiniowane mapowania zostają dodane na końcu bezwarunkowej grupy mapowań.

![Ilustracja 9. Opcja mapowania wartości komponentu na pole zewnętrznego modelu danych](/files/1c8dc93d0bd7e873ee7a1cc7cda1659b1dccc149)

Edytować można jedynie mapowania pól, które mają zdefiniowane nie więcej niż jedno mapowanie. W przeciwnym wypadku edytor wyświetli przycisk przekierowujący do zakładki **Model danych**, która pozwala na definiowanie bardziej złożonych mapowań.

![Ilustracja 10. Opcja mapowania komponentu posiadającego więcej niż jedno mapowanie](/files/773a9f47c4491d3ceeed0cc949f99e3532067a6d)

Edytor mapowania jest widoczny tylko gdy wniosek posiada zdefiniowany minimum jeden proces systemu zewnętrznego.

### Usuwanie komponentów ze strony

Usuwanie komponentów możliwe jest poprzez kliknięcie przycisku menu znajdującego się w prawym górnym rogu zaznaczonego komponentu, a następnie wybranie opcji **Usuń**. Jeśli usunięcie komponentu nie jest możliwe, ikona usuwania nie wyświetla się.

<figure><img src="/files/gKITLsRMosctU9yywtYf" alt=""><figcaption><p align="center"><em><strong>Ilustracja 11.</strong> Usuwanie komponentu</em></p></figcaption></figure>

### Cofanie operacji

Użytkownik może skorzystać z opcji wycofania dowolnej zmiany wykonanej w trakcie pracy z kopią roboczą (od momentu jej utworzenia). Aby cofnąć efekty ostatnio wykonanej czynności wystarczy nacisnąć przycisk **Cofnij zmiany** znajdujący się w prawym górnym rogu edytora, bądź skorzystać ze skrótu klawiszowego Ctrl + Z.

![Ilustracja 12. Ikony Cofnij i Ponów](/files/d22f61f135cbb201aebf2b75bd2cd12febca3c34)

Podczas wycofywania operacji blokowane są wszelkie interakcje z edytorem. Zmiany można wycofywać dowolną ilość razy (aż do przywrócenia oryginalnego stanu artefaktu).

Uwaga: operacje są cofane niezależnie od aktualnie otwartej zakładki. Np. w przypadku, gdy użytkownik wykona zmianę w zakładce **Model danych**, a następnie przejdzie do zakładki **Kroki**, wycofanie zmian wycofa zmianę z pierwszej zakładki.

### Zapisywanie wersji

Aby zapisać nową wersję artefaktu należy nacisnąć ikonę **Zapisz** ![](/files/5TrzLFPiuhyuouFpYgJe) znajdującą się w prawej części górnej belki. Spowoduje to otwarcie popupa, na którym można uzupełnić opis zmiany oraz wybrać, czy zapisać artefakt w istniejącej gałęzi (MINOR), czy utworzyć nową gałąź (MAJOR). W przypadku zapisu nowej wersji wniosku, zostaje on automatycznie opublikowany.

![Ilustracja 13. Okno zapisu wersji artefaktu](/files/591db32d849d4e02dfcb7190b4c2e57a51e75f06)


# Wspólne właściwości komponentów

## Podstawowe własności komponentów <a href="#wspolnewlasciwoscikomponentow-podstawowewlasnoscikomponentow" id="wspolnewlasciwoscikomponentow-podstawowewlasnoscikomponentow"></a>

Niezależnie od typu każdy komponent posiada zdefiniowane właściwości dostępne w panelu wyświetlonym z prawej strony po zaznaczeniu komponentu.

<table><thead><tr><th width="224.5390625">Właściwość Eximee Designer</th><th width="253.6953125">Nazwa atrybutu w Źródle</th><th>Opis</th></tr></thead><tbody><tr><td>Sekcja <strong>Podstawowe właściwości</strong></td><td></td><td></td></tr><tr><td><strong>Id</strong></td><td>id</td><td>Unikalny identyfikator techniczny pola (nadawany automatycznie przy dodawaniu komponenentu).</td></tr><tr><td><strong>Identyfikator biznesowy</strong></td><td>mid</td><td><p>Biznesowy identyfikator pola (domyślnie jest taki sam jak id, ale można go zmienić).<br><br>Identyfikator biznesowy (Mid) to jednoznaczny identyfikator powiązany z logiką biznesową. Po nadaniu go łatwiej nam będzie wyszukać konkretny komponent przy dodawaniu nasłuchiwań czy parametrów wejścia i wyjścia Page Services. Midu nie mają komponenty Etykieta (Text) i Treść formatowana (TextContent).</p><p>Identyfikator biznesowy powinnien być pisany camelCasem, nie powinien zawierać spacji i polskich znaków.<br><br><strong>UWAGA!</strong></p><p>Z racji tego, że model danych Uniflow opiera się na biznesowych identyfikatorach pól (mid) a nie na id, w przypadku wykorzystywania na wniosku modelu danych Uniflow nie mogą powtórzyć się biznesowe identyfikatory pól (np. mamy dwa różne komponenty o tym samym identyfikatorze biznesowym albo komponent ma ten sam mid co id zmienne sesyjnej).<br></p></td></tr><tr><td><strong>Etykieta</strong></td><td>label</td><td><p>Etykieta komponentu wyświetlana nad komponentem (atrybut nie jest obsługiwany w niektórych kanałach).</p><p><br></p></td></tr><tr><td><strong>Nieaktywne pole prezentowane jako etykieta</strong></td><td>labelIfDisabled</td><td><p>Zaznaczone (ustawione na "true") oznacza, że nieaktywny komponent wyświetlany jest jak tekst (na wniosku wygląda jak prezentowany jak etykieta).</p><p>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.</p><p>Wniosek demo: demoLabelIfDisabled</p></td></tr><tr><td><strong>Pomoc kontekstowa</strong></td><td>toolTips</td><td><p>Definiowanie dynamicznej pomocy kontekstowej dla komponentu w zależności od warunków.</p><p>Więcej w: <a href="/pages/v3B65hqT3xj4U3YapH4L">Pomoc kontekstowa - Tooltip</a></p></td></tr><tr><td><strong>Klucz modelu danych</strong></td><td>model</td><td><p>Dla pól mogących przyjmować wartości określa powiązanie dwustronne z modelem danych.</p><p>Więcej w: <a href="/pages/KG0pXEaHL87RO7XIlUyS">Przechowywanie danych w modelu</a></p></td></tr><tr><td>Sekcja <strong>Jakość danych</strong></td><td></td><td></td></tr><tr><td><strong>Warunek widoczności</strong></td><td>visibleCondition</td><td>Warunek widoczności pola (warunki wpisujemy z użyciem edytora opisanego w <a href="/pages/hXzjgFvoksjR8o8dGewt">Zaawansowany edytor warunków</a>).</td></tr><tr><td><strong>Warunek aktywności</strong></td><td>enabledCondition</td><td>Warunek możliwości edycji pola (warunki wpisujemy z użyciem edytora opisanego w <a href="/pages/hXzjgFvoksjR8o8dGewt">Zaawansowany edytor warunków</a>).</td></tr><tr><td><strong>Maksymalna długość wartości</strong></td><td>maxPropertyLength</td><td><p>Ze względów bezpieczeństwa każda wartość tekstowa w platformie (np.: zawartość pola tekstowego, wartość i opis listy rozwijanej, wartość radio itp.) jest weryfikowana pod względem długości. Domyślnie platforma nie przepuszcza ciągów znaków o długości przekraczającej 256. Jeżeli ze względu na wymagania biznesowe konieczna jest zmiana maksymalnej długości to można to zrobić za pomocą atrybutu <strong>Maksymalna długość wartości</strong>.<br>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.</p><p><strong>UWAGA!</strong></p><p>System posiada dodatkowy twardy limit (domyślnie: 10485760 znaków) - jest to nieprzekraczalny limit, który nie zostanie nadpisany przez wartość atrybutu Maksymalna długość wartości.<br></p></td></tr><tr><td><strong>Warunek wymagalności</strong></td><td>requiredCondition</td><td>Warunek wymagalności pola (warunki wpisujemy z użyciem edytora opisanego w <a href="/pages/hXzjgFvoksjR8o8dGewt">Zaawansowany edytor warunków</a>).</td></tr><tr><td><strong>Walidatory</strong></td><td>externalValidators</td><td><p>Definiowanie specjalizowanych walidatorów zewnętrznych.</p><p>Więcej w: <a href="/pages/lVPOHNqQ5rEO7wfdFB2Y">Walidacje złożone</a></p></td></tr><tr><td><strong>Wartość domyślna</strong></td><td>defaultValue</td><td>Dla pól mogących przyjmować wartości określa wartość początkową komponentu.</td></tr><tr><td><strong>Formater</strong></td><td>formatter</td><td>Patrz: <a href="/pages/QtuZa8iDFF99WgQsPvDk">Ustawienie formatowania dla komponentu</a>.</td></tr><tr><td><strong>Opis pola</strong></td><td>description</td><td>Tekst wyświetlany jako opis pola poniżej niego, domyślnie jest to wartość pusta.<br><br>Dostępność funkcjonalności zależy od licencji i może nie być dostępna we wszystkich wdrożeniach.</td></tr><tr><td>Sekcja <strong>Interakcje</strong></td><td></td><td></td></tr><tr><td><strong>Nasłuchiwanie</strong></td><td>listeningOn</td><td><p>Lista komponentów, od których zależny jest komponent. Zmiana wartości komponentów nasłuchiwanych spowoduje odświeżenie stanu komponentu.</p><p>Więcej w: <a href="/pages/zzKeW0m7KL1LeJuJGjIf">Nasłuchiwanie i czyszczenie</a>.</p></td></tr><tr><td><strong>Źródło danych zewnętrznych</strong></td><td>enternalDataSource</td><td><p>Definiowanie zewnętrznych źródeł danych.</p><p>Więcej w: <a href="/pages/j3qNIVPhV7mObqCBufU4">Zasilanie komponentów zewnętrznymi źródłami danych</a></p></td></tr><tr><td><strong>Wyczyszczenie pola</strong></td><td>clearOn</td><td>Lista komponentów, od których zależne jest wyczyszczenie danych wprowadzonych do komponentu.</td></tr><tr><td><strong>Źródło danych z innego pola</strong></td><td>valueSourceId</td><td>ID innego komponentu, który zapewni wartość dla danego komponentu (przykład użycia został opisany w: <a href="/pages/jgFYBEKKjFDwnFdNf2Ql">Przekazywanie wartości między komponentami lub stronami wniosku</a>).</td></tr><tr><td>Sekcja <strong>Bezpieczeństwo</strong></td><td></td><td></td></tr><tr><td><strong>Biała lista znaków</strong></td><td>extraWhitelistCharacters</td><td><p>Ze względów bezpieczeństwa każda wartość tekstowa w platformie (np.: zawartość pola tekstowego, wartość i opis listy rozwijanej, wartość radio, wartość grupy kafli itp.) jest weryfikowana pod względem dopuszczalnych znaków. Domyślnie platforma dopuszcza następujące klasy znaków:</p><ul><li>litery (łącznie ze znakami diakrytycznymi wszystkich języków),</li><li>cyfry,</li><li>znaki białe (różnego rodzaju spacje, tabulacje, znaczniki nowej linii itp.),</li><li>następujące znaki specjalne: '.' (kropka), ',' (przecinek), '-' (myślnik), '_' (podkreślnik).</li></ul><p>Jeżeli do serwera trafi wartość ze znakiem spoza listy to serwer przywróci ostatnią bezpieczną wartość. Jeżeli ze względu na wymagania biznesowe konieczne jest rozszerzenie listy znaków specjalnych na danym polu to można użyć do tego atrybutu <strong>Biała lista znaków</strong> (extraWhitelistCharacters). Wartością atrybutu jest ciąg znaków, które mają być dopuszczalne w danym polu.</p><p><strong>UWAGA!</strong></p><p>W przypadku rozszerzania listy dopuszczalnych znaków, ze względów bezpieczeństwa należy się upewnić, że usługi, do których będzie wysyłana ta wartość są gotowe na przyjęcie danego znaku oraz odpowiednio zabezpieczone.</p><p>Znak @ (małpa) domyślnie jest niedopuszczalny, o ile pole nie jest typu "email" (parametr <strong>Typ danych</strong> (expected type)).</p><p><strong>WAŻNE!</strong></p><p>W przypadku komponentów, które oprócz etykiety, mają również wartość (np. Radio grupa, Grupa kafli), i wartości te z jakiegoś powodu są różne (w kontekście niedozwolonych znaków), konieczne jest zdefiniowane w <strong>Biała lista znaków</strong> obydwu wartości - definiujemy to dla Grupy kafli, a nie dla pojedynczego Kafla.</p><p>Przykład: np. dla kafelka z etykietą "5+" zdefiniowano wartość option jako ">5" - w takiej sytuacji w białej liście jako dopuszczalne znaki musimy zdefiniować zarówno "+", jak i ">"</p><p>(stosowanie różnych wartości dla treści i wartości nie jest rekomendowanym rozwiązaniem, zaleca się stosowanie uspójnionych wartości).</p></td></tr><tr><td><strong>Pole techniczne</strong></td><td>technicalField</td><td>Pole wykorzystywane na wewnętrzne potrzeby logiki szablonu wniosku, nie jest propagowane do kolejnych systemów oraz nie jest widoczne na wniosku. Właściwość dostępna jest dla wybranych komponentów.</td></tr><tr><td>Sekcja <strong>Stylizacja</strong></td><td></td><td></td></tr><tr><td><strong>Nazwa stylów</strong></td><td>styleName</td><td>Nazwa stylu komponentu (w eximee Webforms odpowiada stylowi CSS, który zostanie nadany danemu komponentowi).</td></tr><tr><td>Sekcja <strong>Pozostałe</strong></td><td></td><td></td></tr><tr><td><strong>Automatyczna aktualizacja wartości</strong><br></td><td>autoServerUpdate</td><td><p>Automatyczne odsyłanie wartości do serwera (niezależnie czy na dany komponent coś nasłuchuje). Dodatkowo w przypadku zaznaczenia tej flagi przetwarzanie w grafie (po zmianie wartości) rozpoczyna się od komponentu, którego wartość się zmieniła (domyślnie przetwarzanie rozpoczyna się od jego następników).</p><p><strong>UWAGA!</strong></p><p>Ustawienie ma duży wpływ na wydajność platformy wnioskowej. Należy ją stosować wyłącznie w miejscach, w których jest wymagana (np. gdy używamy Suggestera). W sytuacjach wątpliwych prosimy o kontakt z zespołem Consdata.</p><p>Przykładowy wniosek z suggesterem i właściwością autoServerUpdate: test_autoserverUpdate.</p></td></tr><tr><td><strong>Tag GTM / Aktywowanie GTM</strong></td><td>gtmTagName/pushTagsToGtm</td><td>Możliwość skonfigurowania funkcjonalności <strong>Google Tag Manager</strong>. Domyślnie pole nie jest zaznaczone (wartość "false").</td></tr><tr><td><strong>Zbieranie statystyk</strong></td><td>getStats</td><td>Pole wykorzystywane do zbierania statystyk o danym komponencie. Domyślnie pole nie jest zaznaczone (wartość "false").</td></tr><tr><td><strong>Widoczność na wydruku</strong></td><td>printable</td><td>Określa czy komponent ma być widoczny na wydruku wniosku. Domyślnie pole jest zaznaczone (wartość "true").</td></tr><tr><td><strong>Zachowanie zmiany wartości, gdy komponent jest ukryty</strong></td><td>preserveValueWhenHidden</td><td><p>Flaga ta służy do zabezpieczenia zmiany wartości komponentu na domyślną, gdy zostanie on ukryty (lub jest on ukryty po odparkowaniu). Wartość komponentu zostanie zachowana również po zaparkowaniu i będzie możliwa do użycia w kolejnych sesjach. Domyślnie pole nie jest zaznaczone (wartość "false").</p><p>Funkcjonalność nie jest dostępna dla niektórych komponentów.</p></td></tr></tbody></table>

### Warunki widoczności <a href="#wspolnewlasciwoscikomponentow-warunkiwidocznosci" id="wspolnewlasciwoscikomponentow-warunkiwidocznosci"></a>

Dla każdego komponentu w panelu **Właściwości** można określić warunki jego widoczności, klikając **Dodaj warunek widoczności** w polu **WARUNEK WIDOCZNOŚCI** (dostępnym w sekcji **Jakość danych**). W wyświetlonym edytorze warunków można wprowadzać warunki zapisane prostym językiem wyrażeń (więcej w [Zaawansowany edytor warunków](/budowanie-aplikacji/logika-biznesowa/jezyk-wyrazen-definiowania-warunkow-warunki-z-getvalue/zaawansowany-edytor-warunkow)). Wykorzystywany język wyrażeń został opisany w [Język wyrażeń definiowania warunków](/budowanie-aplikacji/logika-biznesowa/jezyk-wyrazen-definiowania-warunkow-warunki-z-getvalue).

<figure><img src="/files/PX3owIr0U3YwtF8w1nJd" alt=""><figcaption><p><em><strong>Ilustracja 1.</strong> Pusta właściwość definiowania warunku widoczności</em></p></figcaption></figure>

Komponent jest widoczny jedynie w przypadku spełnienia warunku wpisanego w polu **WARUNEK WIDOCZNOŚCI**.

### Warunki wymagalności <a href="#wspolnewlasciwoscikomponentow-warunkiwymagalnosci" id="wspolnewlasciwoscikomponentow-warunkiwymagalnosci"></a>

Dla każdego komponentu w panelu **Właściwości** można określić warunki przy których komponent jest wymagalny, klikając **Dodaj warunek wymagalności** w polu **WARUNEK WYMAGALNOŚCI** (dostępnym w sekcji **Jakość danych**). Okno edycji warunku jest analogiczne do okna edycji warunku widoczności komponentów. Do definiowania warunków wykorzystywany jest język JavaScript opisany w [Język wyrażeń definiowania warunków](/budowanie-aplikacji/logika-biznesowa/jezyk-wyrazen-definiowania-warunkow-warunki-z-getvalue).

Komponenty, dla których warunek jest spełniony są wymagalne i nie jest możliwe przejście na kolejną stronę wniosku bez wprowadzenia wartości.

### Warunki komponentów w trybie tylko do odczytu <a href="#wspolnewlasciwoscikomponentow-warunkikomponentowwtrybietylkodoodczytu" id="wspolnewlasciwoscikomponentow-warunkikomponentowwtrybietylkodoodczytu"></a>

Dla każdego komponentu w panelu **Właściwości** można określić warunki, przy których komponent jest prezentowany w trybie tylko do odczytu, klikając **Dodaj warunek aktywności** w polu **WARUNEK AKTYWNOŚCI**. Okno edycji warunku jest analogiczne do okna edycji warunku widoczności komponentów. Do definiowania warunków wykorzystywany jest język JavaScript opisany w [Język wyrażeń definiowania warunków](/budowanie-aplikacji/logika-biznesowa/jezyk-wyrazen-definiowania-warunkow-warunki-z-getvalue).

Dla komponentów z niespełnionym warunkiem zablokowana jest możliwość edycji ich wartości podczas prezentacji wniosku.

### Nasłuchiwanie <a href="#wspolnewlasciwoscikomponentow-nasluchiwanie" id="wspolnewlasciwoscikomponentow-nasluchiwanie"></a>

Dla każdego komponentu można określić listę komponentów, na które nasłuchuje dany komponent (więcej w [Nasłuchiwanie i czyszczenie](/budowanie-aplikacji/interfejs-uzytkownika/formularze/dynamicznosc-formularza/nasluchiwanie-i-czyszczenie)).

Na podstawie nasłuchiwania tworzony jest graf zależności. W momencie zmiany stanu komponentu podgraf zależności zawierający wszystkie ścieżki kończące się na zmienianym komponencie jest sortowany topologicznie i komponenty w podgrafie są odświeżane. Odświeżanie komponentów następuje w kolejności wynikającej z sortowania topologicznego w taki sposób, że odświeżane są tylko te komponenty, których przynajmniej jeden bezpośredni poprzednik w grafie zmienił stan.

Cykle w grafie zależności rozwiązywane są arbitralnie (ucinane za komponentem leżącym głębiej w grafie)

Istnieje możliwość włączenia odświeżania wszystkich komponentów w grafie (niezależnie od tego czy bezpośredni poprzednik zmienił stan). Jest to czynność administracyjna i wymaga zmiany następującego wpisu w pliku /etc/eximee/webforms.xml:

```
<webforms>
    <server>
        ...
        <nonBlockingGraphFormTemplates>nazwa_szablonu1,nazwa_szablonu2</nonBlockingGraphFormTemplates>
    </server>
</webforms>
```

{% hint style="info" %}
Wniosek demo: demoWspolneWlasciwosciKomponentow
{% endhint %}


# Pomoc kontekstowa

Większość komponentów w Eximee Designer ma możliwość zdefiniowania pomocy kontekstowej. Wyjątkami są komponenty **Generator kodów QR** oraz **Strona**.

<figure><img src="/files/JnO1727H8iR1yy9qGu5k" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Wygląd właściwości pozwalającej uzyskać dostęp do edytora pomocy kontekstowej</em></p></figcaption></figure>

Po wejściu do edytora pomocy kontekstowej wysuwana jest szuflada. Gdy komponent nie ma dodanej żadnej pomocy kontekstowej zawartość szuflady wygląda jak na ilustracji poniżej.

<figure><img src="/files/zkekxSCONFDkneSJ0ag1" alt=""><figcaption><p align="center"><em><strong>Ilustracja 2.</strong> Wygląd szuflady edytora bez dodanych pomocy kontekstowych</em></p></figcaption></figure>

Kliknięcie w znajdujący się u dołu szuflady przycisk **Dodaj pomoc kontekstową** powoduje dodanie elementu do szuflady. Reprezentuje on nową pomoc kontekstową.

<figure><img src="/files/duDw9uc6jdAsoGGciL6Q" alt=""><figcaption><p align="center"><em><strong>Ilustracja 3.</strong> Wygląd nowo dodanej i nieskonfigurowanej pomocy kontekstowej</em><br></p></figcaption></figure>

Podstawowymi właściwościami podlegającymi edycji jest nazwa klucza pomocy kontekstowej oraz warunek jej wyświetlania.

Przed dodaniem klucza z treścią pomocy kontekstowej, należy klucz i jego treść dodać w zakładce **Tłumaczenia**. Edycja przeprowadzana jest poprzez kliknięcie w polu **Podaj nazwę klucza**.

W polu **Dodaj warunek** można zdefiniować dynamiczną pomoc kontekstową z treścią zależną od warunków:

* wartości zmiennych sesyjnych,
* wartości innych komponentów.

Jeśli zdefiniowanych jest kilka pomocy kontekstowych, wyświetlona zostanie jedynie pierwsza pomoc kontekstowa, której warunek jest spełniony. W celu zmiany kolejności treści pomocy można posłużyć się funkcjonalnością drag & drop.

<figure><img src="/files/xszUvu0Zg6NclAkvnQZa" alt=""><figcaption><p align="center"><em><strong>Ilustracja 4.</strong> Przykład zdefiniowanych dwóch różnych pomocy kontekstowych wyświetlanych warunkowo</em></p></figcaption></figure>

Kliknięcie w **Pokaż szczegóły** rozszerza kafel i pozwala uzyskać dostęp do dodatkowych opcji, widocznych na ilustracji poniżej:

<figure><img src="/files/fTjahXFxCuph8BtrUn9i" alt=""><figcaption><p align="center"><em><strong>Ilustracja 5.</strong> Wygląd rozszerzonego okna edycji pomocy kontekstowej</em></p></figcaption></figure>

W widoku szczegółowym istnieje możliwość zdefiniowania następujących właściwości:

* **Nazwa stylu** - nazwa stylu do zaaplikowania na pomoc kontekstową,
* **Ikona pomocy** - ustalenie, czy powinna być wyświetlana ikona pomocy kontekstowej,
* **Widoczna na focus pola** - ustalenie, czy pomoc kontekstowa powinna być wyświetlana podczas zaznaczania,
* **Interaktywna pomoc kontekstowa** - ustalenie, czy będzie można wchodzić w interakcję z treścią pomocy kontekstowej,
* **Szerokość/Wysokość** dymka pomocy kontekstowej,
* **Pozycja** pomocy kontekstowej względem komponentu, którego dotyczy.

W szufladzie edytora pomocy kontekstowej można zdefiniować wiele tooltipów. Wówczas są one rozpatrywane w kolejności od góry do dołu. Każdy kafel pomocy kontekstowej posiada po lewej stronie uchwyt, który pozwala go chwycić, a następnie przesunąć na żądaną pozycję. W taki sposób można uszeregować całą listę i zmieniać kolejność elementów.

**Widoczność pomocy kontekstowej**

W widoku szczegółowym należy określić jeden z dwóch sposobów prezentacji pomocy kontekstowej:

* Ikona pomocy,
* Widoczna na focus pola.

Widoczność pomocy kontekstowej sterowana jest również opcjonalnym warunkiem.

<figure><img src="/files/qnB4pCZfRb5PkeWIi9uC" alt=""><figcaption><p align="center"><em><strong>Ilustracja 6.</strong> Przykładowy wygląd tooltipa na wniosku</em></p></figcaption></figure>

<figure><img src="/files/g9Too0nXjUng4Lcfgi8v" alt=""><figcaption><p align="center"><em><strong>Ilustracja 7.</strong> Przykładowy wygląd tooltipa na wniosku</em></p></figcaption></figure>

{% hint style="info" %}
Wniosek demo: demoTooltipy
{% endhint %}

{% hint style="info" %}
♿WCAG: [Dobre praktyki WCAG dla low-code dev](/budowanie-aplikacji/proces-biznesowy/tworzenie-procesu-biznesowego-w-bpmn-2.0/dobre-praktyki)
{% endhint %}


# Zmiana szerokości komponentów

* **Siatka kolumnowa:** Eximee Designer opiera układ formularza na siatce kolumn. Każda strona wniosku ma ustaloną liczbę kolumn (domyślnie 10 kolumn) przeznaczonych na komponenty. Liczbę kolumn formularza ustala się podczas tworzenia szablonu i każda nowo dodana strona dziedziczy tę wartość.
* **Sekcje a układ kolumn:** Komponent Sekcja domyślnie **dziedziczy** liczbę kolumn strony, ale można ustawić dla niego **własną** liczbę kolumn. Oznacza to, że jeśli strona ma np. 10 kolumn, wybrana sekcja może mieć np. 16 kolumn – wewnątrz takiej sekcji komponenty ułożą się w drobniejszej siatce, dając większą elastyczność układu.
* **Szerokość komponentu:** Każdy komponent może zajmować od jednej kolumny do pełnej szerokości (wszystkie kolumny) w swojej sekcji/stronie. Szerokość komponentu (w liczbie kolumn) można zmienić bezpośrednio w edytorze – w trybie edycji złap komponent za jego prawą lub lewą krawędź i przeciągnij, aby rozszerzyć lub zwęzić element. W trakcie przeciągania pojawia się zielony cień pokazujący nowy rozmiar komponentu oraz liczba na środku komponentu informująca, ile **kolumn** będzie on zajmował po puszczeniu. Aktualna szerokość komponentu (w kolumnach) jest również widoczna we właściwościach danego komponentu, w sekcji **Stylizacja**.
* **Elastyczność układu:** Liczbę kolumn układu można zwiększać w razie potrzeby – nowe kolumny zostaną dodane po prawej stronie formularza. Zmniejszanie liczby kolumn jest również możliwe, jednak **przed** obniżeniem tej wartości należy najpierw zwęzić komponenty na stronie/sekcji, tak aby żaden nie zajmował więcej kolumn niż nowa planowana szerokość. Dzięki temu układ pozostaje spójny i komponenty nie „wypadną” poza nowy rozmiar siatki.

### Przykłady

* **Rozciągnięcie komponentu na więcej kolumn:** W trybie edycji najedź kursorem na komponent, **złap** za jego prawą lub lewą krawędź i **przeciągnij**, aby zwiększyć jego szerokość. Podczas przeciągania komponentu zobaczysz zielony podświetlony obszar wskazujący nowy rozmiar oraz liczbę kolumn, które komponent będzie zajmować. Po puszczeniu przycisku myszy komponent zostanie rozszerzony do nowej szerokości.
* **Dwa komponenty w jednym wierszu:** Aby ustawić dwa komponenty obok siebie w tym samym rzędzie, upewnij się, że pierwszy z nich **nie zajmuje pełnej szerokości** strony/sekcji. Przeciągnij jego krawędź, zmniejszając szerokość tak, aby pozostawić wolne kolumny w wierszu. Następnie dodaj (lub przenieś) drugi komponent – jeżeli suma szerokości obu elementów nie przekracza całkowitej liczby kolumn, **drugi komponent ustawi się obok pierwszego** w jednym wierszu. Przykładowo: dla układu 10-kolumnowego dwa komponenty o szerokości 5 kolumn każdy wypełnią wspólnie cały wiersz.
* **Ustawienie komponentu na pełną szerokość:** Jeśli chcesz, aby komponent zajmował całą szerokość sekcji lub strony, rozszerz go na **maksymalną liczbę kolumn**. Można to zrobić poprzez przeciągnięcie krawędzi komponentu aż do końca wiersza (do pełnej szerokości kontenera) albo wpisując docelową liczbę kolumn we właściwościach komponentu (pole **Liczba kolumn** w sekcji *Stylizacja*). Komponent ustawiony na pełną szerokość będzie zajmować wszystkie kolumny dostępne w danym wierszu.

### Najczęstsze pytania (FAQ)

* **Ile kolumn ma standardowa strona?** Domyślnie nowo utworzony formularz (wniosek) podzielony jest na **10 kolumn** – taką wartość można zmienić podczas tworzenia szablonu. Jeśli nie zostanie zmieniona, wszystkie strony wniosku będą używać tej domyślnej liczby kolumn.
* **Czym różni się layout sekcji od layoutu strony?** **Strona** posiada globalnie ustawioną liczbę kolumn (wspólną dla całej strony). **Sekcja** jest komponentem-kontenerem wewnątrz strony – domyślnie przejmuje ona liczbę kolumn strony, ale można przypisać jej inną liczbę kolumn. W praktyce pozwala to zdefiniować niezależną siatkę w obrębie sekcji (np. sekcja może mieć więcej kolumn niż strona), co daje swobodę w rozmieszczaniu elementów wewnątrz tej sekcji.
* **Jak ustawić własny układ kolumn?** Liczbę kolumn strony można zmienić po utworzeniu formularza, edytując jego definicję. W trybie edycji wniosku przejdź do zakładki **Źródło** i odszukaj definicję danej strony, następnie zmień atrybut `numColumns` w sekcji `system:Page.layout` na żądaną wartość (np. 12). W przypadku **sekcji** zmiana układu kolumn jest dostępna bezpośrednio w Designerze – we właściwościach komponentu Sekcja (sekcja **Układ**) wyłącz dziedziczenie kolumn i wpisz własną liczbę kolumn dla tej sekcji. Zwiększenie liczby kolumn nie stanowi problemu (nowe kolumny zostaną dodane z prawej strony); przy **zmniejszaniu** liczby kolumn pamiętaj natomiast, by najpierw odpowiednio zwęzić komponenty w danym układzie, tak aby żaden nie przekraczał nowej mniejszej szerokości.

{% hint style="info" %}
Należy pamiętać, że przed zmniejszeniem liczby kolumn trzeba najpierw zwęzić komponenty. Można to zrobić w widoku **Wniosek** lub w **Źródle** ustawiając opcję **horizontalSpan** na taką jak liczba kolumn lub mniejszą.
{% endhint %}


# Walidacja wartości komponentów

Walidacja wartości komponentów w Eximee Designer pozwala na kontrolę poprawności danych wprowadzanych w formularzach. Dzięki walidacjom możemy upewnić się, że wszystkie dane przesyłane do systemu spełniają określone kryteria (np. są kompletne i w poprawnym formacie), co zapobiega błędom na późniejszych etapach procesu. Eximee Designer umożliwia podpięcie **standardowych walidacji** do kontrolek (komponentów) formularza – na przykład walidatora numeru PESEL, numeru dowodu osobistego czy numeru konta bankowego. **Domyślnie walidacje nie są aktywne**, dopóki nie zostaną skonfigurowane, dzięki czemu projektant sam decyduje, które pola wymagają sprawdzania. Każda walidacja definiowana jest dla konkretnego pola – pozwala to wyświetlić komunikat o błędzie bezpośrednio przy tym polu w przypadku niespełnienia warunków.


# Maska danych sensytywnych

Maskowanie danych sensytywnych służy do ukrywania części wrażliwych informacji w polu tekstowym lub etykiecie poprzez zastąpienie wybranych znaków symbolem `*`. Pozwala to zabezpieczyć takie dane jak PESEL czy numer karty kredytowej, aby nie były one w pełni widoczne na ekranie. Właściwość **Maska danych sensytywnych** znajdziemy w panelu właściwości komponentu, w sekcji **Bezpieczeństwo**. Po włączeniu maskowania, określone znaki wartości pola zostaną wyświetlone jako gwiazdki.

<figure><img src="/files/zDRvwquZ7AOwQQfFyenj" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Maska danych sensytywnych w Polu tekstowym</em></p></figcaption></figure>

Należy pamiętać, że maskowanie danych sensytywnych **działa tylko dla pól zasilanych danymi z innego źródła** (np. wartość pobierana z innego pola lub usługi). Jeżeli użytkownik **samodzielnie wpisuje** dane do pola, maska nie zostanie nałożona – wprowadzone znaki pozostaną widoczne w całości. Przykładowo, jeśli pole tekstowe *A* jest automatycznie uzupełniane wartością skopiowaną z innego pola *B* (źródło danych z innego pola), to na polu *A* możemy zastosować maskę, aby ukryć część informacji. Jeśli jednak użytkownik wpisuje dane w *A* ręcznie, maskowanie nie zadziała.

Maskowanie można także stosować na komponentach typu **Etykieta (Text)** wyświetlających dane wniosku. W przypadku etykiety, oprócz samego włączenia maskowania, dostępna jest dodatkowa opcja **Warunek maskowania danych sensytywnych** – pozwala ona określić warunek (logiczny), przy spełnieniu którego dana etykieta będzie maskować swoją wartość. Dzięki temu można np. maskować numer PESEL tylko dla niektórych typów użytkowników lub w określonych stanach procesu.

<figure><img src="/files/qi1XWfhRjQhpHGnLX3zE" alt=""><figcaption><p align="center"><em><strong>Ilustracja 2.</strong> Warunek maskowania danych sensytywnych w Etykiecie</em></p></figcaption></figure>

{% hint style="info" %}
Uwaga: Nie należy łączyć jednocześnie Maski danych sensytywnych z innymi formaterami na tym samym polu. W przypadku pól tekstowych zaleca się nie nakładać maskowania sensytywnego równocześnie z formatterem (np. formatowaniem numeru telefonu), aby uniknąć konfliktów i nieprzewidzianego działania formatowania.
{% endhint %}

{% hint style="info" %}
Wniosek demo: demoKomponentyTekstowe
{% endhint %}


# Walidacje proste (wbudowane)

Walidacje proste to zestaw podstawowych sprawdzeń dostępnych bezpośrednio w Eximee Designer. Ich konfiguracja odbywa się poprzez ustawienie odpowiednich właściwości komponentu w panelu **Jakość danych**. Poniżej wymieniono najważniejsze wbudowane sposoby walidacji:

* **Wymagalność pola** – określa, czy pole musi zostać obowiązkowo uzupełnione przez użytkownika. Ustawiana jest za pomocą właściwości **Warunek wymagalności (requiredCondition)** w sekcji **Jakość danych** danego komponentu. Jeśli chcemy, aby pole było zawsze wymagane, jako warunek podajemy wartość logiczną `true`. Możemy też wprowadzić bardziej złożony warunek zależny od innych pól – np. pole tekstowe staje się wymagane dopiero, gdy użytkownik zaznaczy określony checkbox. Warunki definiuje się w edytorze warunków i mogą one odwoływać się do wartości innych komponentów lub zmiennych sesyjnych. **Przykład:** Dla pola *Email* można ustalić **requiredCondition** na `getValue("GesCheckbox1") == "true"`, co oznacza, że adres e-mail będzie wymagany tylko jeśli zaznaczono wcześniej checkbox zgody. W takiej sytuacji należy dodatkowo upewnić się, że pole Email **nasłuchuje** na zmianę wartości tego checkboxa – służy do tego właściwość „Nasłuchiwanie” w panelu interakcji. Dzięki nasłuchiwaniu, gdy użytkownik zaznaczy lub odznaczy checkbox, formularz od razu sprawdzi ponownie warunek wymagalności dla pola Email. Jeśli warunek wymagalności nie jest spełniony (czyli pole jest wymagane, ale puste), użytkownik nie będzie mógł przejść do kolejnego kroku, a pod polem pojawi się komunikat błędu informujący, że pole jest wymagane.

<figure><img src="/files/FIanWkxSstcXBdwWf5cz" alt=""><figcaption><p align="center"><em><strong>Ilustracja 1.</strong> Przykład warunku wymagalności pola uzależnionego od wartości innego komponentu (tutaj checkboxa)</em></p></figcaption></figure>

* **Minimalna/Maksymalna liczba znaków** – określa dopuszczalną długość tekstu w polu. Dla komponentu **Obszar tekstu (TextArea)** dostępne są właściwości **minLength** (minimalna liczba znaków) oraz **maxLines** (maksymalna liczba wierszy tekstu). Dla **Pola tekstowego (TextField)** można ustawić **Minimalną liczbę znaków (minLength)** oraz **Maksymalną liczbę znaków (maxLength)**, co definiuje maksymalną długość wpisywanego tekstu. Przykładowo, aby wymusić wpisanie co najmniej 50 znaków opisu w polu komentarza, ustawiamy minLength = 50 – jeśli użytkownik wpisze mniej, zobaczy komunikat o konieczności dłuższej wypowiedzi.
* **Maska (wyrażenie regularne)** – pozwala zdefiniować **wzorzec**, jaki musi spełniać wpisywana wartość. Używa się jej np. do walidacji formatów takich jak kod pocztowy, numer telefonu, NIP itp. Konfiguracja polega na wpisaniu wyrażenia regularnego w polu **Maska** (sekcja *Jakość danych* komponentu), a następnie podaniu treści komunikatu błędu w polu **Komunikat błędu dopasowania do maski**. Jeżeli użytkownik wprowadzi wartość niepasującą do zadanego regexu, pod polem wyświetli się zdefiniowany komunikat, a formularz nie pozwoli przejść dalej dopóki wartość nie zostanie poprawiona. **Przykład:** Dla pola *Kod pocztowy* możemy ustawić maskę `\d{2}-\d{3}` oraz komunikat "Niepoprawny format kodu pocztowego". Wpisanie ciągu znaków niespełniającego tego wzorca (np. z literami lub złym układem cyfr) spowoduje wyświetlenie błędu.

| Wyrażenie regularne                                                                    | Znaczenie                                                                                                                                                                                                                                                                      | Przykładowe wartości                                        |
| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- |
| \d{2}-\d{3}                                                                            | Kod pocztowy                                                                                                                                                                                                                                                                   | 61-897                                                      |
| \d{11}                                                                                 | PESEL                                                                                                                                                                                                                                                                          | 75010125915                                                 |
| (\d{3}\[- ]\d{3}\[- ]\d{2}\[- ]\d{2})\|(\d{3}\[- ]\d{2}\[- ]\d{2}\[- ]\d{3})\|(\d{10}) | NIP                                                                                                                                                                                                                                                                            | <p>782-226-19-60<br>lub 782-22-61-960<br>lub 7822261960</p> |
| \[a-zA-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ]+\[a-zA-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ\ \\-\\']\*                      | Pole zaczyna się od litery, dalej tylko litery, spacja, myślnik, apostrof. Przykładowe wykorzystanie w polu imię lub nazwisko.                                                                                                                                                 | Janina Nowak-Kowalska                                       |
| \[0-9\\(\\+]+\[0-9\ \\(\\)\\+\\-]\*                                                    | <p>Pole zaczyna się od cyfry, otwarcia nawiasu lub plusa, dalej tylko cyfry, nawiasy, spacje, plus, myślniki.<br>Przykładowe wykorzystanie w polu z numerem telefonu (rozwiązanie alternatywne wobec przykładowej maski z <strong>visibleMask Prezentacja maski</strong>).</p> | <p>+48 (12) 31 23 123<br>lub (48) 123-123-123</p>           |
| \[0-9A-Za-z]\*                                                                         | Możliwość wprowadzenia tylko cyfr i liter                                                                                                                                                                                                                                      | <p>abc123</p><p>123abc</p>                                  |
| \[0-9]{6}\[\\\*]{1,6}\[0-9]{4}                                                         | Maskowany numer karty - pole należy uzupełnić podając 6 pierwszych cyfr oraz 4 ostatnie cyfry numeru karty, rozdzielone znakami " \* " (maksymalnie sześć znaków specjalnych: " \* ").                                                                                         | 123456\*\*7890                                              |

* **Prezentacja maski (visibleMask)** – nie mylić z powyższą maską regex. Prezentacja maski służy do zdefiniowania formatu, w jakim **podczas wpisywania** mają się układać znaki w polu tekstowym. Typowym przykładem jest automatyczne dodawanie myślników lub spacji w kodzie pocztowym, NIP czy numerze karty kredytowej w trakcie wpisywania. Właściwość **Prezentacja maski** określamy także w sekcji *Jakość danych*. Używa się tu specjalnej składni (np. cyfry, litery, znaki specjalne) by określić format wyświetlania. **Przykład:** Dla numeru NIP chcemy format `999-999-99-99` – odpowiednie wyrażenie prezentacji maski spowoduje, że użytkownik wpisuje ciąg ciągły cyfr, a na ekranie pojawiają się one w podziale 3-3-2-2 wraz z automatycznie wstawianymi myślnikami. Prezentacja maski dotyczy wyłącznie wyglądu wpisywanych danych dla wygody użytkownika – nie weryfikuje poprawności samej wartości (od tego jest maska regex). Wśród elementów definicji maski występują następujące znaki:
  * **S** - reprezentuje dowolny znak będący literą (A-Z,a-z),
  * **9** - reprezentuje dowolny znak będący liczbą (0-9),
  * **A** - reprezentuje dowolny znak alfanumeryczny (A-Z,a-z,0-9),
  * **?** - elementy maski umieszczone za "?" są opcjonalne.

| Definicja maski        | Znaczenie                                        | Prezentacja maski                   | Przykładowe wartości                       |
| ---------------------- | ------------------------------------------------ | ----------------------------------- | ------------------------------------------ |
| 99-999                 | Kod pocztowy                                     | \_\_-\_\_\_                         | 61-897                                     |
| 99999999999            | PESEL                                            | \_\_\_\_\_\_\_\_\_\_\_              | 75010125915                                |
| 999-999-99-99          | NIP                                              | \_\_\_-\_\_\_-\_\_-\_\_             | 782-22-61-960                              |
| +99 99 99 99 999? w999 | Numer telefonu z opcjonalnym numerem wewnętrznym | +\_\_ \_\_ \_\_ \_\_ \_\_\_ w\_\_\_ | +48 61 41 51 000 lub +48 61 41 51 000 w001 |

### Walidacja po każdym znaku <a href="#walidacjeproste-walidacjapokazdymznaku-validationoneverysign" id="walidacjeproste-walidacjapokazdymznaku-validationoneverysign"></a>

W sekcji **Jakość danych** znajduje się opcja **Walidacja po każdym znaku (validationOnEverySign)** - pozwala na wywołanie walidacji (tylko wymagalność pola oraz maska) na komponencie po każdym wprowadzonym znaku. Wartość domyślna komponentu "false".

{% hint style="info" %}
Wnioski demo: demoRegex, demoPrezentacjaMaski, demoWalidatory
{% endhint %}


# Walidacje złożone (własne)

Walidacje złożone wymagające implementacji algorytmu, implementowane są przez programistów i dołączane do biblioteki walidatorów znajdującej się w **Eximee Validation**. W przypadku gdy walidacja ma się odbywać poprzez usługi zewnętrzne (np. szyna ESB), konieczne jest użycie **Service Proxy** w celu udostępnienia danej usługi.

Jeśli walidacje nie wymagają połączenia z usługami zewnętrznymi, można skorzystać z lekkich walidatorów skryptowych (więcej w: [Walidatory skryptowe (validationScript)](/budowanie-aplikacji/logika-biznesowa/scriptcode/walidatory-skryptowe-validationscript)). Walidatory złożone można stosować dla pól wniosku, stron lub komponentów złożonych (wykorzystywanych później na wniosku).

### Walidacje złożone dla komponentów <a href="#walidacjezlozone-walidacjezlozonedlakomponentow" id="walidacjezlozone-walidacjezlozonedlakomponentow"></a>

Poza wymagalnością i maską, do komponentów można dodawać również specjalizowane walidatory zewnętrzne.

#### **Podpięcie walidatora**

Aby podpiąć walidator, należy wejść w tryb edycji artefaktu i wybrać dowolny komponent mający możliwość podpięcia walidatora. Następnie należy kliknąć sekcję **Jakość danych** w menu właściwości komponentu. Po rozwinięciu sekcji zobaczymy podsekcję **WALIDATORY**.

<figure><img src="/files/PkFtvannsyATLXAy9lN8" alt=""><figcaption><p><em>Ilustracja 1. Sekcja "Jakość danych" z podsekcją WALIDATORY</em></p></figcaption></figure>

Po kliknięciu na **WALIDATORY** lub ikonę ołówka, wysunięte zostanie okno walidatorów.

<figure><img src="/files/gLfPnMCwashCyv5tyXTH" alt=""><figcaption><p align="center"><em><strong>Ilustracja 2.</strong> Okno walidatorów</em></p></figcaption></figure>

Po wybraniu opcji **Wybierz walidator** będziemy mogli wyszukać oraz wybrać dany walidator. Na liście zawarte są standardowe walidatory oraz walidatory skryptowe. Dla walidatora można zdefiniować warunek wywołania (pole **Dodaj warunek**). Jest to warunek JavaScriptowy, w którym można użyć pól lub zmiennych sesyjnych dostępnych na wniosku. Sposób tworzenia warunków został opisany w [Język wyrażeń definiowania warunków (warunki z getValue)](/budowanie-aplikacji/logika-biznesowa/jezyk-wyrazen-definiowania-warunkow-warunki-z-getvalue).

<figure><img src="/files/QxMzsP1zuODs1gR40uq6" alt=""><figcaption><p align="center"><em><strong>Ilustracja 3.</strong> Dodanie walidatora</em></p></figcaption></figure>

#### **Symulacja**

Walidatory, tak samo jak w przypadku usług zewnętrznych, wspierają możliwość zastąpienia ich działania skryptem symulacyjnym. Podpinanie takiego skryptu wymaga wybrania w oknie walidatorów zakładki **Symulacja** oraz wybrania z listy dostępnego skryptu symulacyjnego.

<figure><img src="/files/leHlb20pH1nglDsMwGfa" alt=""><figcaption><p align="center"><em><strong>Ilustracja 4.</strong> Zakładka podpięcia skryptu symulacyjnego</em></p></figcaption></figure>

Z tego poziomu możemy również zdecydować się na utworzenie nowego skryptu klikając przycisk **Generuj nowy skrypt**. Nowo utworzony skrypt będzie miał automatycznie wygenerowaną treść zgodną z walidatorem oraz opisanymi wydzielonymi sekcjami kodu.

<figure><img src="/files/jCla2U9JgvqSRewrscGE" alt=""><figcaption><p align="center"><em><strong>Ilustracja 5.</strong> Tworzenie skryptu symulacyjnego</em></p></figcaption></figure>

Należy pamiętać, że takie skrypty zostaną uruchomione **jedynie** w przypadku wejścia na wniosek z **włączonym** trybem symulacji logiki wniosku!

### Walidacje złożone na stronie <a href="#walidacjezlozone-walidacjezlozonenastronie" id="walidacjezlozone-walidacjezlozonenastronie"></a>

#### **Dodanie walidatorów na stronie**

Walidatory można dodawać również na stronie:

* Jeżeli strona nasłuchuje na pola, które przekazujemy do walidatora, walidator jest wołany przy zmianie pola, na które strona nasłuchuje.
* Jeżeli strona nie będzie nasłuchiwać na pola, walidator zostanie wywołany dopiero po kliknięciu przycisku **Dalej/Wyślij.**\ <br>

<figure><img src="/files/nUlKYb3Fsfr3JYmLbCbb" alt=""><figcaption><p align="center"><em><strong>Ilustracja 6.</strong> Panel właściwości z dodanymi dwoma walidatorami dla strony Page1</em></p></figcaption></figure>

#### **Dodanie** **walidatorów na komponencie złożonym**

Istnieje możliwość dodania walidatorów na komponencie złożonym. Będą one działały tak, jakby były dodane na stronie, na której znajduje się komponent złożony.

### Dodanie tłumaczeń komunikatów walidacji <a href="#walidacjezlozone-dodanietlumaczenkomunikatowwalidacji" id="walidacjezlozone-dodanietlumaczenkomunikatowwalidacji"></a>

Każdy walidator zwraca komunikat walidacyjny. Treść komunikatu może być już przetłumaczona na język polski lub może być w innym języku. Po podpięciu walidatora należ przejść do zakładki **Tłumaczenia** i wyszukać właściwy klucz błędu w celu zmiany tłumaczenia.

Jeśli komunikat walidatora zawiera parametry, to w tłumaczeniu należy je także umieścić w odpowiednim miejscu.

<figure><img src="/files/h9G6BjkAis1IliyYHXYR" alt=""><figcaption><p align="center"><em><strong>Ilustracja 7.</strong> Przykład tłumaczeń komunikatu dla walidatora z przekazywaniem parametrów</em></p></figcaption></figure>

{% hint style="info" %}
Więcej informacji w [Tworzenie walidatorów](/budowanie-aplikacji/logika-biznesowa/scriptcode/walidatory-skryptowe-validationscript/tworzenie-i-podpiecie-walidatorow-skryptowych).
{% endhint %}


# Model danych na interfejsie

### Wiązanie pól formularza z modelem danych

Kiedy model danych jest już zdefiniowany i podpięty, możemy w **formularzu wniosku** powiązać konkretne pola (komponenty UI) z polami modelu. W edytorze formularza każdy komponent, który przechowuje jakąś wartość (np. pole tekstowe, pole wyboru, data itp.), posiada właściwość **"Klucz modelu danych"**.

Jeżeli formularz jest podpięty do aplikacji, klucz można wygodnie wybrać z listy. Gdy na liście nie ma klucza, którego potrzebujemy, można wpisać go ręcznie.

<figure><img src="/files/WOJz0F7Nrwp8pU0QslhV" alt=""><figcaption><p>Ilustracja 1. Wybór klucza modelu danych z listy (z możliwością wpisania ręcznego)</p></figcaption></figure>

Po wskazaniu klucza dane z komponentu zostają związane z odpowiednim miejscem w modelu. Od tego momentu komponent staje się **dwukierunkowo związany** (two-way binding) z modelem danych – podczas inicjalizacji formularza wartość z modelu (jeśli istnieje) zostanie wczytana do pola, a gdy użytkownik wypełni lub zmieni tę wartość, zostanie ona zapisana z powrotem do modelu danych przy zapisie wniosku. Oznacza to, że **po zapisaniu formularza, wszystkie powiązane pola aktualizują odpowiadające im wartości w modelu danych**, dzięki czemu model zawsze odzwierciedla bieżący stan danych wniosku.

<figure><img src="/files/gNjExodM2nfgLyMPgq1d" alt=""><figcaption><p>Ilustracja 1. Przykład dwukierunkowego związania za pomocą klucza modelu danych</p></figcaption></figure>

{% hint style="info" %}
**Info:** Można też stosować **jednokierunkowe powiązanie** pola z modelem w sytuacji, gdy chcemy jedynie wyświetlić wartość z modelu na formularzu, ale nie aktualizować jej na podstawie wejścia użytkownika. Taki jednorazowy odczyt realizuje się np. poprzez wstawienie odwołania do zmiennej modelu w tekstach (etykietach) albo użycie właściwości komponentu **`valueSourceId`**, która pobierze wartość z modelu tylko do odczytu. Standardowo jednak, dla pól edytowalnych korzystamy z powiązania dwustronnego, aby wprowadzone dane zostały zapisane.
{% endhint %}

<figure><img src="/files/OkffjOMUn0yh60ncJRLX" alt=""><figcaption><p>Ilustracja 2. Przykład jednokierunkowego związania za pomocą valueSourceId</p></figcaption></figure>

Należy pamiętać, że **nie każdy komponent formularza można powiązać z modelem**. Model danych ma sens tylko dla pól, które przechowują wartości. W związku z tym nie powiążemy z modelem np. takich elementów jak:

* linki (odnośniki),
* pola typu CAPTCHA,
* pojedyncze przyciski radio (poza grupami radiobuttonów),
* okna popup,
* kody QR (jeśli występują jako obraz/element dekoracyjny).

Wszystkie pozostałe pola (tekstowe, liczbowe, wybory z listy, checkboxy, daty, sekcje itp.) mogą i **powinny** być powiązane z modeliem danych, jeśli ich wartość ma być zachowana lub użyta poza samym formularzem. Powiązanie to zapewnia spójność – każda dana wprowadzona przez użytkownika ma swoje miejsce w modelu, skąd może być dalej przetwarzana (np. przekazana do procesu).

Wartości z modelu danych mogą być wykorzystywane w artefakcie Treść (TextContent) np.

{% code expandable="true" %}

```java
<p>
    Przykładowa treść ${model:client.name}
</p>

```

{% endcode %}

### Obsługa pól tablicowych (list)

Model danych umożliwia definiowanie pól będących kolekcjami (tablicami) obiektów lub wartości prostych. Jeśli w modelu dane pole ma mieć wiele powtórzeń (np. lista adresów, listę produktów, itp.), należy ustawić jego `multiplicityMax` > 1 (np. `null` dla braku górnego limitu) oraz przygotować odpowiednie źródło danych zwracające kolekcję. W formularzu takie pole może być reprezentowane np. przez **Sekcję powtarzalną** (Repeatable Section) z odpowiednimi polami wewnątrz. Ważne jest, by **poprawnie odwoływać się do elementów tablicy** w kluczach modelu:

* `kolekcja[].pole` – odwołanie do *wszystkich* wystąpień pola w kolekcji (zwraca całą listę wartości lub np. konkatenację, zależnie od kontekstu),
* `kolekcja[0].pole` – odwołanie do pola w **pierwszym** elemencie kolekcji (indeks 0 oznacza pierwszy element, 1 - drugi, itd.),
* **Uwaga:** Nie można pomijać indeksu! Składnia `kolekcja.pole` (bez `[]` lub indeksu) jest niepoprawna i spowoduje błąd uniemożliwiający uruchomienie formularza. Zawsze należy użyć notacji tablicowej przy odwołaniu do pól elementów kolekcji.
* Dla sekcji powtarzalnych w formularzu, w których użytkownik może dynamicznie dodawać/usuwać elementy, Eximee używa zmiennej `_rowIdx` przypisanej do danej sekcji, aby przekazywać indeks bieżącego wiersza. W kluczu modelu pojawia się wtedy identyfikator w postaci `NazwaSekcji_rowIdx`. Na przykład, jeżeli sekcja powtarzalna jest powiązana z kolekcją `produkty[]` i ma pole `nazwa`, to klucz pola w sekcji może wyglądać: `produkty[NazwaSekcji_rowIdx].nazwa`. Mechanizm ten zapewnia powiązanie każdego dynamicznie dodanego pola z unikalnym indeksem w modelu.

<figure><img src="/files/Vettv44POa2aOva4TvFO" alt=""><figcaption><p>Ilustracja 3. Podpięcie pola tablicowego do sekcji powtarzalnej</p></figcaption></figure>

<figure><img src="/files/sFOEVJLkL96sYEMUXm6H" alt=""><figcaption><p>Ilustracja 4. Podpięcie Comboboxa znajdującego się w sekcji powtarzalnej do modelu danych</p></figcaption></figure>

### Wykorzystanie modelu w zakładce Jakość danych

Można używać kluczy z modelu danych w zakładce **Jakość danych** do definiowania warunków widoczności, wymagalności lub aktywności.

Należy jednak pamiętać, że jeśli dane pole nasłuchuje zmian w innym polu, każde takie odwołanie będzie powodować ponowne zapytanie do modelu danych, co może negatywnie wpłynąć na wydajność. W takich przypadkach zaleca się pobranie wartości z modelu danych do zmiennej i korzystanie z tej zmiennej w warunkach, co pozwala uniknąć niepotrzebnych odwołań do modelu.

<figure><img src="/files/13kSKuZ62IMWnea1X21L" alt=""><figcaption><p>Ilustracja 5. Warunek widoczności z wykorzystaniem modelu danych</p></figcaption></figure>

### dataModelTransformer

Dzięki **dataModelTransformer**, znajdującym się w xml (zakładka "Źródło") można wpłynąć na dane, które po zapisie wniosku spadną do modelu danych.

Aby wykorzystać tę funkcjonalność, należy w xml (w ecMetadata wewnątrz iftTemplateMetadata) dodać skrypt, który będzie mógł zmodyfikować zapisywany model.

Przykład mapowania zmiennych sesyjnych do modelu danych:

{% code expandable="true" %}

```java
<dataModelTransformer>
  <content>
      function transform(input) {
          input.put('bazaOfert.KredytNr', api.form.v1.value("agreementId"));
          input.put('bazaOfert.CIF', api.form.v1.value("cif"));
          if(api.form.v1.value("GesCheckbox5") == "false"){
              input.put('daneKlientaCis.NumerTelefonu', api.form.v1.value("phoneNumber"));
              input.put('daneKlientaCis.AdresEmail', api.form.v1.value("email"));
          }  
          return input;
      }
  </content>
</dataModelTransformer>
```

{% endcode %}

Przykład mapowania wartości z niewidocznych pól do modelu danych:

{% code expandable="true" %}

```java
<dataModelTransformer>
  <content>
      function transform(input) {
              for (let node of api.form.v1.invisibleFormNodes()) {
                  if(node.model()) {
                      input.put(node.model(), '');
                  }
              }
              return input;
          }
  </content>
</dataModelTransformer>
```

{% endcode %}




---

[Next Page](/llms-full.txt/1)

