Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
mariusobert
Developer Advocate
Developer Advocate
In this post, I demonstrate how existing SAPUI5 apps can be seamlessly integrated into the Fiori Launchpad on Cloud Foundry. This integration will go beyond just embedding the web app but also include the usage of the UI5 Flexibility Services.

Updates:

23rd Jul 2020: UI5 flexibility for key users is now available on the trial landscape as well

22nd Sep 2020: Added paragraph for SaaS subscriptions

19th Dec 2020: Adapt as the portal service instance will be removed from the trial landscape at the end of the year

29th Jan 2021: Rebranding to SAP BTP

22nd Mar 2021: Add performance tip

I already wrote about the integration of non-ui5 web apps in the Fiori Launchpad in a previous #CloudFoundryFun post. With that approach, a website or web app can be embedded in an iframe into the Launchpad. But that also brings a disadvantage; the iframe detaches the embedded web app from the Launchpad. Without this connection, the web app cannot use features of the Shell control or the UI5 Flexibility services. If you want to use these features, you'll need to implement the web app with SAPUI5 or reuse the Fiori Element templates (sap.fe.templates).


Tile of the demo app in the Fiori Launchpad


There is already a great post that explains all the necessary steps to create such an application using the SAP Web IDE. And you can use the easy-ui5 generator to create a similar app without having to deal with boilerplate code. This can be done with the SAP Business Application Studio or any other local IDE. 

This post, one the other hand, focuses on this boilerplate code. It will explain all the components and snippets that differentiate a Fiori Launchpad application from a regular SAPUI5 app – in other words: What is needed to convert a SAPUI5 web app to a Fiori Launchpad app. My friend and colleague dj.adams.sap.

 


My guest appearance at #HandsOnSAPDev


 

The Fiori Launchpad


The SAP Fiori launchpad is a shell that hosts SAP Fiori apps and provides the apps with services such as navigation, personalization, embedded support, and application configuration.

To efficiently implement Fiori apps, developers need a (sandbox) system that they can use during the development process. For this post's content, I will explain two ways to simulate this shell, which we will also use later.

Mocking the Fiori Launchpad with static resources


This approach is quite simple and, therefore, ideal for beginners. You just need to add another script to the index.html file and configure the Fiori Launchpad. With this, you can quickly mock the Fiori Launchpad locally within minutes. The disadvantage of this mock is that it is just that – a mock. While you can define plugins, they won't work as there is no backend system connected to them. Furthermore, you are always logged in as the "default user".


The sandbox mock with the "Default User"



Testing with a service instance


Note: This approach has been removed from the trial landscape but remains available in production accounts. Please use the Saas subscription option, which is explained in the next session, in trial environments.

This approach provides the full Fiori Launchpad experience. Once connected to the approuter, the portal service can read the information of the current user and expose the full functionality of the Fiori Launchpad - including plugins and shell services. The CommonDataModel.json configuration file defines the properties of the Fiori Launchpad.

Using this approach is Cloud-Foundry-easy. You just need to provision a service instance (service: portal, plan: standard) and connect this service instance to your approuter. A deployer module will configure the service based on the configuration file. This module is a Cloud Foundry task and part of the MTA project, as we will see later.

The full (Software as a) Service


The previous approach helps you to create a fully functional Fiori Launchpad experience that can be created by any developer without special roles and permissions. The developer can configure the development sandbox (apps, catalogs, etc.) freely in a text file - the so-called CommonDataModel.json.

For production use-cases, however, you need an admin who will use the Site Manager UI. In this UI, the admin can manage all sites (Site Directory) and content (Content Manager) to assigned roles to apps and apps to group. These features are delivered by two SAP BTP services, which are both offered as a subscription on the subaccount-level:

Please refer to this post if you want to learn more about the similarities and differences between them

UI5 Flexibility Services


The UI5 flexibility services make it possible to tailor standard apps to the individual needs of the end-users. These adoptions are applied per-user (aka personalization) or per-group (aka key user adaptions). These services fulfill the demand that the business apps need the flexibility to rearrange UI elements and display or hide information depending on the user's individual needs and the domain they are working in.

For this, it's crucial to use stable IDs for all controls so that the modifications can be tracked and stored reliably. The UI5 support assistant can help you in case you are not sure if all of your IDs are stable.

The flex services have been available for a while now. While the LREP (layered repository) enables these services in ABAP systems, the following two services do this in non-ABAP systems:

UI5 Flexibility Personalization Service


The name already suggests that this service stores the customizations of an individual user.

The interaction with this service typically happens in a WYSIWYG-matter. E.g., when end-users rearrange the element in the Overview page, save their filter variants in list reports, select the content of smart links in the context popover. Additionally to this "in-place" personalization, users can select the "Personalize App" item in the user action menu to show and hide entire sections of the object pages.

This sample application mocks the filter variant feature of the smart filter bar. All other mentioned personalization features can be tested in this second sample application.

Consuming this service is quite easy. If you already use the portal service, you won't have to do anything! It makes much sense to use personalization service combined with the Fiori Launchpad. Which is why the personalization service is already "stacked" on top of the portal service. All you need to do is integrating your app in the FLP.

 

UI5 Flexibility for Key Users


Different target groups are using the service for key users, and regular end-users might not even be aware of this service. The service is only visible selected domain experts - the key users. With this domain knowledge, they know which smart filter variants are especially useful for their business and which views are essential. With the right role collection assigned, they can save filters that are reusable by all end-users. Besides this, key users are also able to customize object pages. They can change labels, hide or add new fields and fragments. The latter feature can be tested with this demo app when you select "Adapt UI" from the user action menu. These features take work off application developers and enable quick iterations when fine-tuning business applications.

This service is available since June 15th and can be used for both - standalone apps and Fiori apps that are part of the Fiori Launchpad. For this reason, developers need to provide the service and wire it up with the web application. The following hands-on will explain all the necessary steps to do this.

Performance tip


Requests for i18n files that return HTTP code 404 will slow down your web app. Many times the locale includes the country while the translation in the i18n doesn’t include the country causing the UI5 fallback and the many redundant 404.

So it is highly recommended to check the console logs and provide the missing translation files, providing also full locale language and country, to avoid the UI5 fallback logic.


For better performance, resource bundles are cached and these redundant calls to the server can be avoided.

Hands-on: Integrate a SAPUI5 App in the Fiori Launchpad


Note: This approach has been removed from the trial landscape but remains available in production accounts. 

0 Preparation


Before we get to the fun part, we need to install some necessary tools for cloud development on SAP BTP, Cloud Foundry environment (if you haven't done so already):

In either case, you also need to Set Up SAP Launchpad Service

1 Clone the UI5 sample app


Clone the sample app from the SAP organization or fork it and clone your fork. Open the project in the Business Application Studio. In case you are using a local IDE, open the project with this IDE.
git clone https://github.com/SAP/openui5-sample-app
code openui5-sample-app

2 Modify the UI5 sample app


2.1 Change the web app descriptor


The default manifest is missing a couple of configurations. Replace the current file with the following content to add properties like the version number, title, and description. This new file also contains a default route and an inbound navigation intent that the Fiori Launchpad uses to open the app.
{
"_version": "1.12.0",
"sap.app": {
"id": "sap.ui.demo.todo",
"type": "application",
"i18n": "i18n/i18n.properties",
"applicationVersion": {
"version": "1.0.0"
},
"title": "{{ToDoList}}",
"description": "{{ToDoList}}",
"crossNavigation": {
"inbounds": {
"intent1": {
"signature": {
"parameters": {},
"additionalParameters": "allowed"
},
"semanticObject": "data",
"action": "display",
"title": "Sample App",
"icon": "sap-icon://add"
}
}
}
},
"sap.ui": {
"technology": "UI5",
"icons": {},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
}
},
"sap.ui5": {
"rootView": {
"viewName": "sap.ui.demo.todo.view.App",
"type": "XML",
"async": true,
"id": "app"
},
"flexEnabled": true,
"contentDensities": {
"compact": true,
"cozy": true
},
"dependencies": {
"minUI5Version": "1.75.0",
"libs": {
"sap.ui.core": {},
"sap.m": {},
"sap.f": {},
"sap.ui.unified": {}
}
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "sap.ui.demo.todo.i18n.i18n",
"supportedLocales": [
"en",
"de"
],
"fallbackLocale": "en"
}
},
"": {
"type": "sap.ui.model.json.JSONModel",
"uri": "model/todoitems.json"
}
},
"resources": {
"css": [
{
"uri": "css/styles.css"
}
]
},
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"viewPath": "sap.ui.demo.todo.view.App",
"controlId": "app",
"controlAggregation": "pages",
"async": true
},
"routes": [
{
"name": "RouteMainView",
"pattern": "",
"target": [
"TargetMainView"
]
}
],
"targets": {
"TargetMainView": {
"viewType": "XML",
"viewLevel": 1,
"viewId": "app",
"viewName": "MainView"
}
}
}
}
}

2.2 Remove header and add an Object Page


The sample app includes a page header that won't be necessary any longer as the Fiori Launchpad comes with a header. Remove <customHeader> and add another page to test the personalization service later:
<mvc:View xmlns:mvc="sap.ui.core.mvc" 
xmlns:core="sap.ui.core"
xmlns="sap.m"
xmlns:uxap="sap.uxap"
xmlns:layout="sap.ui.layout"
xmlns:f="sap.f" controllerName="sap.ui.demo.todo.controller.App" displayBlock="true">
<App>
<Page showHeader="false">
<content>
<f:DynamicPage >
.....
</f:DynamicPage>
</content>

<uxap:ObjectPageLayout id="ProductDetail">
<uxap:sections>
<uxap:ObjectPageSection id="sec1" title="Section 1">
<uxap:subSections>
<uxap:ObjectPageSubSection id="subSection1" title="">
<uxap:blocks>
<Label id="sec1Label" text="Label 1" />
</uxap:blocks>
</uxap:ObjectPageSubSection>
</uxap:subSections>
</uxap:ObjectPageSection>
<uxap:ObjectPageSection id="sec2" title="Section 2">
<uxap:subSections>
<uxap:ObjectPageSubSection id="subSection2" title="">
<uxap:blocks>
<Label id="sec2Label" text="Label 2" />
</uxap:blocks>
</uxap:ObjectPageSubSection>
</uxap:subSections>
</uxap:ObjectPageSection>
</uxap:sections>
</uxap:ObjectPageLayout>
</Page>
</App>
</mvc:View>

2.3 Replace an index.html with Fiori Sandbox


For preliminary testing, we want to leverage the FLP Sandbox resources. To do so, replace the current index.html file, which starts the web app as a standalone app, with this sandbox environment.
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Fiori Launchpad Sandbox</title>

<script>
window["sap-ushell-config"] = {
defaultRenderer: "fiori2",
bootstrapPlugins: {
"KeyUserPlugin": {
"component": "sap.ushell.plugins.rta"
},
"PersonalizePlugin": {
"component": "sap.ushell.plugins.rta-personalize"
}
},
applications: {
"show-demo": {
title: "Demo App",
icon: "sap-icon://add",
additionalInformation: "SAPUI5.Component=sap.ui.demo.todo",
applicationType: "URL",
url: "./",
navigationMode: "embedded"
},
}
};
</script>

<script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/test-resources/sap/ushell/bootstrap/sandbox.js">
</script>

<script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-resourceroots='{
"sap.ui.demo.todo": "./"
}' data-sap-ui-theme="sap_fiori_3" data-sap-ui-compatVersion="edge" data-sap-ui-async="true"
data-sap-ui-frameOptions="allow">
</script>


<script>
sap.ui.getCore().attachInit(() => sap.ushell.Container.createRenderer().placeAt("content"));
</script>
</head>

<body class="sapUiBody" id="content"></body>

</html>

2.4 Run it


Run the app locally to see the sample app in the FLP Sandbox
cd openui5-sample-app/
yarn install
yarn start

The App Studio will show a popup that asks whether you want to expose the open port. Confirm this question and access the index.html file. For local IDEs: Access http://localhost:8080/index.html with the browser of your choice.

You'll see an FLP Sandbox that contains one app:


Tile of the sample app in the FLP Sandbox



Opened sample app in the FLP Sandbox


All changes in this step can be found here.

3 Convert the sample app to a Cloud Foundry project and add the portal service


For this conversion, we need to add a few more modules and tie them together in the overall project files.

3.1 Add routing definition to the web app


The web app shall be stored in the HTML5 Application Repository. This repository has the requirement that each web app needs to contain a webapp/xs-app.json file, which includes at least the following lines.
{
"welcomeFile": "flpSandbox.html",
"routes": [{
"source": "^(.*)",
"target": "$1",
"authenticationType": "xsuaa",
"service": "html5-apps-repo-rt"
}]
}

3.2 Add the application router module


The approuter will be used as a single entry point for your web application and is connected to the HTML5 application repository. Create the approuter/package.json module descriptor.
{
"name": "demo",
"version": "0.0.1",
"engines": {
"node": "12.x.x"
},
"scripts": {
"start": "node node_modules/@sap/approuter/approuter.js"
},
"dependencies": {
"@sap/approuter": "^7.1.0"
}
}

The only other file of this module contains its configuration. Create another file approuter/xs-app.json with the following content.
{
"welcomeFile": "/cp.portal",
"authenticationMethod": "none",
"logout": {
"logoutEndpoint": "/do/logout"
},
"routes": [ ]
}

3.3 Add the deployer module


The approuter will serve the sample app from the HTML5 Application Repository. The deployer module will take the minified app and upload it to this repository. Create the following deployer/package.json file. This is all you need to do to set this deployed module up.
{
"name": "webapp-deployer",
"engines": {
"node": "12.x.x"
},
"dependencies": {
"@sap/html5-app-deployer": "2.1.0"
},
"scripts": {
"start": "node node_modules/@sap/html5-app-deployer/index.js"
}
}

3.4 Add the launchpad module


Like the previous module, there needs to be an application (better: task) that uploads the Launchpad configuration to the service instance and applies it. This app is defined in the launchpad/package.json file:
{
"name": "launchpad-site-content",
"description": "Portal site content deployer package",
"engines": {
"node": "12.X"
},
"dependencies": {
"@sap/portal-cf-content-deployer": "3.32.0-20200312112659"
},
"scripts": {
"start": "node node_modules/@sap/portal-cf-content-deployer/src/index.js"
}
}

And the following configuration is described in launchpad/portal-site/CommonDataModel.json.
{
"_version": "3.0.0",
"identification": {
"id": "c9aae627-9601-4a11-83c3-41b94a3c8026-1576776549699",
"entityType": "bundle"
},
"payload": {
"catalogs": [
{
"_version": "3.0.0",
"identification": {
"id": "defaultCatalogId",
"title": "Catalog Title",
"entityType": "catalog",
"i18n": "i18n/i18n.properties"
},
"payload": {
"viz": [
{
"id": "sap.ui.demo.todo",
"vizId": "data-display"
}
]
}
}
],
"groups": [{
"_version": "3.0.0",
"identification": {
"id": "defaultGroupId",
"title": "Group",
"entityType": "group"
},
"payload": {
"viz": [
{
"id": "sap.ui.demo.todo-1",
"appId": "sap.ui.demo.todo",
"vizId": "data-display"
}
]
}
}],
"sites": [
{
"_version": "3.0.0",
"identification": {
"id": "b9ad73bb-384c-4740-b39a-7f0fad5e6acc-1576776549700",
"entityType": "site",
"title": "SAP Fiori launchpad site on Cloud Foundry",
"description": ""
},
"payload": {
"config": {
"ushellConfig": {
"bootstrapPlugins": {
"PersonalizePlugin": {
"component": "sap.ushell.plugins.rta-personalize"
}
},
"renderers": {
"fiori2": {
"componentData": {
"config": {
"applications": {
"Shell-home": {}
}
}
}
}
}
}
},
"groupsOrder": [
"defaultGroupId"
],
"sap.cloud.portal": {
"config": {
"theme.id": "sap_fiori_3",
"theme.active": [
"sap_fiori_3"
]
}
}
}
}
]
}
}

3.5 Configure the XSUAA service instance


The xsuaa service instance manages the application security details and needs multiple parameters to be set up correctly. Add this configuration to the xs-security.json file, which will be referenced by the xsuaa service instance in the next sub-step.
{
"xsappname": "sample",
"tenant-mode": "dedicated",
"description": "Security profile of called application",
"scopes": [
{
"name": "uaa.user",
"description": "UAA"
}
],
"role-templates": [
{
"name": "Token_Exchange",
"description": "UAA",
"scope-references": [
"uaa.user"
]
}
]
}

3.6 Tie it all together


Add the following mta.yaml project descriptor to the root level of the project. This file contains all of the modules mentioned above, as well as the service instances that are hooked up to them.
ID: sample
_schema-version: 3.2.0
description: Enter description here
version: 0.2.0
parameters:
enable-parallel-deployments: true

modules:
- name: sample
type: nodejs
path: approuter
parameters:
disk-quota: 512M
memory: 512M
requires:
- name: sample_uaa
- name: sample_html5_repo_runtime
- name: sample_portal
- name: sample_deployer
type: com.sap.html5.application-content
path: deployer
requires:
- name: sample_html5_repo_host
build-parameters:
builder: custom
commands:
- npm run build:ui --prefix ..
- name: sample_launchpad_deployer
type: com.sap.portal.content
path: launchpad
deployed-after:
- sample_deployer
requires:
- name: sample_portal
- name: sample_html5_repo_host
- name: sample_uaa

resources:
- name: sample_uaa
type: org.cloudfoundry.managed-service
parameters:
path: ./xs-security.json
service-plan: application
service: xsuaa
- name: sample_html5_repo_runtime
type: org.cloudfoundry.managed-service
parameters:
service-plan: app-runtime
service: html5-apps-repo
- name: sample_html5_repo_host
type: org.cloudfoundry.managed-service
parameters:
service-plan: app-host
service: html5-apps-repo
config:
sizeLimit: 1
- name: sample_portal
type: org.cloudfoundry.managed-service
parameters:
service-plan: standard
service: portal

Last but not least, add the following dependencies and build/deploy scripts to allow a smooth deployment.
{
"scripts": {
...
"build:mta": "mbt build",
"deploy:cf": "cross-var cf deploy mta_archives/sample_$npm_package_version.mtar",
"deploy": "run-s build:mta deploy:cf",
"build:ui": "ui5 build --clean-dest --include-task=generateManifestBundle --dest deployer/resources/webapp"
},
"devDependencies": {
...
"cross-var": "^1.1.0",
"mbt": "1.0.14",
"npm-run-all": "^4.1.5"
}
}

3.7 Deploy the web application to the Fiori Launchpad


Click the CF connector on the bottom-left corner of the App Studio (or run cf login) to connect to your Cloud Foundry endpoint. Execute the following commands to trigger the build and deployment of your code:
cd openui5-sample-app
yarn install
yarn run deploy

3.8 Test the personalization service


You can find the URL of the launchpad page in the terminal output once the deployment finished - access this URL. And click on the tile that represents the sample app.


The integrated sample app


Select "Personalize App" from the user action menu and scroll down to the Object Page.


User action menu


Now you can remove entire sections and save your modification.


Removal of a section


Test the personalization from a different browser to see that it has been persisted. The section will still be visible when you log in with another user.

All changes in this step can be found here.

4 Integrate the key user service



Needed entitlement for step 4



4.1 Add service to the project descriptor


Add a service instance of the key user service to the mta.yaml descriptor. Define the service instance and link it to the approuter.
...
modules:

- name: sample
...
requires:
- name: sample_flexibility_keyuser

resources:
...
- name: sample_flexibility_keyuser
parameters:
service-plan: keyuser
service: ui5-flexibility-keyuser
type: org.cloudfoundry.managed-service

4.2 Add new route


We already linked the key user service instance to the approuter module. Now we have to define the route which forwards traffic to the service (in the xs-app.json file).
{
"welcomeFile": "/cp.portal",
"authenticationMethod": "none",
"logout": {
"logoutEndpoint": "/do/logout"
},
"routes": [{
"source": "^/keyuser/(.*)$",
"target": "$1",
"service": "com.sap.ui.flex.cf.keyuser",
"endpoint": "keyuser"
}]
}

4.3 Add service to the portal


The approuter is now ready to accept incoming "key user changes". Change the configuration of the portal service in launchpad/portal-site/CommonDataModel.json to activate the key user plugin in the SAP Fiori Launchpad and to set the corresponding connector up.
{
...
"payload": {
"sites": {
"payload": {
"config": {
"ushellConfig": {
"bootstrapPlugins": {
"KeyUserPlugin": {
"component": "sap.ushell.plugins.rta"
},
...
...
"sap.cloud.portal": {
"config": {
...
"flexibilityServices": [{
"connector": "KeyUserConnector",
"url": "/keyuser"
}]
...

4.4 Redeploy the application to SAP BTP


yarn run deploy

4.5 Add a role to your user


Browse to the SAP Cloud Cockpit (or to the production landscape) and navigate to your subaccount. Under Security, click on Role Collections and click the New Role Collection button. Choose any name for this role collection.


Adding the new role collection "Developer"


Click Add Role and select the application identifier that starts with "ui5-flexibility-keyuser", the suffix might vary in your account. Confirm with Save.


Add the scope to the role collection


Go back to the subaccount and select Trust Configuration and the SAP ID Service.


Navigate to the default IdP (SAP ID Service)


Search for your user by entering the associated email address, click Assign Role Collection, and choose the role collection you just created.


Assign the role collection to your user



4.6 Key user


Navigate to the SAP Fiori Launchpad app and log out and back in again to ensure the new role collection takes effect. Now you can select Adapt UI from the user action menu.



Switch to the key user mode


The UI will change into the key user mode, and you can remove the only fragment of the To-Do app. Use the activation icon on the top-left to activate the change and click Save & Exit to return to the standard application mode.


Activate the key user changes for all users


You can now ask a friend to access the same web app. Your friend won't see the To-Do list now because the key user changes apply to everyone.

All changes in this step can be found here.

Summary


In this post, you have learned:

  • How to deploy the UI5 sample app to the SAP Fiori Launchpad on Cloud Foundry

  • About the different options to mock the Fiori Launchpad environment

  • What functionality is offered by the UI5 Flexibility services

  • How to leverage Cloud Foundry services to create an SAP Fiori Launchpad app with SAPUI5

  • How to establish a route that redirects traffic to a Cloud Foundry service instance


Did you like this post? If so, you might also like this post that can be seen as "Advanced concepts of Fiori Development in SAP BTP, Cloud Foundry environment"

Next Steps



  • Have a look at your entire codebase as a whole and familiarize yourself with it 

  • (or on GitHub)

  • Embed your SAPUI5 apps in the SAP Launchpad Service

  • Use easy-ui5 to bootstrap Fiori Apps in one-step (+ tutorial)

  • Learn more about the UI5 Flexibility services

38 Comments