BlueVibes Container

(version 5.3.1)

What is Blue Vibes Container?

BlueVibes Container (or short: BV Container) is a lightweight GUI orchestration platform.
It can be also regarded as a modern application portal solution.
Blue Vibes container is one part of the Blue Vibes.
BV Container has the following roles in the Blue Vibes ecosystem:

:warning: BV Container is not supported by Internet Explorer browser because IE does not support web component standards. Polyfills could be added, if there is really a need to support IE.

Micro-App development and integration

While BV Container gives the possibility to a micro-app developer to write an application using any backend and frontend frameworks, the application must fulfill some requirements required by the web component standard to prepare it for seamless integration into BV-Container.
Those requirements are:

Exposing web components

The main approach to include a micro-app into BV Container is by using custom web elements (part of web components standard). To achieve this, it is mandatory that micro-app is exposed as a custom element. Read more about the web component concepts here.

It is worth mentioning, that a component (element/tag) name must be unique, otherwise component cannot be loaded into container. This is part of existing web-component standard as well. To avoid name collisions with other micro-apps, we suggest using a prefix per micro-application. Additionally, a micro-app with one or more (web) components has to be bundled in a single js file (default: main.js) and styles need to be bundled in single css file (default: main.css). This means that a single .js file can contain several web-component definitions, not just one.

Since many JS frameworks including React and Angular produce multiple js and css files in production build, additional build script should be added in order to bundle them into one js and css file (main.js and main.css). BlueVibes blueprint project includes this script.

When we load multiple micro-apps into the BV Container, each one of them will create a global webpackJsonp inside window object, and micro-apps will fail to render. To avoid conflict, build script from BlueVibes blueprint renames this variable by adding micro-app name to it. This way all micro-apps will be loaded on the screen. This script is just one of possible approaches to resolve problem with overriding webpackJsonp global variable.

API & images paths

As we described earlier bv Container acts as an API gateway, so every micro-application will be behind an alias/path. This is done to make a micro-app developer’s life easier, by aggregating certain repeating security and other integration aspects together. Let us imagine that we have a BV Container running on a host: example.bluevibes.io and a registered micro-app: my-app with some back-end API endpoint /api/hello. Once the micro-app is loaded into the browser inside of BV Container, if the micro-app calls a relative (relative to the server root) api endpoint /api/hello, it is going to hit the api of the BV Container first and not the actual micro-app’s endpoint, which will cause an error. To avoid this issue, micro-app developer has to always build micro-app with the context path (e.g. /my-app/) configured, same as ID of micro-app. By doing that, developer must call the api in client code with this context in mind (fetch(MICRO_APP_CONTEXT + API_PATH)). In our example api call would look like: fetch("/my-app/api/hello").

This gets more complex when the container is running directly behind a reverse proxy like Apache (i.e. prod.bluevibes.io/entry). In this case the micro-app API is “hidden” behind the BV Container proxy path, and additionally micro-app alias path. In a given example, an API call should look like: /entry/my-app/api/hello. To make the frontend code aware that there is a reverse-proxy in front of BV Container, BV Container will add a cookie with root path of the container (this value is configurable). Taking those facts into account, the fetch should call api in a following way: fetch( bvContainerRoot + microAppAlias + ApiPath).

Similar to the API, static images (i.e. /static/bv-logo.png) are “hidden” behind proxy/api-gateway path, so providing/evaluating links for images should be done in a similar way.

Redirection & router

Since GUI will be loaded inside of BV Container and rendered as a web-component (or in rarer occasions as an iframe), using redirection for displaying another view will not work. It will lead to leaving the BV Container. For the similar reasons, because of the nature of web-components, it is not possible to use routers in the micro-app.
If you need to navigate to other applications or pages, please refer to the app-to-app or page-to-page navigation features.

Global variables

Using window and other global variables in JS is not recommended generally, especially in the context of BV Container. When multiple application (JS files) are loaded, probability for a collision is even higher. To avoid any unpredicted behavior and bugs we highly recommend not to use the window global variables. If you must use them, prefix them with some unique name.

And for ES6 variables in global scope (const or let) there are following limitations: * Global scope variables are not shared between different micro apps (multiple js script files) * Global scope variables are shared between two instances of a same micro app (same js script file)

This should be taken into consideration while developing apps that can be referenced multiple times on a page. For example, if developer creates global scope variable as following:

const myUniqueId = "id" + Math.random();

const MyComponent = () => {
    // Using my unique variable
    console.log(myUniqueId);
};

The myUniqueId variable will be created only once, at the moment when the micro app’s js script is included into page. After that same value will be used for any micro app instance on page, which can produce bugs and unexpected behaviour.

CSS

By default, micro-app component is included as a custom element inside of the shadow dom (read more about shadow dom here). If you have packed all your css in a single file, it will be appended into shadow dom which will provide the isolation and prevent css leaking.

In case where developer is using shadow dom with JSS, he must ensure that css insertion point is inside of shadow dom root element. Here is an example of how to achieve that in React with material-ui in web component definition:

import { StylesProvider, jssPreset } from '@material-ui/styles';
import { create } from 'jss';

connectedCallback() {
    const jss = create({
        ...jssPreset(),
        // Define a custom insertion point that JSS will look for when injecting the styles into the DOM.
        insertionPoint: this,
    });
    
    ReactDOM.render(<StylesProvider jss={jss}><MyApp/></StylesProvider>, this);
}

This option is not yet stable, so we recommend using following solution if your app uses JSS.

Developer can configure his micro-app not to use the shadow dom. In that case the css is loaded globally, and it can lead to collision with css styles from different applications. To prevent this, a developer can generate unique css class names for his application by using JSS or some other framework of choice. It is important to make sure that generated class names will not match generated class names from some other app. Here is the example in react using JSS with material-ui and unique class name generator:

import {StylesProvider} from '@material-ui/styles';

const MyApp = () => {
    const generateRandomClassName = (rule: Rule, sheet?: StyleSheet<string>) => {
        const uniqueId = Math.ceil(Math.random() * 100000);
        if (sheet && sheet.options.classNamePrefix) {
            return `myAppPrefix-${sheet.options.classNamePrefix}-${rule.key}-${uniqueId}`;
        }
        return `myAppPrefix-${rule.key}-${uniqueId}`;
    };

    return (
        <StylesProvider generateClassName={generateRandomClassName}>
            <MyAppImplementation />
        </StylesProvider>
    )    
}

// ... later in the app code:
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';

const useStyles = makeStyles((theme: Theme) => createStyles({
    myApp: {
        display: "flex",
        color: "red"
    }
}), {classNamePrefix: "myApp"});
Micro App Version

BV Container has an option to display versions of all micro-apps in a selected workspace. That can be achieved by clicking on About/Info button on the bottom of the pages drawer. In order for this to work, a micro-app needs to expose his own API for accessing the version information. If micro-app is developed with the help of bv-spring or a plain Spring Boot, we recommend “Spring Boot Actuator” to be used for this. By default, BV Container expects micro-app to have info API exposed on /actuator/info, but it is not mandatory. In case that info API is missing, BV Container will just show “unknown version”. But also, some other API path can used as well, and that can be configured inside of a micro-app config. It is only important that the result of that API is in following format:

{
  "app": {
    "version": "0.1.0"
  }
}

Layout

BV Container supports two page layout options: GRID and FULL_SCREEN.

GRID layout

In the grid page layout (default layout), a user can organize his micro-apps into grid-like structure. It has following the features:

Initial configuration of the page layout can be done in your workspaces configuration. Layout must be configured on the page item level. For more details check the example of the page item configuration bellow:

{
    "instanceId": "micro-app-instance-id",
    "title": "Page item title",
    "layout": {
        "column": 1,
        "span": 2,
        "height": 300,
        "positionInColumn": 1
    }
}

Layout configuration in this example has the following fields:

User can reset his layout changes on a page to a default (as set in a configuration from the admin) by using the micro-app repository drawer. After the reset, components on the screen will be completely reloaded, and all current state will be lost. Layout change event will not be useful in this case, since web-component will be instantiated from the scratch. But the information about the new state of the layout will be provided inside of metadata object provided via web-component attribute.

Additional tweaking of the grid layout is possible with global gui configuration (grid-layout-column-number and grid-layout-new-item-span). Just take into consideration that changing number of columns in production could produce some unexpected changes in GUI on existing pages.

On each layout change, all micro apps on a page will receive a page-layout-changed event that will contain layout detail for their specific page item wrapper. Following is the example of layout details object that micro app will receive:

{
  "h": 40,
  "w": 2,
  "widthInPixels": 630,
  "heightInPixels": 577,
  "widthPercentage": 50
}

Value “w” represent number of grid columns that item uses. Value “h” is number of grid rows that item uses. Other values in layout details are mostly self-explanatory.

FULL_SCREEN layout

In the full screen layout, a micro-app will fill the whole page space. Only one app per page is allowed. This layout is useful for mobile micro-apps, because the height of all elements is set to ‘100%’ so mobile micro-app developer can implement his app to behave as a mobile app.

Custom Headers

In the ‘grid’ layout, it is possible to define a custom header for each micro-app. Custom header will fill up the space left of micro-app toolbar (right part of the default header).

Developer should implement the custom header inside of his micro-app and expose it as an additional web-component. Later in container configuration, headerHtmlTag should be configured on micro-app instance on which this custom header should be displayed instead of the default one. When left unconfigured, the default header will be displayed.

    {
        "instanceId": "micro-app-instance-id",
        "name": "Micro App",
        "microAppId": "micro-app-id",
        "componentId": "micro-app-comp-id",
        "headerHtmlTag": "micro-app-header"
    }
class CustomHeaderWebComp extends HTMLElement {
    constructor() {
        super();
    }
    connectedCallback() {
        ReactDOM.render(<CustomHeaderImplementation />, this);
    }
}
customElements.define("micro-app-header", CustomHeaderWebComp);

Header html tag can be configured on micro-app component level as well, and in that case, every instance of that micro-app will have a custom header.

{
    "microAppId": "micro-app-id",
    "url": "http://localhost:60000/micro-app-id",
    "name": "Micro App",
    "components": [
      {
        "componentId": "micro-app-comp-id",
        "headerHtmlTag": "micro-app-header"
      }
    ]
  }

Default header has a height of 36px. That is a default height. A custom header can be sized up to 52px in height. If you want to set custom header height, simply set it in css on the root element of the custom header implementation.

Custom headers behave in a same way as any other micro-app component. All event bus types that are registered for a micro-app component will be used in a custom header as well. Same applies to parameter definitions. This will enable the developer to have a communication between micro-app and its header. For example, micro-app can be registered to produce and consume change-header-counter-custom-event event. From micro-app code, this event can be fired to send some data to header. In header code, developer should create a listener for this event, and update header state accordingly.

Metadata attribute is also forwarded to the custom header from BV Container.

Metadata attribute

Each micro-app component that is displayed in BV container will receive a metadata object through metadata attribute on a web component. This object contains application relevant metadata. Content of metadata object:

Example of metadata retrieval in micro-app code:

class SomeWebComponent extends HTMLElement {
    constructor() {
        super();
    }
    connectedCallback() {
        const metadata = this.getAttribute("metadata");
        ReactDOM.render(<SomeReactApp locale={metadata.locale} />, this);
    }
}

Security

Authorization

BV Container supports single sign-on through the following authorization flows:

Switching between the mentioned flows is done with the property ‘bv.container.authorization-flow’, with available values being simple, oauth2 and acp. Regardless of the used auth flow inside BV Container, each micro-app is responsible for securing access to its own data. BV Container will pass the token (not if ACP with disabled validation mode is used) to the micro-app and the micro-app should verify the token’s signature and the required roles and permissions. By using BV Spring security, it is easy to set-up and configure the security of the micro-apps.

SIMPLE flow configuration

In case of the simple flow, container expects that authorization is done by another system, and it acts as a resource server. Theoretically, it could be at the same time protected by JWT and SAML token, but mostly this is one type of token. More about configuring SAML and JWT security is available as part of bv-spring security module.

To set up the simple flow in BV Container, the minimal configuration is shown in the example below:

bv:
  container:
    authorization-flow: simple 
    # represents base url of container
    # Both absolute(i.e. https://sub.main.domain/dev/bv) and relative path(i.e. /dev/bv) are supported.
    # Relative path is used in case when BV Container runs behind proxy and more than one domain, i.e. banking.corp.ametiq.com and banking.ametiq.com.  
    base-url: ""
    oauth2:
          jwt-key-value: default-public-key # Value of public key used for validating JWT tokens 

OAuth flow configuration

The login OAuth2 flow is presented in following diagram:

After the login, accessing resources flow is presented in following diagram:

Following is the configuration of the OAuth2 security flow.

We have to configure BV Container as an OAuth2 client and as a Resource Server at the same time. As a client, it should be able to manage users authentication with Authorization Server, and do an OAuth2 dance behind the scene. Container as a resource server should be able to parse access token, extract roles and create User/Authorization object.

To set up OAuth2 in BV Container, the minimal configuration is shown in the example below:

bv:
  container:
    authorization-flow: oauth2 
    # represents base url of container, it's needed for OAuth2 dancing.
    # Both absolute(i.e. https://sub.main.domain/dev/bv) and relative path(i.e. /dev/bv) are supported.
    # Relative path is used in case when BV Container runs behind proxy and more than one domain,
    # i.e. banking.corp.ametiq.com and banking.ametiq.com.  
    base-url: http://localhost:8080 
    oauth2:
      # base path of authentication server(i.e. key-cloak), it's used for redirecting and this
      # url has to be accessible by end-user. In some cases, this link is accessible by end-user
      # but not for BV Container(i.e. docker/localhost) or because of some reverse-proxy configuration,
      # so in that case we have to provided one additional property `authorization-server-internal-url`.
      authorization-server: http://localhost:8888 
      # following three properties must be provided. If some of provided values is not correct, OAuth dancing will fail.
      realm: default-realm
      client-id: default-client-id
      client-secret: default-client-secret

There are also optional parameters which should be configured only if you are configuring some custom OAuth2 Authorization Server.

bv:
  container:
    oauth2:
      # Optional url for auth server in case there are different urls for internal and external access.
      authorization-server-internal-url: http://internal:8888
      # Raw value of public key used for jwt validation.
      jwt-key-value:
      # JWK uri where set of keys is provided from auth server. If this property is configured, property 'jwt-key-value' must be set to empty.
      jwk-key-uri: https://authserver/auth/realms/test-realm/protocol/openid-connect/certs
      # Logout url of auth server used for clearing user session.
      logout-url: https://authserver/auth/realms/test-realm/protocol/openid-connect/logout
      # Url where user will be redirected after login (if referer is not found). Default value is base-url.
      home-page: https://localhost/index.html
      # Token expiration tolerance that is to decide when access token should be refreshed. Default is 5.
      token-expiration-tolerance-in-seconds: 5
Public key

By default, BV Container uses default url for retrieving public-key from the authorization server (key-cloak), and it does not require any configuration. In case that BV Container has to use a custom url for key obtaining, the url has to be provided in property bv.container.oauth2.jwk-key-uri.

In case that BV Container has to use provided (static) public key value, it can be done by setting key-value in the property bv.container.oauth2.jwt-key-value. Because of spring-security nature, additionally the property bv.container.oauth2.jwk-key-uri must be set to blank value, otherwise a spring security exception will be thrown on application startup.

If you have specific requirements and this minimal set of properties does not cover your case, then you need to do some advance configuration.

Docker compose example

Following is the example of BV Container configured to run with oauth2 flow:

version: '3'
services:
  bv-container:
    image: docker.corp.ametiq.com/bv-container:2.0.0
    container_name: bv-container
    ports:
          - "8080:8080"
    environment:
      - BV_CONTAINER_BASE_URL=https://localhost/bv/dev
      - BV_CONTAINER_AUTHORIZATION_FLOW=oauth2
      - BV_CONTAINER_OAUTH2_AUTHORIZATION_SERVER=https://localhost/bv/keycloak
      - BV_CONTAINER_OAUTH2_AUTHORIZATION_SERVER_INTERNAL_URL=http://keycloak:8080/bv/keycloak
      - BV_CONTAINER_OAUTH2_REALM=bluevibesdev
      - BV_CONTAINER_OAUTH2_CLIENT_ID=bv-client
      - BV_CONTAINER_OAUTH2_CLIENT_SECRET=73db4288-2288-4a67-807d-72613ef3e9ab

And an example of BV Container configured to run with simple flow:

version: '3'
services:
  bv-container:
    image: docker.corp.ametiq.com/bv-container:2.0.0
    container_name: bv-container
    ports:
          - "8080:8080"
    environment:
      - BV_CONTAINER_BASE_URL=https://localhost/bv/dev
      - BV_CONTAINER_AUTHORIZATION_FLOW=simple
      - BV_CONTAINER_OAUTH2_JWT_KEY_VALUE=public-key-value
Micro App as a resource server

To have a secured micro app in OAuth2 flow, the micro app must be configured to validate bearer tokens propagated by the BV Container. If developer chooses to use bv-spring library in his micro app, this configuration is quite simple. There must be @EnableResourceServerSecurity annotation present in configuration and following yaml config:

# Make sure that dev mode is disabled
bv:
  security:
    dev-mode:
      mode: disabled

# Key for validation must be configured in one of the following ways:
security:
  oauth2:
    resource:
      # using raw public key value
      jwt:
        key-value: public-key-value
      # or providing key set uri which is prefered option of available
      jwk:
        key-set-uri: http://keycloak/auth/realms/your-realm/protocol/openid-connect/certs

ACP flow configuration

ACP flow works as following:

To set up the ACP flow in BV Container, a following configuration is required:

bv:
  container:
      authorization-flow: acp
  security:
    acp:
      token-ttl-in-minutes: 120 # Time token will be kept into ACP token cache
      token-source: query # Where acp token will be extracted from
      token-request-param-name: acpToken # Name of query/header param for acp token
    jwt: # In acp flow tokens will be propagated in jwt format
      external-token-claim: acp # Claim in which source acp token will be stored
      token-ttl-in-minutes: 30 # JWT token time-to-live

In order to validate the ACP token, external service (e.g. AIL) must be contacted. Feign client must be configured for this:

ail-base-url: localhost:9999
ail-acp-token:
  url: ${ail-base-url}

JWT tokens generated from ACP token and user data must be encoded/signed before propagation. For this to work, key store with signing certificate must be available and configured. More on that can be found in bv-security module. As an alternative if key store is not available, signing key can be provided in configuration as well by using bv.security.jwt.key property.

For testing purposes AIL stubs that return dummy user data are available.

Content Security Policy

We have integrated content security policy per default inside Blue Vibes Container to guard against cross-site scripting (XSS) attacks.
This can additionally be fine-tuned according to specific needs.
For more details please check configuring security headers in Blue Vibes.

GUI Configuration

BV Container have an option to customize its GUI with configuration. An example of gui configuration:

bv:
  container:
    gui:
      show-user-button: true
      show-logout-button: false
      show-qr-code-button: false
      show-language-button: true
      show-themes-button: true
      show-workspaces-button: true
      show-about-button: true
      show-zoom-button: true
      sticky-header: true
      themes-path: "/conf/theme.json"
      default-workspace: workspaceX
      default-page: pageZ
      grid-layout-column-number: 4
      grid-layout-new-item-span: 2
      grid-layout-disable-css-transform: true
      default-locale: "de_CH"
      available-locale-definitions:
        - {locale: "de_CH", label: "DE (CH)"}
        - {locale: "en_US", label: "EN (US)"}
bv.container.gui properties
Property Type Default value Description
show-user-button boolean true Should user menu button be displayed. Only in web view.
show-logout-button boolean true Should logout button be displayed. Only in web view.
show-qr-code-button boolean depends on the auth flow Should qr code button be displayed. Only in web view and for OAuth2 flow.
show-language-button boolean true Should language/locale selection button be displayed.
show-themes-button boolean true Should themes selection button be displayed.
show-workspaces-button boolean true Should workspace selection button be displayed.
show-about-button boolean true Should about button be displayed in user option menu.
show-zoom-button boolean false Should zoom option be displayed in user option menu.
sticky-header boolean false Should header (app bar) always be on top.
themes-path String null Path to themes file
translations-path String null Path to custom translations file
default-workspace String null If it present, container navigates automatically to the workspace.
default-page String null If it present, container navigates automatically to the page inside of the workspace.
grid-layout-column-number Number null Number of columns on pages with grid layout. Default is 4. Values can be between 1 and 8.
grid-layout-new-item-span Number null Number of columns that new item will span when added to grid layout. Default is 2. It must be less than grid-layout-column-number but not less than 1.
grid-layout-disable-css-transform boolean false By default, grid layout uses css transform for element positioning. If your apps do not support css transform, you can turn it off with this property.
default-locale String de_CH Default locale of the BV Container. User will have this locale selected until he selects his own preference.
available-locale-definitions Array de_CH, en_US Available locales of the BV Container. By default it contains de_CH and en_US, but it can be overridden to contain any locale.
Landing to default workspace and page

When a user comes to the container, usually he/she has an option to choose a workspace, then a page. But sometimes choosing a workspace is pointless (i.e. the same workspace is used in most cases, or there is only one workspace existing). In order to avoid this unnecessary step, a BV Container support a default workspace option (above mentioned property: bv.container.gui.default-workspace). BV Container determines whether there is a default workspace or only one workspace. The same logic is applied to the page, the container first checks the property bv.container.gui.default-page or if there is only one page, container navigates to that page immediately.

Frontend parameters

Front end parameters are URL query parameters used to turn some UI options on directly through the URL. The format of the URL with frontend parameters is as follows:

https://bv-container-host/bvc-context/#/workspace/w1/page/p1?frontendParam1=value1&frontendParam2=value2

These parameters can be used by micro app developers as well. Note that they are not sent to the backend, they are frontend only. If for some reason the regular query params that are sent to backend are needed, just define them before #.

Frontend parameters are targeted to single page, so when user switches the page, parameters will be lost. But, the parameters are preserved in case of “stacked” navigation in same page (e.g. navigate-to-page event).

BV Container supports following predefined frontend parameters: * noHeader=true: Hides the header (app bar) of the container on a target page.

Theme

There is a possibility to define custom themes for BV Container which will change the look and feel of both BV Container and integrated micro apps. If you define multiple themes, there will be an option available to select the theme from UI. A selected theme is saved as a user preference, it won’t be applied globally. First theme in the file will be treated as default one, and if user hasn’t set the preference, default one will be selected. Theme selector can be hidden with configuration: bv.container.gui.show-themes-button: false. After theme is changed, event bus will fire theme-changed event, on which micro app can update its style accordingly.

Following features are currently available in the BV Container:

Themes should be defined in json file and made available to BV Container via property themes-path. Here is an example of themes json file:

[
    {
      "name": "Default Theme",
      "customLogo": "https://bluevibes.io/logo.png",
      "primaryColor": "#AABBCC",
      "secondaryColor": "#CCBBAA",
      "infoColor": "#03A9F4",
      "warningColor": "#FFC107",
      "errorColor": "#E51C23",
      "successColor": "#259B24",
      "microAppHeaderTextColor": "#44BB00",
      "microAppBackgroundColor": "#FAFAFA",
      "containerHeaderTextColor": "#000000",
      "containerContentBackgroundColor": "#FAFAFA",
      "backgroundColor": "#44BB00",
      "buttonTextColor": "#FAFAFA",
      "fontFamily": "Righteous",
      "customFavicon": "https://my-cdn/favicon.ico",
      "type": "light",
      "customFonts": [
        {
          "fontFamily": "Righteous",
          "fontStyle": "normal",
          "fontWeight": 400,
          "src": "local('Righteous'), local('Righteous-Regular'), url(https://fonts.gstatic.com/s/righteous/v8/1cXxaUPXBpj2rGoU7C9WiHGFq8Kk1Q.woff2) format('woff2');"
        },
        {
          "fontFamily": "Some Other Font",
          "fontStyle": "normal",
          "fontWeight": 400,
          "src": "local('Some Other Font'), url(https://myfonts/some-other-font.woff2) format('woff2');"
        }
      ],
      "microAppDrawer": {
        "width": 220,
        "fontFamily": "Ubuntu",
        "fontSize": "16px",
        "fontWeight": "bold",
        "fontColor": "#444477",
        "fontColorDisabled": "#555566",
        "itemHeight": "60px",
        "itemPadding": "10px",
        "itemBackgroundColor": "#BEBEBE",
        "itemBackgroundColorDisabled": "#999999",
        "itemIconColor": "#DDDDDD",
        "backgroundColor": "gray",
        "itemDefaultIcon": "data:image/png;base64,iVBORw0KGgoAAAANSUh...AAElFTkSuQmCC"
      }
    },
    {
      "name": "Secondary",
      "primaryColor": "#AA00CC",
      "secondaryColor": "#00BBAA",
      "microAppHeaderTextColor": "#77BB00",
      "fontFamily": "Arial",
      "customFonts": []
    }    
]

:warning: Theme variables and provided fonts will not work inside of IFrame.

Custom logo

The custom logo is an option to have a logo on the right side of the header. Logo is configured in a same fashion like html img tag. User can define a URL to the image or Base64/Svg string.

Primary and secondary color

Primary color is the main color of the theme. Header and some UI components will inherit this color. Primary color is available to the micro apps via CSS variable --bv-color-primary. Developer can use this variable in his app by doing following:

<div style={{color: "var(--bv-color-primary, red)"}}>

This way, even if the variable is not available (during the development outside of the BV Container context), default value (red) will be used.

Secondary color works the same way as primary, but it uses variable --bv-color-secondary. Secondary color won’t change much in BV Container UI, but it can be used by micro apps to have uniform secondary color.

Variables are available even in shadow dom components.

Alert colors

Alert colors are the same concept as primary and secondary colors, just used to have uniform style for warnings, information, error and success alerts and messages across the apps.

Following alert css variables are available: * --bv-color-info * --bv-color-warning * --bv-color-error * --bv-color-success

Micro app header text and background color

With these values user can style how will micro app look on a page. The color of the text and icons of the micro app header (only in grid layout) can be changed with “microAppHeaderTextColor”. This config is also available as a variable --bv-micro-app-header-text-color. Micro app background color can be changed as well with “microAppBackgroundColor”. Developer must use the css variable --bv-micro-app-background-color in his micro app, so that theme changes are applied correctly.

Dark theme

BV Container has a lot of flexibility in creating a dark theme. The starting point should be to change the type of theme from the default value (“light”) to “dark”. Just change option type to the value dark and that’s it. With this, BV Container adapt highlight and focus colors to work better with darker themes. Now theme creator can style the following to achieve the desired look: * primaryColor * backgroundColor (--bv-background-color) which is the background color of all surfaces in BV Container that are not styled otherwise. * textColor (--bv-text-color) which is the default color of the text on the page. If the micro apps on a page use white background even in the dark theme, the text color should black or some other dark color. * containerHeaderTextColor (in the dark theme is usually set to white). * buttonTextColor (--bv-button-text-color) which is the color of the text in buttons and select components. * containerContentBackgroundColor (--bv-container-content-background-color) which is the color of the surface where micro apps are displayed. It should be styled to have similar color as the micro app background, but still different to have contrast effect. * micro app background and header text color (check the previous section) * micro app repository drawer style (more details bellow)

Font family

With fontFamily configuration global font family is configured for BV Container and its micro apps. Font family is applied automatically to all micro apps (even the shadow dom components), unless it is overridden in micro app code. The defined font must be available to the browser, but also, custom font can be defined and used.

Custom fonts

There is a possibility to define custom fonts. Css logic @font-face is used to achieve this. To define a new font, font definition must be publicly available on some URL. Config param customFonts takes array of custom font object, so multiple fonts can be defined. Here is the example of one font object with currently available fields:

{
    "fontFamily": "My Custom Font",
    "fontStyle": "normal",
    "fontWeight": 400,
    "fontDisplay": "swap",
    "src": "local('My Custom Font'), url(https://this-is-a-url-to-your-font-definition/my-font.woff2) format('woff2');"
}

Defined fonts are available to all micro apps, even to ones under shadow dom. Developer can define custom font as a global font family with fontFamily config field.

You can read more about custom font definition via @font-face here.

Micro app sidebar styling

Micro app sidebar can be styled in detail, as seen in following snippet:

{
  "microAppDrawer": {
      "width": 220, 
      "fontFamily": "Arial",
      "fontSize": "16px",
      "fontWeight": "bold",
      "fontColor": "#444477",
      "fontColorDisabled": "#555566",
      "itemHeight": "60px",
      "itemPadding": "10px",
      "itemBackgroundColor": "#BEBEBE",
      "itemBackgroundColorDisabled": "#999999",
      "itemIconColor": "#DDDDDD",
      "backgroundColor": "gray",
      "itemDefaultIcon": "data:image/png;base64,iVBORw0KGgoAAAANSUh...AAElFTkSuQmCC"
  }
}

Available settings are: * width is the width in pixels of the sidebar. * fontFamily is the font family specific to the sidebar. * fontSize is the font size of the item texts. * fontWeight is the font weight of the item texts. * fontColor is the font color of the item texts. * fontColorDisabled is the font color of the unselectable item. * itemHeight is the height of the individual item in user defined unit. * itemPadding is the padding of the individual item in user defined unit. * itemBackgroundColor is the background color of the individual item. * itemBackgroundColorDisabled is the background color of the unselectable item. * itemIconColor is the color of icons in case SVG icons are used. * itemDefaultIcon is the user defined default icon. It accepts any html src value. Used when micro app icon is not set. * backgroundColor is the background color of the whole sidebar.

Custom favicon

Custom favicon can be set by providing the URL to the icon in theme config customFavicon. If not provided, default icon will be used. Favicon can be defined only once, regardless of the number of themes, and it should be in the default (first) theme.

Custom Translations

There is a possibility to override default values of the labels inside of BV Container. That can be achieved is similar fashion as custom theme, by providing the translations json file which will contain the translations for the labels you want to change.

Following is the example of the content of such a file:

{
  "workspaces.label": {
    "en_US": "Workspace Selection",
    "de_CH": "Arbeitsbereiche"
  },
  "logout.label": {
    "en_US": "Sign Out",
    "de_CH": "Abmelden"
  }
}

This file will override the default values of these specific labels. This file should be provided to BV Container via property translations-path (full path: bv.container.gui.translations-path).

To see full list of the labels that can be overridden go here, or find default translations sector inside of documentation pdf file.

Custom Locales

By default, BV Container has two locales: en_US and de_CH. But this can be overridden via configuration (bv.container.gui.available-locale-definitions). Following is an example of such a configuration:

bv:
  container:
    gui:
      default-locale: "de_CH"
      available-locale-definitions:
        - {locale: "de_CH", label: "DE (CH)"}
        - {locale: "en_US", label: "EN (US)"}
        - {locale: "it_IT", label: "IT (IT)"}

This configuration contains three locale definitions with default one being “de_CH”.

To achieve the same in the docker-compose script use the following:

bv-container-banking:
    image: bv-container-image
    container_name: bv-container
    environment:
      - BV_CONTAINER_GUI_DEFAULT-LOCALE=de_CH
      - BV_CONTAINER_GUI_AVAILABLE-LOCALE-DEFINITIONS_0_locale=de_CH
      - BV_CONTAINER_GUI_AVAILABLE-LOCALE-DEFINITIONS_0_label=DE (CH)
      - BV_CONTAINER_GUI_AVAILABLE-LOCALE-DEFINITIONS_1_locale=en_US
      - BV_CONTAINER_GUI_AVAILABLE-LOCALE-DEFINITIONS_1_label=EN (US)
      - BV_CONTAINER_GUI_AVAILABLE-LOCALE-DEFINITIONS_2_locale=it_IT
      - BV_CONTAINER_GUI_AVAILABLE-LOCALE-DEFINITIONS_2_label=IT (IT)
      - BV_CONTAINER_GUI_TRANSLATIONS-PATH=/bv-config/translations.json
      - ...

If you introduce a new locale, make sure to adapt custom translations json to include all translations of the new language.

Also, if developer wants to localize the names of pages, workspaces or micro apps, localized text must be provided in the workspaces / micro-apps definition json file instead of strings. Following is the example of the workspace name localization:

Before:

{
    "workspaceId": "my-space",
    "name": "My Workspace"
}

After:

{
    "workspaceId": "my-space",
    "name": {
                "key": "My Workspace",
                "translations": [
                  {
                    "locale": "de_CH",
                    "text": "Mein Arbeitsbereich"
                  },
                  {
                    "locale": "en_US",
                    "text": "My Workspace"
                  }
                ]
            }
}

User preferences

BV Container automatically stores user preferences related to the UI. Preferences currently stored are: * Selected locale * Selected theme * Page layout and micro app configuration

For new users default values are used.

BV Container has also an option to configure custom user preferences provider. The custom provider is just a REST API which will return preferences for current user.

The API definition can be found here.

Expected response from the custom provider should contain (not mandatory): * User locale * User theme * User display name (This will be shown in UI instead of the username) * Custom parameters

Custom parameters are a non standard parameters related to the business app logic and not to BV Container logic. They are propagated to all micro apps via attributes.

To configure the custom provider, following configuration must be provided:

bv:
  container:
    custom-user-preferences-api:
      url: http://remote-api/custom-user-preferences
    force-custom-preferences: true | false

First value (custom-user-preferences-api) is the url to the REST API which will provide us the preferences. Second value (force-custom-preferences) sets the priority of the custom parameters. By default (false value), custom parameters are read initially when user haven’t set any preference, to serve as a default value. When user sets his preference (e.g. change the language) preferences are read from database from that point. And, if force-custom-preferences is true, custom preferences from the provider are used every time (if missing, local one are used instead). Note that user display name and custom parameters will be taken custom provider if available even if force-custom-preferences is not true, since user cannot set the preference on those values.

Data store

BV container needs data storage to keep needed metadata, we support a few different type of data storage. Changing type of data storage is done through the property bv.container.data-store. The current version of container support following type of data store:

SQL

If user starts BV Container without any additional settings, H2 in-memory database will be used. To use a real database. user has to provide datasource configuration, i.e. mssql:

spring:
  datasource:
    url: jdbc:sqlserver://localhost:1433;databaseName=test1
    username: SA
    password: BlueVibes(!)2019
    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver

Scalability

One of the main benefits of using micro-apps is a scalability, and BV Container supports easy scalability as well. Since BV Container is OAuth2 client, it has to store access and refresh tokens, which means it’s not completely stateless, so additional configuration must be provided in order to run multiple instances of BV Container.

Session distribution

BV Container is using a session to store Oauth2 tokens. When running multiple instances, BV Container should be configured to use database for session distribution.

In order to enable session distribution, following configuration should be provided:

spring:
  session:
    store-type: jdbc
    jdbc:
      initialize-schema: always

This configuration will enable spring jdbc session distribution, and 2 tables will be created in your database: - SPRING_SESSION - SPRING_SESSION_ATTRIBUTES

Micro-Apps Configuration of BV Container

One micro-App in BlueVibes context represents one (or more) frontend components and a micro-app backend, usually serving those front-end resources. BV Container manages and displays the components of these micro-apps. We organize these micro-apps components into workspaces and pages. Container can have multiple workspaces, and workspace can have multiple pages. Page is where a micro-app is displayed. It can be multiple micro-apps on one page. A diagram related to this can be found under BV-Container architecture page page.

This workspace and application data (BV configuration) must be provided in an external json files. When BV Container is started, a batch process starts and compares the state of the json files and the current database state. Import will not remove any existing records from the database, but will update existing ones, in case of changes. Additionally, if there are new micro-apps in the .json file, they will be added to the DB. If you removed some micro-app from .json file, the entry will, however, remain in the database. If you want to clear the state of micro-apps from DB, you will have to manually clear these 2 tables. Just be careful not to clear the user preferences table!

To make files available to BV Container, the following parameters have to be provided: init-data.micro-applications=PATH_TO_THE_APP_JSON and init-data.workspaces=PATH_TO_WS_JSON.

Docker compose example
version: '3'
services:
  bv-container:
    image: docker.corp.ametiq.com/bv-container:2.0.0
    container_name: bv-container
    ports:
      - "8080:8080"
    environment:
      - INIT_DATA_MICRO_APPLICATIONS=/conf/micro-applications.json
      - INIT_DATA_WORKSPACES=/conf/workspaces.json
      - BV_CONTAINER_GUI_THEMES-PATH=/conf/theme.json
    volumes:
      - /YOUR_PATH/micro-applications.json:/conf/micro-applications.json
      - /YOUR_PATH/workspaces.json:/conf/workspaces.json
      - /YOUR_PATH/theme.json:/conf/theme.json
Application json

To make an application available in the container, we have to register the micro-app. This is done by providing micro-application.json file, which contains an array of micro-apps. Here is an example:

[
  {
    "microAppId": "micro-app-x",
    "url": "http://x-url:8080",
    "name": "The X",
    "components": [
      {
        "componentId": "app-x",
        "produceEvents": [
          "appEvent"
        ],
        "paramDefinitions": [
          {
            "name": "appParam"
          }
        ]
      }
    ]
  },
  {
    "microAppId": "micro-app-y",
    "url": "http://y-url:8080",
    "name": "The Y",
    "components": [
      {
        "componentId": "app-y"
      },
      {
        "componentId": "app-y-small"
      }
    ]
  }
]

JSON micro-application model:

MicroApplication
Field name Required Type Description
microApplicationId true String Unique micro-app identifier.
url true String The url path of a micro-app. Path must be accessible by container. Access from the outside world is done through the container, thanks to a container’s internal gateway.
name false LocalizedText/String Human readable name of application. It is used for labels and title in FE. If not specified, microApplicationId is used as name.
description false LocalizedText/String Short description if it is needed.
jsPath false String Path to the js bundle file. Default value is “/web-component/main.js”
cssPath false String Path to the css bundle file. Default value is “/web-component/main.css”. Set if your .css has a custom name. In case of no external css, set cssPath to "" to avoid browser log errors
infoPath false String Path to the info API. Default value is “/actuator/info”. Set if your app have custom (non Spring Boot Actuator) info url.
components true MicroApplicationComponent[] List of micro web components. Every application has at least one gui component.
MicroApplicationComponent
Field name Required Type Description
componentId true String Unique component identifier. To avoid complexity and potential bugs, it should be the same as web-component tag.
htmlTag false String Custom web-component tag. If not specified, the componentId will be used instead.
icon false String Micro app component icon can be customized by providing image data or url (e.g. "icon": "data:image/svg+xml;utf8,%3Csvg xmlns...")
iframePath false String Path for legacy iframe pages. Default value is /index.html. It is recommended to have absolute path set here to avoid relative path issues
wrapperDisplayType false String Wrapper css display type (e.g. flex, block etc). Default value is ‘block’.
configurable false boolean Flag for configuring if user can change the settings of the component / instance. Default value is true.
removable false boolean Flag for configuring if user can remove instance from the page. Default value is true.
paramDefinitions false ParamDefinition[] Input parameters(custom-web-component attributes or iframe query params) should be defined here. Later they are used for validation.
produceEvents false String[] Definition of events produced by the component. (!) It’s not supported for iframe. Read more about events below in Event Bus section.
consumeEvents false String[] Definition of events consumed by the component. (!) It’s not supported for iframe. Read more about events below in Event Bus section.
ParamDefinition
Field name Required Type Description
name true String Parameter name.
required false boolean Indicates whether parameter is required or not. Default: false.
Workspaces json

To make a registered micro-app available for the end-user, first we need to define a workspace and assign the app to workspace and page. This configuration is done by providing workspaces.json file containing a list of workspaces. Here is an example:

[
  {
    "workspaceId": "my-space",
    "name": "My space",
    "instances": [
      {
        "instanceId": "the-x",
        "name": "The X",
        "microAppId": "micro-app-x",
        "componentId": "app-x"
      }
    ],
    "pages": [
      {
        "pageId": "x-page",
        "name": "Page X",
        "items": [
          {
            "instanceId": "the-x"
          }
        ]
      }
    ]
  }
]
Workspace
Field name Required Type Description
workspaceId true String Unique workspace identifier.
name false LocalizedText/String Human readable name of workspace, it is used for labels in FE.
instances false MicroApplicationInstance[] List of available applications in the workspace.
pages false WorkspacePage[] Pages that belong to the workspace.
MicroApplicationInstance
Field name Required Type Description
instanceId true String Unique instance identifier.
name false LocalizedText/String Human readable name of instance, it is used for title in FE.
description false LocalizedText/String Short description.
icon false String Micro app instance icon can be customized by providing image data or url (e.g. "icon": "data:image/svg+xml;utf8,%3Csvg xmlns...")
microAppId true String Reference to a registered micro app. If provided id does not match any of registered micro apps, an exception will be thrown.
componentId true String Reference to a component of the micro app. If provided id does not match any of components of the micro app, an exception will be thrown.
type false ComponentType Enum [WEB_COMPONENT - default, SHADOW_WEB_COMPONENT, IFRAME] that tells how micro app would be rendered inside of the container.
singleInstance false boolean Mark an instance to have limited instantiation on page. If true, only one micro app instance can be on page. Otherwise is not limited
configurable false boolean Flag for configuring if user can change the settings of the component / instance. Default value is true.
removable false boolean Flag for configuring if user can remove instance from the page. Default value is true.
produceEvents false String[] This is already defined in a MicroApplicationComponent. If we want to override those values, we can do it by defining them here.
consumeEvents false String[] This is already defined in a MicroApplicationComponent. If we want to override those values, we can do it by defining them here.
params false ParamValue Values of parameters needed for application. If a parameter is required, but the value is not provided, an exception will be thrown. If a parameter value is provided, but not defined, a warning will be logged.
ParamValue
Field name Required Type Description
name true String Name of the parameter that we want pass to the micro-app.
value false String Value that will be passed to the micro-app.
WorkspacePage
Field name Required Type Description
pageId true String Unique page identifier
name false LocalizeText/String Name of the page. It’s used as label in container menu.
icon false String Page icon can be customized by providing image data or url (e.g. "icon": "data:image/svg+xml;utf8,%3Csvg xmlns...")
layout false PageLayout Page layout. Available options are: GRID and FULL_SCREEN. Default is GRID.
editable false boolean Indicates whether page is editable by the user (can the user reorder items or add new item). Default is false.
unlisted false boolean Indicates whether page is hidden from page lists in UI . Default is false.
items true WorkspacePageItem[] List of items (application instances) that are shown on the page.
WorkspacePageItem
Field name Required Type Description
pageItemId false String Unique identifier(not required), will be generated by container itself.
instanceId true String Reference to an existing instance in the workspace to be shown. If there is no instance, an exception will be thrown.
title false LocalizeText/String Title to be displayed. But it should be defined only in case if we want to override value from instance (name)
layout false PageItemLayout In case of ‘GRID’ page layout, it is used as a page item layout configuration. It holds position, size and state of item in layout. If not provided, default layout will be used

When using ‘grid’ page layout, following type is important for initial layout configuration.

PageItemLayout
Field name Required Type Description
column true Number In which column will item be rendered. Available values: 1 - 4
span true Number Over how many column should item span on page. Available values: 1 - 4
height true Number Height of the page item in pixels.
positionInColumn true Number Position of the item inside of the column

In order to provide multi-language support for all end-user visible fields, we have introduced LocalizedText. But, since many of the apps are usually only in Swiss German, to make easier definition, we allowed entering just a string, which by default will be treated as a LocalizedText with de_CH locale. And in case you need localization, you can do it in every json field of type LocalizedText by entering correct structure.

LocalizedText
Field name Required Type Description
key true String Unique translation key.
translations true Translation[] List of all translation.
Translation
Field name Required Type Description
locale true String Translation locale. (i.e. de_CH )
text true String Translation text.

Event Bus

Event Bus is a way for components to communicate with each other directly in GUI. Each component should be registered for events that consume and also for events which produces inside of container configuration. Events are nothing more than DOM events.

When micro-app publishes an event, all other micro-apps that are registered to listen for that event will receive it.

In your micro-app, you need to do some additional setup in order to listen for events. In following example we can see micro-app that listens for master-data-selected events.

class DetailsAppWebComponent extends HTMLElement {

    constructor() {
        super();
    }

    connectedCallback() {
        // Here we add a listener for 'master-data-selected' events sent by event bus.
        this.addEventListener("BV:master-data-selected", this.masterDataHandler);
        this.renderReact();
    }

    disconnectedCallback() {
        // Here we remove the listener for 'master-data-selected' to avoid duplicate listeners.
        this.removeEventListener("BV:master-data-selected", this.masterDataHandler);
    }

    masterDataHandler(event) {
        this.renderReact(event.detail);
    }

    renderReact( masterData = undefined ) {
        ReactDOM.render(<DetailsApp masterData={masterData} />, this);
    }
}
customElements.define("details-app", DetailsAppWebComponent);

You may have noticed that event listener uses ‘BV:’ prefix for events, that is because we expect events that are propagated from event bus. Behind the scene, master component sends event without the prefix, event bus catches the event, adds the prefix and propagate the event further. This is done to differentiate between incoming and outgoing events, so we can avoid infinite event loops.

To produce events from your micro-app, you can do the following:

let event = new Event("master-data-selected", {bubbles: true});
elem.dispatchEvent(event);

You can use this code anywhere in the app, because event will bubble up to the event bus. If you don’t want your events to bubble through dom tree, you need to fire events from web component root element.

There are also some predefined technical events available (no need for registration):

Note: Event bus does not work with IFRAME component type.

To see how navigation and tabs events are used, checkout the following sections.

Navigation

In BV Container there are three options for navigating from one micro-app to another:

All options have the following properties:

:warning: On IFRAME components both navigation types will not work because event bus is not supported in that case.

:warning: Event bus events are global. That means that if two pages are loaded in navigation stack, and event is fired from some micro-app, all micro-apps on both pages, that are registered for that specific event type, will receive fired event.

Page to page navigation

In “page to page” navigation option, user can navigate from current page to another page in same workspace. Navigation won’t be the same as simple page switch (via container navigation buttons). Current page state will be completely preserved. It can be imagined as a target page is just displayed ‘over’ the current page. You can also navigate further without any problems, all previous pages will be kept with its state. Navigation affects browser history. Address bar will be updated and back button on the browser will navigate to previous page. Let’s see how navigate to page works on example:

// Code inside of the micro-app in the current page...
const eventDetail = {
            pageId: "agenda",
            params: {
                "doctor": "doc123",
                "doctorData": {
                    "city": "Dublin",
                    "type": "pediatrician"
                }
            }
        };

element.dispatchEvent(new CustomEvent("navigate-to-page", {detail: eventDetail}));

In this example navigate-to-page event is fired. In event detail object it can be seen that target page is a page with id ‘agenda’. That target page should be present in a current workspace. Event detail also contains params object, which contains params for micro-apps on target page. For example, if on the target page there are two micro-apps, they will both accept provided parameters as web component attributes. See micro-app configuration for an example. In micro-app web component definition, these params can be retrieved by doing following:

class AgendaWebComponent extends HTMLElement {
    ...
    connectedCallback() {
        const doctor = this.getAttribute("doctor");
        const doctorData = this.getAttribute("doctorData");
        ReactDOM.render(<Agenda doctor={doctor} doctorData={doctorData} />, this);
    }
    ...
}
...

Navigation back to previous page user can achieved in following ways:

// Code inside of the micro-app in the current page...
element.dispatchEvent(new CustomEvent("navigate-to-previous-page"));

App to app navigation

In “app to app” navigation option, user can navigate from an micro-app instance in a page to some other micro-app instance defined in workspace instance repository. So it is not necessary for the target micro-app to be defined in a page. Event is quite similar to one in page-to-page navigation. Only difference is that in event detail object, we define targetInstanceId instead of pageId. In this option, page will not change, only target micro-app instance will be loaded over a micro-app that initiated navigate-to-app event. So target micro-app will replace just a space on a page where source micro-app is. Here is the example:

// Code inside of the micro-app in the current page...
const eventDetail = {
            targetInstanceId: "agendaApp123",
            params: {
                "doctor": "doc124",
                "doctorData": {
                    "city": "London",
                    "type": "pediatrician"
                }
            }
        };

element.dispatchEvent(new CustomEvent("navigate-to-app", {detail: eventDetail}));

In this example a micro-app initiates navigate-to-app event to load micro-app with instance id ‘agendaApp123’ and provides parameters for it.

Navigation back to previous app user can achieved by using navigate-to-previous-app event. Example for this event can be seen below

// Code inside of micro-app in a current page...
element.dispatchEvent(new CustomEvent("navigate-to-previous-app"));

One limitation of app-to-app navigation is that browser will not keep history of app navigation, so user cannot use browser back button. Also, header button will not be shown in this case.

Navigation to a single app in a page

This is a special case where user want to navigate to a micro app which is not defined in any page, but wants to have same navigation behaviour like in “page to page” navigation (browser history, back button, etc). Event used for this type of navigation is navigate-to-page-app and it is initiated in a similar way like “app to app” navigation event.

// Code inside of the micro-app in the current page...
const eventDetail = {
            targetInstanceId: "agendaApp123",
            params: {
                "doctor": "doc124",
                "doctorData": {
                    "city": "London",
                    "type": "pediatrician"
                }
            }
        };

element.dispatchEvent(new CustomEvent("navigate-to-page-app", {detail: eventDetail}));

Navigating back in this case is the same as in “page to page scenario”. So navigate-to-previous-page event is used for that.

Tabs navigation

Similar to “page to page” navigation, user can also open an app or a page into new tab, and in that way, preview multiple pages at the same time. Micro app implementer just needs to know page id or micro app instance id and with specific tabs event, that page or app will be opened in the new app.

But, there are few caveats tabs navigation:

The newly opened tab will take page name or micro app name as a title, but also custom title can be provided using event parameter customTitle.

Following is the example how can we open a page in the new tab:

// Code inside of the micro-app in the current page...
const eventDetail = {
            pageId: "agenda",
            params: {
                "customTitle": "Dr. Phil",
                "doctor": "doc123",
                "doctorData": {
                    "city": "Dublin",
                    "type": "pediatrician"
                }
            }
        };

element.dispatchEvent(new CustomEvent("open-page-in-tab", {detail: eventDetail}));

This code will open the page with id “agenda” in new tab and set the tab title to be “Dr. Phil”.

In a similar way we can open single micro app in new tab. Here is an example:

// Code inside of the micro-app in the current page...
const eventDetail = {
            targetInstanceId: "doc-viewer",
            params: {
                "customTitle": "Patient Smith (CT Scan 04.04.2020)",
                "patient": "123",
                "document": {
                    "id": "doc1",
                    "type": "pdf"
                }
            }
        };

element.dispatchEvent(new CustomEvent("open-app-in-tab", {detail: eventDetail}));

This code will open the “doc-viewer” app into full screen layout page in new tab with custom title.

State of the opened tabs is temporary. After browser page is reloaded, all tabs will lost.

Usage on mobile device

BV Container is completely responsive and adaptive when rendered from mobile browser or BV Mobile Container iOs app.

Communication between BV Container and BV Mobile is achieved with ‘Native’ events. When container is rendered inside of react-native app, ReactNativeWebView util object will be available globally in javascript window object. There are also NativeUtils available in container which is used for communication.

Available native events:

QR code generation

In order to use your app inside of BV Mobile Container iOS app, you need to generate QR code which will be scanned by the mobile app. QR code generator detects the page where user currently is. So if you want to display specific page / app in BV mobile app, first navigate to that page, and then generate QR code. QR code is also a way for user to authenticate.

QR code is only used in OAuth2 security scenario for now.

There is also possibility to generate QR code page outside of BV Container, which can be used as a login URL or with a third party software. Following is the example of such url:

http://my-bv-container/#/otp/workspace/my-workspace/page/my-page/

So the structure of the url is as following:

{URL-of-the-container-app}/#/otp{path-to-the-page}

Path to the page represents the page which will be loaded after user logs in via QR code. It can be also omitted, and in that case, user will be redirected to the home page.

Demo

In order to see Blue Vibes Container in action, we have provided a few demo purpose applications with the needed configuration. Thanks to the docker-compose, demo can be started by one command. Check here for more details. Access to the source code is needed for this.