mirror of
https://github.com/samply/bridgehead.git
synced 2025-07-01 00:30:20 +02:00
Compare commits
2 Commits
feature/re
...
feature/ex
Author | SHA1 | Date | |
---|---|---|---|
f139651e97 | |||
a689a2f808 |
@ -391,6 +391,7 @@ To learn how to integrate your custom module into Teiler, please refer to https:
|
||||
```bash
|
||||
ENABLE_TEILER=true
|
||||
```
|
||||
[For further information](ccp/modules/teiler.md)
|
||||
|
||||
### Data Exporter Service
|
||||
|
||||
@ -412,6 +413,7 @@ For convenience, it's recommended to enable the Teiler web frontend alongside th
|
||||
ENABLE_TEILER=true
|
||||
ENABLE_EXPORTER=true
|
||||
```
|
||||
[For further information](ccp/modules/exporter.md)
|
||||
|
||||
## Things you should know
|
||||
|
||||
|
@ -1,19 +1,287 @@
|
||||
# Teiler
|
||||
This module orchestrates the different microfrontends of the bridgehead as a single page application.
|
||||
|
||||
**Teiler** is the central frontend of the **bridgehead system**. It brings together multiple independent tools—each built as a **microfrontend**—into a single, unified web application.
|
||||
|
||||
Users interact with Teiler as one coherent interface, but behind the scenes, it dynamically integrates and displays self-contained modules developed with different technologies (**Angular**, **Vue**, **React**, etc.). This modular approach makes Teiler highly flexible, allowing teams to develop, deploy, and maintain features independently.
|
||||
|
||||
Teiler ensures:
|
||||
|
||||
* **A consistent look and feel** across tools.
|
||||
* **Smooth navigation** between components.
|
||||
* **Seamless user authentication** across the entire interface.
|
||||
|
||||
Each independent tool integrated into Teiler is called a **bridgehead app**. A bridgehead app can be:
|
||||
|
||||
- A fully standalone microfrontend with its own frontend and backend services.
|
||||
- An embedded service inside the Teiler Dashboard.
|
||||
- An external link to another service, possibly hosted on a central server or elsewhere in the federated research network.
|
||||
|
||||
The modularity of Teiler enables it to adapt easily to the evolving needs of the research federated network by simply adding, updating, or removing bridgehead apps.
|
||||
|
||||
Below is a breakdown of Teiler's internal components that make this orchestration possible.
|
||||
|
||||
- [Teiler Orchestrator](#teiler-orchestrator)
|
||||
- [Teiler Dashboard](#teiler-dashboard)
|
||||
- [Teiler Backend](#teiler-backend)
|
||||
|
||||
---
|
||||
|
||||
## Teiler Orchestrator
|
||||
Single SPA component that consists on the root HTML site of the single page application and a javascript code that
|
||||
gets the information about the microfrontend calling the teiler backend and is responsible for registering them. With the
|
||||
resulting mapping, it can initialize, mount and unmount the required microfrontends on the fly.
|
||||
|
||||
**GitHub repository:** [https://github.com/samply/teiler-orchestrator](https://github.com/samply/teiler-orchestrator)
|
||||
|
||||
The **Teiler Orchestrator** is the entry point of the **Single Page Application (SPA)**. It consists of:
|
||||
|
||||
The microfrontends run independently in different containers and can be based on different frameworks (Angular, Vue, React,...)
|
||||
This microfrontends can run as single alone but need an extension with Single-SPA (https://single-spa.js.org/docs/ecosystem).
|
||||
There are also available three templates (Angular, Vue, React) to be directly extended to be used directly in the teiler.
|
||||
- An **HTML root page**.
|
||||
- A **JavaScript layer** that:
|
||||
- **Retrieves microfrontend configurations** from the backend.
|
||||
- **Registers and manages** the microfrontends using [**Single-SPA**](https://single-spa.js.org/), the framework Teiler uses to create and coordinate its microfrontend environment.
|
||||
|
||||
Using this information, the orchestrator dynamically **loads the correct microfrontend** for a given route and manages its **lifecycle** (*init*, *mount*, *unmount*) in real time.
|
||||
|
||||
**Microfrontends** run in their own containers and can be implemented with any major frontend framework. To be compatible with Teiler, they must integrate with **Single-SPA**.
|
||||
|
||||
To encourage developers to create their own microfrontends and integrate them into Teiler, we provide **starter templates** for **Angular**, **Vue**, and **React**. Developing a new microfrontend is straightforward:
|
||||
|
||||
1. Use one of the templates.
|
||||
2. Extend it with your own functionality.
|
||||
3. Add its configuration in the **Teiler Backend**.
|
||||
|
||||
This modular approach accelerates development and fosters collaboration.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Teiler Dashboard
|
||||
It consists on the main dashboard and a set of embedded services.
|
||||
### Login
|
||||
user and password in ccp.local.conf
|
||||
|
||||
**GitHub repository:** [https://github.com/samply/teiler-dashboard](https://github.com/samply/teiler-dashboard)
|
||||
|
||||
The **Teiler Dashboard** is the unified interface users interact with after logging in. It provides:
|
||||
|
||||
- A **single point of access** where various bridgehead apps are embedded as microfrontends.
|
||||
- **Central navigation** and **session management** for a smooth user experience.
|
||||
|
||||
### Authentication and Authorization
|
||||
|
||||
Teiler uses **OpenID Connect (OIDC)** for user authentication, accessible via the **top navigation bar**.
|
||||
|
||||
We consider three possible **application roles**:
|
||||
|
||||
| Role | Description |
|
||||
|--------|-----------------------------------------------------------|
|
||||
| Public | Accessible by any user without the need to log in |
|
||||
| User | Normal users working with various bridgehead applications |
|
||||
| Admin | Bridgehead system administrators |
|
||||
|
||||
It is possible to **deactivate OIDC authentication** entirely. In such cases, **all apps must have at least the public role** to allow access. While this may be suitable for development or testing, we **strongly encourage** at least some external authentication mechanism or network-level access control to secure the bridgehead environment.
|
||||
|
||||
Alternatively, basic authentication can be enforced through the existing **Traefik infrastructure** integrated with the bridgehead.
|
||||
|
||||
---
|
||||
|
||||
## Teiler Backend
|
||||
In this component, the microfrontends are configured.
|
||||
|
||||
**GitHub repository:** [https://github.com/samply/teiler-backend](https://github.com/samply/teiler-backend)
|
||||
|
||||
The **Teiler Backend** serves as the central configuration hub for all microfrontends and bridgehead apps. It defines:
|
||||
|
||||
- Which bridgehead apps are available.
|
||||
- Their loading URLs and routes.
|
||||
- Optional metadata such as display names, icons, roles, and activation status.
|
||||
|
||||
It enables the orchestrator to remain **generic and flexible**, adapting dynamically to whatever apps are defined in the backend configuration.
|
||||
|
||||
### Assets Directory
|
||||
|
||||
There is an **assets** directory where you can save images and other static files to be accessible to your microfrontends. This helps configure and customize apps more easily and quickly.
|
||||
|
||||
Assets can be referenced via:
|
||||
|
||||
```
|
||||
<Teiler Backend URL>/assets/<filename>
|
||||
```
|
||||
|
||||
### App Configuration via Environment Variables
|
||||
|
||||
Apps are configured using environment variables with the following structure:
|
||||
|
||||
```
|
||||
TEILER_APP<Number>_<suffix>
|
||||
Optional: TEILER_APP<Number>_<LanguageCode>_<suffix>
|
||||
```
|
||||
|
||||
- The **number** is just for grouping variables for a single app and has no intrinsic meaning.
|
||||
- The **app** is the unit within Teiler, shown as a box in the dashboard.
|
||||
- Apps can be:
|
||||
- Embedded apps inside the Teiler Dashboard (there is a helper Python script for generating embedded apps: [create-embedded-app.py](https://github.com/samply/teiler-dashboard/blob/main/create-embedded-app.py))
|
||||
- External links (e.g., central services outside the local bridgehead instance)
|
||||
- An app's frontend (microfrontend or embedded app) can either contain the entire functionality or serve as a frontend communicating with other backend microservices in the bridgehead.
|
||||
|
||||
Currently supported languages in the main projects DKTK and BBMRI are **English (EN)** and **German (DE)**, but the system can be extended to other languages.
|
||||
|
||||
The Teiler Dashboard requests variables from the backend for each app and passes the desired language code. If a language-specific variable is unavailable, the default language value is returned.
|
||||
|
||||
### Internationalization (i18n)
|
||||
#### ⚠️ Important
|
||||
|
||||
If you make any changes to the **Teiler Dashboard**, and those changes involve text elements (e.g., labels, buttons, messages), you must also update the **English translations**, since the application uses **internationalization (i18n)**.
|
||||
|
||||
The **default language** of the project is **German**, so any new text must be manually translated into English after extracting the updated i18n entries.
|
||||
|
||||
To extract new translation entries, run the following command:
|
||||
|
||||
```bash
|
||||
ng extract-i18n --output-path src/i18n --format=xlf2
|
||||
````
|
||||
|
||||
This will generate or update the file:
|
||||
`src/i18n/messages.xlf`
|
||||
|
||||
---
|
||||
|
||||
#### ✅ Requirements to Run the Extraction Command
|
||||
|
||||
| Program | Purpose | Linux Shell (Ubuntu/Debian) | Windows PowerShell |
|
||||
| -------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
||||
| **Node.js** | JavaScript runtime required by Angular and npm | `sudo apt update && sudo apt install nodejs npm`<br>**or**<br>[Use NodeSource setup](https://github.com/nodesource/distributions) (recommended) | [Download from nodejs.org](https://nodejs.org) and install manually |
|
||||
| **npm** | Node package manager (comes with Node.js) | *(Included with Node.js)* | *(Included with Node.js)* |
|
||||
| **Angular CLI** | Command-line interface for Angular tooling | `npm install -g @angular/cli` | `npm install -g @angular/cli` |
|
||||
| **Angular project dependencies** | Required packages from `package.json` | `npm install` | `npm install` |
|
||||
|
||||
---
|
||||
|
||||
#### ✏️ Updating the English Translation
|
||||
|
||||
After running the extraction command, the file `src/i18n/messages.xlf` will contain any newly added i18n entries.
|
||||
|
||||
To provide English translations:
|
||||
|
||||
1. Open `src/i18n/messages.en.xlf`.
|
||||
2. Compare it with the updated `messages.xlf` to identify any new entries.
|
||||
3. Copy the new `<trans-unit>` blocks from `messages.xlf` into `messages.en.xlf`.
|
||||
4. For each entry, add the English translation inside the `<target>` tag (in `messages.en.xlf`):
|
||||
|
||||
```xml
|
||||
<trans-unit id="..." datatype="html">
|
||||
<source>Willkommen</source>
|
||||
<target>Welcome</target>
|
||||
</trans-unit>
|
||||
```
|
||||
|
||||
### App Availability Monitoring
|
||||
|
||||
The Teiler Backend regularly **pings apps** to check availability and displays status messages such as:
|
||||
|
||||
- "Frontend not available"
|
||||
- "Backend not available"
|
||||
- "Frontend and Backend not available"
|
||||
|
||||
### Accepted TEILER_APP Variable Suffixes
|
||||
|
||||
| Suffix | Description |
|
||||
|------------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| NAME | Identifier of the app (no spaces). For embedded apps, must match the identifier defined in Teiler Dashboard. |
|
||||
| TITLE | Display title shown to users. |
|
||||
| DESCRIPTION | Brief description of the app. |
|
||||
| BACKENDURL | URL of the backend microservice (if applicable). |
|
||||
| BACKENDCHECKURL | URL that the backend pings to verify backend availability. Defaults to BACKENDURL if not specified. |
|
||||
| SOURCEURL | URL of the microfrontend or external link (not used for embedded apps). |
|
||||
| SOURCECHECKURL | URL to ping to check microfrontend or external link availability. Defaults to SOURCEURL if not specified. |
|
||||
| ROLES | Comma-separated roles allowed: `TEILER_PUBLIC`, `TEILER_USER`, `TEILER_ADMIN`. |
|
||||
| ISACTIVATED | `true` or `false`. Used to temporarily deactivate an app without deleting its config. |
|
||||
| ICONCLASS | Bootstrap icon class to display in app box (e.g., `"bi bi-search"`). |
|
||||
| ICONSOURCEURL | URL to an image icon. Prefer using local assets instead of external URLs. |
|
||||
| ORDER | Relative display order of the app in the dashboard. |
|
||||
| ISEXTERNALLINK | `true` or `false`. Indicates if the app is an external link outside the local bridgehead. |
|
||||
| ISLOCAL | `true` or `false`. Indicates if the app runs locally within the bridgehead site or on a central server. |
|
||||
|
||||
*Note:* Embedded apps often have many of these variables preconfigured and may not require manual specification. See the [Teiler Dashboard documentation](https://github.com/samply/teiler-dashboard) for details.
|
||||
|
||||
### Additional Teiler Backend Variables for Dashboard Configuration
|
||||
|
||||
| Variable Prefix | Description |
|
||||
|------------------------------------|--------------------------------------------------------------------------------------------------------------|
|
||||
| TEILER_DASHBOARD_ | General configuration of the dashboard. |
|
||||
| TEILER_DASHBOARD_<LangCode>_ | Language-specific configuration overrides. |
|
||||
|
||||
Important suffixes include:
|
||||
|
||||
| Suffix | Description |
|
||||
|------------------|-------------------------------------------------------------------------------------------|
|
||||
| WELCOME_TITLE | Title shown on the initial screen before login. |
|
||||
| WELCOME_TEXT | Welcome message or instructions before login. |
|
||||
| FURTHER_INFO | Additional informational text or links. |
|
||||
| BACKGROUND_IMAGE_URL | URL to a background image (SVG recommended for scalability). |
|
||||
| LOGO_URL | URL to the project or bridgehead logo. |
|
||||
| LOGO_HEIGHT | Height of the displayed logo. |
|
||||
| LOGO_TEXT | Title text of the bridgehead (e.g., "DKTK Bridgehead"). |
|
||||
| COLOR_PALETTE | JSON link to color palettes for text, lines, icons, and background (especially for SVGs). |
|
||||
| COLOR_PROFILE | Selected color profile from the palette. (color palette name) |
|
||||
| FONT | Font family for the dashboard text. |
|
||||
|
||||
### 🎨 Color Palette
|
||||
|
||||
Below is an example of a **color palette** definition in JSON format:
|
||||
|
||||
```json
|
||||
{
|
||||
"color-palettes": [
|
||||
{
|
||||
"name": "Grey",
|
||||
"colors": {
|
||||
"text": "grey",
|
||||
"line": "grey",
|
||||
"icon": "grey",
|
||||
"background": "grey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Black",
|
||||
"colors": {
|
||||
"text": "black",
|
||||
"line": "black",
|
||||
"icon": "black",
|
||||
"background": "#F7ADAD"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Each palette contains a unique `name` and a set of color values for different UI elements.
|
||||
|
||||
#### 🔍 Palette Elements
|
||||
|
||||
| **Variable** | **Description** |
|
||||
| ------------ | --------------------------------------------------- |
|
||||
| `name` | Identifier of the color palette |
|
||||
| `text` | Color used for text |
|
||||
| `line` | Color used for lines (e.g., borders, dividers) |
|
||||
| `icon` | Color used for icons |
|
||||
| `background` | Background color (especially useful for SVG images) |
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 🚀 Ready to Extend Teiler?
|
||||
|
||||
If you want to create your own **bridgehead app** and integrate it into **Teiler**, start by:
|
||||
|
||||
1. Selecting a template **or**
|
||||
2. Building a microfrontend compatible with [Single-SPA](https://single-spa.js.org/).
|
||||
|
||||
Then, register your app’s configuration in the **Teiler Backend** as described above.
|
||||
|
||||
> 💡 **Tip:** This flexible, modular design makes it easy to plug in your own features and services.
|
||||
|
||||
---
|
||||
|
||||
### 🔧 Build & Contribute Your App!
|
||||
|
||||
🧩 **Join the ecosystem!**
|
||||
Add your app to Teiler and expand its functionality for everyone.
|
||||
|
||||
Whether it’s a visualization tool, a data processing module, or a custom UI component — your contribution can help grow the platform. 💪
|
||||
|
||||
> 👉 **Get started today and shape the future of Teiler!**
|
||||
|
||||
|
@ -1,15 +1,345 @@
|
||||
# Exporter and Reporter
|
||||
|
||||
---
|
||||
|
||||
## Exporter
|
||||
The exporter is a REST API that exports the data of the different databases of the bridgehead in a set of tables.
|
||||
It can accept different output formats as CSV, Excel, JSON or XML. It can also export data into Opal.
|
||||
|
||||
**GitHub:** [https://github.com/samply/exporter](https://github.com/samply/exporter)
|
||||
|
||||
The Exporter is a **REST API** that enables the export of data from various **bridgehead databases** as **structured tables**. It currently supports only **FHIR sources** such as **Blaze**, but it is designed to be extended to **other types** of data sources. The Exporter provides multiple output formats, including **CSV, Excel, JSON, and XML**, and can also export data directly into **Opal (DataSHIELD)**.
|
||||
|
||||
### How it works
|
||||
|
||||
The **user** submits a **query** and specifies the desired **export template** and **output format**. The **query** acts like the `WHERE` clause in SQL, filtering data, while the **template** defines what data to select and how to format it, similar to the `SELECT` clause. The Exporter then processes this to generate the export files.
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Below is a list of configurable environment variables used by the Exporter:
|
||||
|
||||
| Variable | Default | Description |
|
||||
| --------------------------------------------------------- | ------------------------------------------- | ---------------------------------------------------------- |
|
||||
| APPLICATION\_PORT | 8092 | Port on which the application runs. |
|
||||
| ARCHIVE\_EXPIRED\_QUERIES\_CRON\_EXPRESSION | `0 0 2 * * *` | Cron expression for archiving expired queries. |
|
||||
| CLEAN\_TEMP\_FILES\_CRON\_EXPRESSION | `0 0 1 * * *` | Cron expression for cleaning temporary files. |
|
||||
| CLEAN\_WRITE\_FILES\_CRON\_EXPRESSION | `0 0 2 * * *` | Cron expression for cleaning written files. |
|
||||
| CONVERTER\_TEMPLATE\_DIRECTORY | | Directory containing conversion templates. |
|
||||
| CONVERTER\_XML\_APPLICATION\_CONTEXT\_PATH | | Path to the XML application context used by the converter. |
|
||||
| CROSS\_ORIGINS | | Allowed CORS origins (comma-separated). |
|
||||
| CSV\_SEPARATOR\_REPLACEMENT | | Character to replace CSV separators within values. |
|
||||
| EXCEL\_WORKBOOK\_WINDOW | 30000000 | Memory window size for Excel workbook processing. |
|
||||
| EXPORTER\_API\_KEY | | API key for authenticating access to the exporter. |
|
||||
| EXPORTER\_DB\_FLYWAY\_MIGRATION\_ENABLED | true | Enable Flyway DB migrations on startup. |
|
||||
| EXPORTER\_DB\_PASSWORD | | Password for exporter database. |
|
||||
| EXPORTER\_DB\_URL | `jdbc:postgresql://localhost:5432/exporter` | JDBC URL for exporter DB. |
|
||||
| EXPORTER\_DB\_USER | | Username for exporter DB. |
|
||||
| FHIR\_PACKAGES\_DIRECTORY | | Directory where FHIR packages are stored. |
|
||||
| HAPI\_FHIR\_CLIENT\_LOG\_LEVEL | OFF | Log level for HAPI FHIR client. |
|
||||
| HIBERNATE\_LOG | false | Enable Hibernate SQL logging. |
|
||||
| HTTP\_RELATIVE\_PATH | | Relative base path for HTTP endpoints. |
|
||||
| HTTP\_SERVLET\_REQUEST\_SCHEME | http | Default HTTP scheme. |
|
||||
| LOG\_FHIR\_VALIDATION | | Enable logging of FHIR validation results. |
|
||||
| LOG\_LEVEL | INFO | Application log level. |
|
||||
| MAX\_NUMBER\_OF\_EXCEL\_ROWS\_IN\_A\_SHEET | 100000 | Max rows per Excel sheet. |
|
||||
| MAX\_NUMBER\_OF\_RETRIES | 10 | Max retry attempts. |
|
||||
| MERGE\_FILENAME | | Name of merged output file. |
|
||||
| SITE | | Site identifier for filenames/logs. |
|
||||
| TEMP\_FILES\_LIFETIME\_IN\_DAYS | 1 | Lifetime of temporary files (days). |
|
||||
| TEMPORAL\_FILE\_DIRECTORY | | Directory for temporary files. |
|
||||
| TIMEOUT\_IN\_SECONDS | 10 | Default timeout (seconds). |
|
||||
| TIMESTAMP\_FORMAT | | Timestamp format string. |
|
||||
| WEBCLIENT\_BUFFER\_SIZE\_IN\_BYTES | 8192 | Buffer size for web client. |
|
||||
| WEBCLIENT\_CONNECTION\_TIMEOUT\_IN\_SECONDS | 5 | Connection timeout (seconds). |
|
||||
| WEBCLIENT\_MAX\_NUMBER\_OF\_RETRIES | 10 | Max retries for web client. |
|
||||
| WEBCLIENT\_REQUEST\_TIMEOUT\_IN\_SECONDS | 10 | Request timeout (seconds). |
|
||||
| WEBCLIENT\_TCP\_KEEP\_CONNECTION\_NUMBER\_OF\_TRIES | 3 | TCP keepalive retry attempts. |
|
||||
| WEBCLIENT\_TCP\_KEEP\_IDLE\_IN\_SECONDS | 30 | TCP keepalive idle time (seconds). |
|
||||
| WEBCLIENT\_TCP\_KEEP\_INTERVAL\_IN\_SECONDS | 10 | TCP keepalive probe interval (seconds). |
|
||||
| WEBCLIENT\_TIME\_IN\_SECONDS\_AFTER\_RETRY\_WITH\_FAILURE | 1 | Wait time after failed retry (seconds). |
|
||||
| WRITE\_FILE\_DIRECTORY | | Directory for final output files. |
|
||||
| WRITE\_FILES\_LIFETIME\_IN\_DAYS | 30 | Lifetime of written files (days). |
|
||||
| XML\_FILE\_MERGER\_ROOT\_ELEMENT | Containers | Root element for XML file merging. |
|
||||
| ZIP\_FILENAME | `exporter-files-${SITE}-${TIMESTAMP}.zip` | Pattern for ZIP archive naming. |
|
||||
|
||||
---
|
||||
|
||||
### About Cron Expressions in Spring
|
||||
|
||||
Cron expressions configure scheduled tasks and consist of six space-separated fields representing second, minute, hour, day of month, month, and day of week. For example, the default `0 0 2 * * *` means “at 2:00 AM every day.” These expressions allow precise scheduling for maintenance tasks such as cleaning files or archiving data.
|
||||
|
||||
---
|
||||
|
||||
## Exporter-DB
|
||||
It is a database to save queries for its execution in the exporter.
|
||||
The exporter manages also the different executions of the same query in through the database.
|
||||
|
||||
**GitHub:** [https://github.com/samply/exporter-db](https://github.com/samply/exporter-db) (If exists; if not, just remove or adjust accordingly)
|
||||
|
||||
The Exporter-DB stores queries for execution by the Exporter and tracks multiple executions of the same query, managing versioning and scheduling.
|
||||
|
||||
---
|
||||
|
||||
## Reporter
|
||||
This component is a plugin of the exporter that allows to create more complex Excel reports described in templates.
|
||||
It is compatible with different template engines as Groovy, Thymeleaf,...
|
||||
It is perfect to generate a document as our traditional CCP quality report.
|
||||
|
||||
**GitHub:** [https://github.com/samply/reporter](https://github.com/samply/reporter)
|
||||
|
||||
The Reporter is a **plugin for the Exporter** designed for generating **complex Excel reports** based on **customizable templates**. It supports various template engines like **Groovy** and **Thymeleaf**, making it ideal for producing detailed documents such as the traditional CCP **data quality report**.
|
||||
|
||||
---
|
||||
|
||||
## Exporter Templates
|
||||
|
||||
An exporter template describes the **structure** and **content** of the **export output**.
|
||||
|
||||
### Main Elements
|
||||
|
||||
* **converter**: Defines the export job, specifying output files and data sources.
|
||||
* **container**: Represents a logical grouping of data rows (like a table).
|
||||
* **attribute**: Defines individual data fields/columns extracted from the data source.
|
||||
|
||||
### Other Elements
|
||||
|
||||
* **cql**: Contains Clinical Quality Language metadata used to enrich or filter data.
|
||||
* **fhir-rev-include**: Defines FHIR reverse includes to fetch related resources.
|
||||
* **fhir-package**: (To be detailed)
|
||||
* **fhir-terminology-server**: (To be detailed)
|
||||
|
||||
### Example Snippet
|
||||
|
||||
```xml
|
||||
<converter id="ccp" excel-filename="Export-${SITE}-${TIMESTAMP}.xlsx" source-id="blaze-store" >
|
||||
<container id="Patient" csv-filename="Patient-${SITE}-${TIMESTAMP}.csv" excel-sheet="Patient" xml-filename="Patient-${SITE}-${TIMESTAMP}.xml" xml-root-element="Patients" xml-element="Patient" json-filename="Patient-${SITE}-${TIMESTAMP}.json" json-key="Patients" >
|
||||
<attribute id="Patient-ID" default-name="PatientID" val-fhir-path="Patient.id.value" anonym="Pat" op="EXTRACT_RELATIVE_ID"/>
|
||||
|
||||
<attribute default-name="DKTKIDGlobal" val-fhir-path="Patient.identifier.where(type.coding.code = 'Global').value.value"/>
|
||||
<attribute default-name="DKTKIDLokal" val-fhir-path="Patient.identifier.where(type.coding.code = 'Lokal').value.value" />
|
||||
<attribute default-name="DateOfBirth" val-fhir-path="Patient.birthDate.value.toString().substring(0, 4) + '-01-01'"/>
|
||||
<attribute default-name="Gender" val-fhir-path="Patient.gender.value" />
|
||||
</container>
|
||||
|
||||
<container id="Diagnosis" csv-filename="Diagnosis-${SITE}-${TIMESTAMP}.csv" excel-sheet="Diagnosis" xml-filename="Diagnosis-${SITE}-${TIMESTAMP}.xml" xml-root-element="Diagnoses" xml-element="Diagnosis" json-filename="Diagnosis-${SITE}-${TIMESTAMP}.json" json-key="Diagnoses">
|
||||
<attribute id="Diagnosis-ID" default-name="DiagnosisID" val-fhir-path="Condition.id.value" anonym="Dia" op="EXTRACT_RELATIVE_ID"/>
|
||||
<attribute id="Patient-ID" link="Patient.Patient-ID" default-name="PatientID" val-fhir-path="Condition.subject.reference.value" anonym="Pat"/>
|
||||
|
||||
<attribute default-name="ICD10Code" val-fhir-path="Condition.code.coding.code.value"/>
|
||||
<attribute default-name="ICDOTopographyCode" val-fhir-path="Condition.bodySite.coding.where(system = 'urn:oid:2.16.840.1.113883.6.43.1').code.value"/>
|
||||
<attribute default-name="LocalizationSide" val-fhir-path="Condition.bodySite.coding.where(system = 'http://dktk.dkfz.de/fhir/onco/core/CodeSystem/SeitenlokalisationCS').code.value"/>
|
||||
</container>
|
||||
|
||||
<container id="Histology" csv-filename="Histology-${SITE}-${TIMESTAMP}.csv" excel-sheet="Histology" xml-filename="Histology-${SITE}-${TIMESTAMP}.xml" xml-root-element="Histologies" xml-element="Histology" json-filename="Histology-${SITE}-${TIMESTAMP}.json" json-key="Histologies" >
|
||||
<attribute id="Histology-ID" default-name="HistologyID" val-fhir-path="Observation.where(code.coding.code = '59847-4').id" anonym="His" op="EXTRACT_RELATIVE_ID"/>
|
||||
<attribute id="Diagnosis-ID" link="Diagnosis.Diagnosis-ID" default-name="DiagnosisID" val-fhir-path="Observation.where(code.coding.code = '59847-4').focus.reference.value" anonym="Dia"/>
|
||||
<attribute id="Patient-ID" link="Patient.Patient-ID" default-name="PatientID" val-fhir-path="Observation.where(code.coding.code = '59847-4').subject.reference.value" anonym="Pat" />
|
||||
|
||||
<attribute default-name="ICDOMorphologyCode" val-fhir-path="Observation.where(code.coding.code = '59847-4').value.coding.code.value"/>
|
||||
<attribute default-name="Grading" val-fhir-path="Observation.where(code.coding.code = '59542-1').value.coding.code.value" join-fhir-path="Observation.where(code.coding.code = '59847-4').hasMember.reference.value"/>
|
||||
</container>
|
||||
|
||||
<container id="Radiation-Therapy" csv-filename="RadiationTherapy-${SITE}-${TIMESTAMP}.csv" excel-sheet="RadiationTherapy" xml-filename="RadiationTherapy-${SITE}-${TIMESTAMP}.xml" xml-root-element="Radiation-Therapies" xml-element="Radiation-Therapy" json-filename="RadiationTherapy-${SITE}-${TIMESTAMP}.json" json-key="Radiation Therapies">
|
||||
<attribute id="Radiation-Therapy-ID" default-name="RadiationTherapyID" val-fhir-path="Procedure.where(category.coding.code = 'ST').id" anonym="Rad" op="EXTRACT_RELATIVE_ID"/>
|
||||
<attribute id="Diagnosis-ID" link="Diagnosis.Diagnosis-ID" default-name="DiagnosisID" val-fhir-path="Procedure.where(category.coding.code = 'ST').reasonReference.reference.value" anonym="Dia"/>
|
||||
<attribute id="Patient-ID" link="Patient.Patient-ID" default-name="PatientID" val-fhir-path="Procedure.where(category.coding.code = 'ST').subject.reference.value" anonym="Pat" />
|
||||
|
||||
<attribute default-name="RadiationTherapyRelationToSurgery" val-fhir-path="Procedure.extension('http://dktk.dkfz.de/fhir/StructureDefinition/onco-core-Extension-StellungZurOp').value.coding.code.value"/>
|
||||
<attribute default-name="RadiationTherapyIntention" val-fhir-path="Procedure.extension('http://dktk.dkfz.de/fhir/StructureDefinition/onco-core-Extension-SYSTIntention').value.coding.code.value" />
|
||||
<attribute default-name="RadiationTherapyStart" val-fhir-path="Procedure.where(category.coding.code = 'ST').performed.start.value"/>
|
||||
<attribute default-name="RadiationTherapyEnd" val-fhir-path="Procedure.where(category.coding.code = 'ST').performed.end.value"/>
|
||||
<attribute default-name="Nebenwirkung Grad" val-fhir-path="AdverseEvent.severity.coding.code.value" join-fhir-path="/AdverseEvent.suspectEntity.instance.reference.where(value.startsWith('Procedure')).value" />
|
||||
</container>
|
||||
|
||||
|
||||
<cql>
|
||||
<default-fhir-search-query>Patient</default-fhir-search-query>
|
||||
|
||||
<token key="DKTK_STRAT_MEDICATION_STRATIFIER" value="define MedicationStatement: if InInitialPopulation then [MedicationStatement] else {} as List <MedicationStatement> " />
|
||||
<token key="DKTK_STRAT_PRIMARY_DIAGNOSIS_NO_SORT_STRATIFIER" value="define PrimaryDiagnosis: First( from [Condition] C where C.extension.where(url='http://hl7.org/fhir/StructureDefinition/condition-related').empty()) " />
|
||||
|
||||
<measure-parameters>
|
||||
{
|
||||
"resourceType": "Parameters",
|
||||
"parameter": [
|
||||
{
|
||||
"name": "periodStart",
|
||||
"valueDate": "2000"
|
||||
},
|
||||
{
|
||||
"name": "periodEnd",
|
||||
"valueDate": "2030"
|
||||
},
|
||||
{
|
||||
"name": "reportType",
|
||||
"valueCode": "subject-list"
|
||||
}
|
||||
]
|
||||
}
|
||||
</measure-parameters>
|
||||
</cql>
|
||||
|
||||
|
||||
|
||||
<fhir-rev-include>Observation:patient</fhir-rev-include>
|
||||
<fhir-rev-include>Condition:patient</fhir-rev-include>
|
||||
<fhir-rev-include>ClinicalImpression:patient</fhir-rev-include>
|
||||
<fhir-rev-include>MedicationStatement:patient</fhir-rev-include>
|
||||
<fhir-rev-include>Procedure:patient</fhir-rev-include>
|
||||
<fhir-rev-include>Specimen:patient</fhir-rev-include>
|
||||
<fhir-rev-include>AdverseEvent:subject</fhir-rev-include>
|
||||
<fhir-rev-include>CarePlan:patient</fhir-rev-include>
|
||||
|
||||
</converter>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1. **Converter**
|
||||
|
||||
Main tag of an exporter template grouping converters to find the best chain for data conversion.
|
||||
|
||||
| Tag | Description |
|
||||
| ------------- | --------------------------------------------------------------------------------------------- |
|
||||
| `<converter>` | Main tag for exporter template containing sources, metadata, and additional query information |
|
||||
|
||||
| Attribute | Description | Example | Default |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------- | --------------------------------------------------- | ------- |
|
||||
| id | ID to reference a template | `id="ccp-opal"` | — |
|
||||
| default-name | Default name when output is in a single file format (no extension; added automatically) | — | — |
|
||||
| ignore | Deactivate template but keep accessible | `ignore="true"` | false |
|
||||
| excel-filename | Name of the Excel output file (supports variables `${SITE}`, `${TIMESTAMP}`) | `excel-filename="Export-${SITE}-${TIMESTAMP}.xlsx"` | — |
|
||||
| csv-separator | CSV separator character | — | `"\t"` |
|
||||
| source-id | ID of the data source | `source-id="blaze-store"` | — |
|
||||
| target-id | ID of a target server for file transfer (e.g., Opal for DataSHIELD) | `target-id="opal"` | — |
|
||||
| opal-project | Opal-specific: name of project | — | — |
|
||||
| opal-permission-type | Opal permission type (`user` or `group`) | — | — |
|
||||
| opal-permission-subjects | Opal permission subjects | — | — |
|
||||
| opal-permission | Opal permission (`administrate` or `use`) | — | — |
|
||||
|
||||
**Notes:**
|
||||
* You can use variables such as `${SITE}`, `${TIMESTAMP}`, and other environment variables within tags.
|
||||
* To define environment variables for a specific export, use the HTTP parameter **`CONTEXT`**.
|
||||
The value must be a Base64-encoded string containing comma-separated key-value pairs.
|
||||
* **Example:**
|
||||
Plain: `KEY1=VALUE1,KEY2=VALUE2`
|
||||
Base64: `S0VZMT1WQUxVRTEsS0VZMj1WQUxVRTI=`
|
||||
|
||||
**Allowed child elements:**
|
||||
|
||||
* `<container>`, `<cql>`, `<fhir-rev-include>`, `<fhir-package>`, `<fhir-terminology-server>`
|
||||
|
||||
---
|
||||
|
||||
### 2. **Container**
|
||||
|
||||
Represents a data table with columns (attributes).
|
||||
|
||||
| Tag | Description |
|
||||
| ------------- | --------------------------------------------------- |
|
||||
| `<container>` | Defines a container/table with attributes (columns) |
|
||||
|
||||
| Attribute | Description | Example | Default |
|
||||
| ---------------- | ------------------------------------------------------------ | --------------------------------------------- | ------- |
|
||||
| id | Container ID to reference | — | — |
|
||||
| default-name | Name of Excel sheet/file (no extension, added automatically) | — | — |
|
||||
| csv-filename | Name of CSV file | `csv-filename="Diagnosis-${TIMESTAMP}.csv"` | — |
|
||||
| json-filename | Name of JSON file | `json-filename="diagnosis-${TIMESTAMP}.json"` | — |
|
||||
| xml-filename | Name of XML file | `xml-filename="diagnosis-${TIMESTAMP}.xml"` | — |
|
||||
| xml-root-element | Root element name in XML | `xml-root-element="diagnoses"` | — |
|
||||
| xml-element | Element name for each entry in XML | `xml-element="diagnosis"` | — |
|
||||
| excel-sheet | Excel sheet name | `excel-sheet="diagnosis-${TIMESTAMP}.xlsx"` | — |
|
||||
| opal-table | Opal table name | `opal-name="Diagnosis"` | — |
|
||||
| opal-entity-type | Opal entity type | — | — |
|
||||
|
||||
---
|
||||
|
||||
### 3. **Attribute**
|
||||
|
||||
Represents a column in a container/table.
|
||||
|
||||
| Tag | Description |
|
||||
| ------------- | --------------------------- |
|
||||
| `<attribute>` | Defines an attribute/column |
|
||||
|
||||
| Attribute | Description | Example | Default |
|
||||
| ------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------- |
|
||||
| id | Attribute ID | `id="Patient-ID"` | — |
|
||||
| default-name | Default name of the attribute (used if no output-specific name provided) | — | — |
|
||||
| link | Reference to an attribute of another container (format: `<container-name>.<attribute-id>`) | `link="Patient.Patient-ID"` | — |
|
||||
| csv-column | Name of the CSV column | — | — |
|
||||
| excel-column | Name of the Excel column | — | — |
|
||||
| json-key | JSON key | — | — |
|
||||
| xml-element | XML element name | — | — |
|
||||
| opal-value-type | Opal-specific value type | — | — |
|
||||
| opal-script | Script to be applied to the field in Opal | — | — |
|
||||
| primary-key | Marks attribute as primary key | `primary-key="true"` | false |
|
||||
| validation | Marks attribute as syntactic validation field (ends with `-Validation` in DKTK/BBMRI reporter) | `validation="true"` | false |
|
||||
| val-fhir-path | FHIR path to extract value (if source is a FHIR server) | `val-fhir-path="Patient.gender.value"` | — |
|
||||
| join-fhir-path | FHIR path for joining secondary resources to main resource | `join-fhir-path="/AdverseEvent.suspectEntity.instance.reference.where(value.startsWith('Procedure')).value"` | — |
|
||||
| condition-value-fhir-path | Condition filtering for complex value extraction (FHIR path syntax) | `condition-value-fhir-path="Patient.birthDate <= today() - 18 'years'"` | — |
|
||||
| anonym | Anonymization prefix; replaces real value with `anonym` + number | `anonym="Pat"` | — |
|
||||
| mdr | Metadata repository ID in DKTK context | `mdr="dktk:dataelement:20:3"` | — |
|
||||
| op | Operation applied on value (e.g., `EXTRACT_RELATIVE_ID`) | `op="EXTRACT_RELATIVE_ID"` | — |
|
||||
|
||||
---
|
||||
|
||||
### Notes on **join-fhir-path**
|
||||
|
||||
* Used to join resources in FHIR queries when container references multiple resources.
|
||||
* Two join types:
|
||||
|
||||
* **Direct:** main resource points to secondary resource.
|
||||
* **Indirect:** secondary resource points back to main resource (path begins with `/`).
|
||||
* Joins can chain multiple resources, e.g., `R1 -> R2 -> R3`, with commas separating joins.
|
||||
|
||||
---
|
||||
|
||||
### 4. **CQL**
|
||||
|
||||
Contains metadata and details important for handling CQL queries.
|
||||
|
||||
| Tag | Description |
|
||||
| ------- | ---------------------------------------------------------------- |
|
||||
| `<cql>` | Container for CQL query metadata including tokens and parameters |
|
||||
|
||||
---
|
||||
|
||||
### 5. **Token (CQL)**
|
||||
|
||||
Replaces keys in CQL queries with specific values (commonly used for stratifiers).
|
||||
|
||||
| Tag | Description |
|
||||
| --------- | ------------------------------------- |
|
||||
| `<token>` | Contains `key` and `value` attributes |
|
||||
|
||||
| Attribute | Description | Example |
|
||||
| --------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
||||
| key | Key to replace in CQL | `key="DKTK_STRAT_MEDICATION_STRATIFIER"` |
|
||||
| value | CQL code snippet that replaces key | `value="define MedicationStatement: if InInitialPopulation then [MedicationStatement] else {} as List <MedicationStatement>"` |
|
||||
|
||||
---
|
||||
|
||||
### 6. **Measure Parameters (CQL)**
|
||||
|
||||
Parameters for a CQL measure query, typically in JSON format.
|
||||
|
||||
| Tag | Description |
|
||||
| ---------------------- | ----------------------------------------------------------- |
|
||||
| `<measure-parameters>` | Parameters such as `periodStart`, `periodEnd`, `reportType` |
|
||||
|
||||
---
|
||||
|
||||
### 7. **Default FHIR Search Query (CQL)**
|
||||
|
||||
FHIR search query applied after obtaining measure reports from CQL.
|
||||
|
||||
| Tag | Description | Example |
|
||||
| ----------------------------- | ----------------------------------------------------- | --------- |
|
||||
| `<default-fhir-search-query>` | Defines a FHIR resource type to query (e.g., Patient) | `Patient` |
|
||||
|
||||
---
|
||||
|
||||
### 8. **FHIR Reverse Include**
|
||||
|
||||
Defines which resources should be reverse-included when using FHIR search as input or CQL\_DATA.
|
||||
|
||||
| Tag | Description |
|
||||
| -------------------- | ------------------------------------------------------------ |
|
||||
| `<fhir-rev-include>` | Specifies reverse include resources to simplify FHIR queries |
|
||||
|
||||
---
|
||||
|
||||
|
@ -1,19 +1,287 @@
|
||||
# Teiler
|
||||
This module orchestrates the different microfrontends of the bridgehead as a single page application.
|
||||
|
||||
**Teiler** is the central frontend of the **bridgehead system**. It brings together multiple independent tools—each built as a **microfrontend**—into a single, unified web application.
|
||||
|
||||
Users interact with Teiler as one coherent interface, but behind the scenes, it dynamically integrates and displays self-contained modules developed with different technologies (**Angular**, **Vue**, **React**, etc.). This modular approach makes Teiler highly flexible, allowing teams to develop, deploy, and maintain features independently.
|
||||
|
||||
Teiler ensures:
|
||||
|
||||
* **A consistent look and feel** across tools.
|
||||
* **Smooth navigation** between components.
|
||||
* **Seamless user authentication** across the entire interface.
|
||||
|
||||
Each independent tool integrated into Teiler is called a **bridgehead app**. A bridgehead app can be:
|
||||
|
||||
- A fully standalone microfrontend with its own frontend and backend services.
|
||||
- An embedded service inside the Teiler Dashboard.
|
||||
- An external link to another service, possibly hosted on a central server or elsewhere in the federated research network.
|
||||
|
||||
The modularity of Teiler enables it to adapt easily to the evolving needs of the research federated network by simply adding, updating, or removing bridgehead apps.
|
||||
|
||||
Below is a breakdown of Teiler's internal components that make this orchestration possible.
|
||||
|
||||
- [Teiler Orchestrator](#teiler-orchestrator)
|
||||
- [Teiler Dashboard](#teiler-dashboard)
|
||||
- [Teiler Backend](#teiler-backend)
|
||||
|
||||
---
|
||||
|
||||
## Teiler Orchestrator
|
||||
Single SPA component that consists on the root HTML site of the single page application and a javascript code that
|
||||
gets the information about the microfrontend calling the teiler backend and is responsible for registering them. With the
|
||||
resulting mapping, it can initialize, mount and unmount the required microfrontends on the fly.
|
||||
|
||||
**GitHub repository:** [https://github.com/samply/teiler-orchestrator](https://github.com/samply/teiler-orchestrator)
|
||||
|
||||
The **Teiler Orchestrator** is the entry point of the **Single Page Application (SPA)**. It consists of:
|
||||
|
||||
The microfrontends run independently in different containers and can be based on different frameworks (Angular, Vue, React,...)
|
||||
This microfrontends can run as single alone but need an extension with Single-SPA (https://single-spa.js.org/docs/ecosystem).
|
||||
There are also available three templates (Angular, Vue, React) to be directly extended to be used directly in the teiler.
|
||||
- An **HTML root page**.
|
||||
- A **JavaScript layer** that:
|
||||
- **Retrieves microfrontend configurations** from the backend.
|
||||
- **Registers and manages** the microfrontends using [**Single-SPA**](https://single-spa.js.org/), the framework Teiler uses to create and coordinate its microfrontend environment.
|
||||
|
||||
Using this information, the orchestrator dynamically **loads the correct microfrontend** for a given route and manages its **lifecycle** (*init*, *mount*, *unmount*) in real time.
|
||||
|
||||
**Microfrontends** run in their own containers and can be implemented with any major frontend framework. To be compatible with Teiler, they must integrate with **Single-SPA**.
|
||||
|
||||
To encourage developers to create their own microfrontends and integrate them into Teiler, we provide **starter templates** for **Angular**, **Vue**, and **React**. Developing a new microfrontend is straightforward:
|
||||
|
||||
1. Use one of the templates.
|
||||
2. Extend it with your own functionality.
|
||||
3. Add its configuration in the **Teiler Backend**.
|
||||
|
||||
This modular approach accelerates development and fosters collaboration.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Teiler Dashboard
|
||||
It consists on the main dashboard and a set of embedded services.
|
||||
### Login
|
||||
user and password in ccp.local.conf
|
||||
|
||||
**GitHub repository:** [https://github.com/samply/teiler-dashboard](https://github.com/samply/teiler-dashboard)
|
||||
|
||||
The **Teiler Dashboard** is the unified interface users interact with after logging in. It provides:
|
||||
|
||||
- A **single point of access** where various bridgehead apps are embedded as microfrontends.
|
||||
- **Central navigation** and **session management** for a smooth user experience.
|
||||
|
||||
### Authentication and Authorization
|
||||
|
||||
Teiler uses **OpenID Connect (OIDC)** for user authentication, accessible via the **top navigation bar**.
|
||||
|
||||
We consider three possible **application roles**:
|
||||
|
||||
| Role | Description |
|
||||
|--------|-----------------------------------------------------------|
|
||||
| Public | Accessible by any user without the need to log in |
|
||||
| User | Normal users working with various bridgehead applications |
|
||||
| Admin | Bridgehead system administrators |
|
||||
|
||||
It is possible to **deactivate OIDC authentication** entirely. In such cases, **all apps must have at least the public role** to allow access. While this may be suitable for development or testing, we **strongly encourage** at least some external authentication mechanism or network-level access control to secure the bridgehead environment.
|
||||
|
||||
Alternatively, basic authentication can be enforced through the existing **Traefik infrastructure** integrated with the bridgehead.
|
||||
|
||||
---
|
||||
|
||||
## Teiler Backend
|
||||
In this component, the microfrontends are configured.
|
||||
|
||||
**GitHub repository:** [https://github.com/samply/teiler-backend](https://github.com/samply/teiler-backend)
|
||||
|
||||
The **Teiler Backend** serves as the central configuration hub for all microfrontends and bridgehead apps. It defines:
|
||||
|
||||
- Which bridgehead apps are available.
|
||||
- Their loading URLs and routes.
|
||||
- Optional metadata such as display names, icons, roles, and activation status.
|
||||
|
||||
It enables the orchestrator to remain **generic and flexible**, adapting dynamically to whatever apps are defined in the backend configuration.
|
||||
|
||||
### Assets Directory
|
||||
|
||||
There is an **assets** directory where you can save images and other static files to be accessible to your microfrontends. This helps configure and customize apps more easily and quickly.
|
||||
|
||||
Assets can be referenced via:
|
||||
|
||||
```
|
||||
<Teiler Backend URL>/assets/<filename>
|
||||
```
|
||||
|
||||
### App Configuration via Environment Variables
|
||||
|
||||
Apps are configured using environment variables with the following structure:
|
||||
|
||||
```
|
||||
TEILER_APP<Number>_<suffix>
|
||||
Optional: TEILER_APP<Number>_<LanguageCode>_<suffix>
|
||||
```
|
||||
|
||||
- The **number** is just for grouping variables for a single app and has no intrinsic meaning.
|
||||
- The **app** is the unit within Teiler, shown as a box in the dashboard.
|
||||
- Apps can be:
|
||||
- Embedded apps inside the Teiler Dashboard (there is a helper Python script for generating embedded apps: [create-embedded-app.py](https://github.com/samply/teiler-dashboard/blob/main/create-embedded-app.py))
|
||||
- External links (e.g., central services outside the local bridgehead instance)
|
||||
- An app's frontend (microfrontend or embedded app) can either contain the entire functionality or serve as a frontend communicating with other backend microservices in the bridgehead.
|
||||
|
||||
Currently supported languages in the main projects DKTK and BBMRI are **English (EN)** and **German (DE)**, but the system can be extended to other languages.
|
||||
|
||||
The Teiler Dashboard requests variables from the backend for each app and passes the desired language code. If a language-specific variable is unavailable, the default language value is returned.
|
||||
|
||||
### Internationalization (i18n)
|
||||
#### ⚠️ Important
|
||||
|
||||
If you make any changes to the **Teiler Dashboard**, and those changes involve text elements (e.g., labels, buttons, messages), you must also update the **English translations**, since the application uses **internationalization (i18n)**.
|
||||
|
||||
The **default language** of the project is **German**, so any new text must be manually translated into English after extracting the updated i18n entries.
|
||||
|
||||
To extract new translation entries, run the following command:
|
||||
|
||||
```bash
|
||||
ng extract-i18n --output-path src/i18n --format=xlf2
|
||||
````
|
||||
|
||||
This will generate or update the file:
|
||||
`src/i18n/messages.xlf`
|
||||
|
||||
---
|
||||
|
||||
#### ✅ Requirements to Run the Extraction Command
|
||||
|
||||
| Program | Purpose | Linux Shell (Ubuntu/Debian) | Windows PowerShell |
|
||||
| -------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
||||
| **Node.js** | JavaScript runtime required by Angular and npm | `sudo apt update && sudo apt install nodejs npm`<br>**or**<br>[Use NodeSource setup](https://github.com/nodesource/distributions) (recommended) | [Download from nodejs.org](https://nodejs.org) and install manually |
|
||||
| **npm** | Node package manager (comes with Node.js) | *(Included with Node.js)* | *(Included with Node.js)* |
|
||||
| **Angular CLI** | Command-line interface for Angular tooling | `npm install -g @angular/cli` | `npm install -g @angular/cli` |
|
||||
| **Angular project dependencies** | Required packages from `package.json` | `npm install` | `npm install` |
|
||||
|
||||
---
|
||||
|
||||
#### ✏️ Updating the English Translation
|
||||
|
||||
After running the extraction command, the file `src/i18n/messages.xlf` will contain any newly added i18n entries.
|
||||
|
||||
To provide English translations:
|
||||
|
||||
1. Open `src/i18n/messages.en.xlf`.
|
||||
2. Compare it with the updated `messages.xlf` to identify any new entries.
|
||||
3. Copy the new `<trans-unit>` blocks from `messages.xlf` into `messages.en.xlf`.
|
||||
4. For each entry, add the English translation inside the `<target>` tag (in `messages.en.xlf`):
|
||||
|
||||
```xml
|
||||
<trans-unit id="..." datatype="html">
|
||||
<source>Willkommen</source>
|
||||
<target>Welcome</target>
|
||||
</trans-unit>
|
||||
```
|
||||
|
||||
### App Availability Monitoring
|
||||
|
||||
The Teiler Backend regularly **pings apps** to check availability and displays status messages such as:
|
||||
|
||||
- "Frontend not available"
|
||||
- "Backend not available"
|
||||
- "Frontend and Backend not available"
|
||||
|
||||
### Accepted TEILER_APP Variable Suffixes
|
||||
|
||||
| Suffix | Description |
|
||||
|------------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| NAME | Identifier of the app (no spaces). For embedded apps, must match the identifier defined in Teiler Dashboard. |
|
||||
| TITLE | Display title shown to users. |
|
||||
| DESCRIPTION | Brief description of the app. |
|
||||
| BACKENDURL | URL of the backend microservice (if applicable). |
|
||||
| BACKENDCHECKURL | URL that the backend pings to verify backend availability. Defaults to BACKENDURL if not specified. |
|
||||
| SOURCEURL | URL of the microfrontend or external link (not used for embedded apps). |
|
||||
| SOURCECHECKURL | URL to ping to check microfrontend or external link availability. Defaults to SOURCEURL if not specified. |
|
||||
| ROLES | Comma-separated roles allowed: `TEILER_PUBLIC`, `TEILER_USER`, `TEILER_ADMIN`. |
|
||||
| ISACTIVATED | `true` or `false`. Used to temporarily deactivate an app without deleting its config. |
|
||||
| ICONCLASS | Bootstrap icon class to display in app box (e.g., `"bi bi-search"`). |
|
||||
| ICONSOURCEURL | URL to an image icon. Prefer using local assets instead of external URLs. |
|
||||
| ORDER | Relative display order of the app in the dashboard. |
|
||||
| ISEXTERNALLINK | `true` or `false`. Indicates if the app is an external link outside the local bridgehead. |
|
||||
| ISLOCAL | `true` or `false`. Indicates if the app runs locally within the bridgehead site or on a central server. |
|
||||
|
||||
*Note:* Embedded apps often have many of these variables preconfigured and may not require manual specification. See the [Teiler Dashboard documentation](https://github.com/samply/teiler-dashboard) for details.
|
||||
|
||||
### Additional Teiler Backend Variables for Dashboard Configuration
|
||||
|
||||
| Variable Prefix | Description |
|
||||
|------------------------------------|--------------------------------------------------------------------------------------------------------------|
|
||||
| TEILER_DASHBOARD_ | General configuration of the dashboard. |
|
||||
| TEILER_DASHBOARD_<LangCode>_ | Language-specific configuration overrides. |
|
||||
|
||||
Important suffixes include:
|
||||
|
||||
| Suffix | Description |
|
||||
|------------------|-------------------------------------------------------------------------------------------|
|
||||
| WELCOME_TITLE | Title shown on the initial screen before login. |
|
||||
| WELCOME_TEXT | Welcome message or instructions before login. |
|
||||
| FURTHER_INFO | Additional informational text or links. |
|
||||
| BACKGROUND_IMAGE_URL | URL to a background image (SVG recommended for scalability). |
|
||||
| LOGO_URL | URL to the project or bridgehead logo. |
|
||||
| LOGO_HEIGHT | Height of the displayed logo. |
|
||||
| LOGO_TEXT | Title text of the bridgehead (e.g., "DKTK Bridgehead"). |
|
||||
| COLOR_PALETTE | JSON link to color palettes for text, lines, icons, and background (especially for SVGs). |
|
||||
| COLOR_PROFILE | Selected color profile from the palette. (color palette name) |
|
||||
| FONT | Font family for the dashboard text. |
|
||||
|
||||
### 🎨 Color Palette
|
||||
|
||||
Below is an example of a **color palette** definition in JSON format:
|
||||
|
||||
```json
|
||||
{
|
||||
"color-palettes": [
|
||||
{
|
||||
"name": "Grey",
|
||||
"colors": {
|
||||
"text": "grey",
|
||||
"line": "grey",
|
||||
"icon": "grey",
|
||||
"background": "grey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Black",
|
||||
"colors": {
|
||||
"text": "black",
|
||||
"line": "black",
|
||||
"icon": "black",
|
||||
"background": "#F7ADAD"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Each palette contains a unique `name` and a set of color values for different UI elements.
|
||||
|
||||
#### 🔍 Palette Elements
|
||||
|
||||
| **Variable** | **Description** |
|
||||
| ------------ | --------------------------------------------------- |
|
||||
| `name` | Identifier of the color palette |
|
||||
| `text` | Color used for text |
|
||||
| `line` | Color used for lines (e.g., borders, dividers) |
|
||||
| `icon` | Color used for icons |
|
||||
| `background` | Background color (especially useful for SVG images) |
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 🚀 Ready to Extend Teiler?
|
||||
|
||||
If you want to create your own **bridgehead app** and integrate it into **Teiler**, start by:
|
||||
|
||||
1. Selecting a template **or**
|
||||
2. Building a microfrontend compatible with [Single-SPA](https://single-spa.js.org/).
|
||||
|
||||
Then, register your app’s configuration in the **Teiler Backend** as described above.
|
||||
|
||||
> 💡 **Tip:** This flexible, modular design makes it easy to plug in your own features and services.
|
||||
|
||||
---
|
||||
|
||||
### 🔧 Build & Contribute Your App!
|
||||
|
||||
🧩 **Join the ecosystem!**
|
||||
Add your app to Teiler and expand its functionality for everyone.
|
||||
|
||||
Whether it’s a visualization tool, a data processing module, or a custom UI component — your contribution can help grow the platform. 💪
|
||||
|
||||
> 👉 **Get started today and shape the future of Teiler!**
|
||||
|
||||
|
Reference in New Issue
Block a user