Skip to Content
Technical Articles
Author's profile photo Marius Obert

Understanding the Nuts and Bolts of SAP Fiori Development in the Cloud Foundry Environment

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%20of%20the%20sample%20app%20in%20the%20FLP%20Sandbox

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 invited me to his show #HandsOnSAPDev where I spoke about the same topic; you can find the recording on YouTube.

 

My%20guest%20appearance%20at%20%23HandsOnSAPDev

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”.

Opened%20Sample%20App%20in%20the%20FLP%20Sandbox

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%20of%20the%20sample%20app%20in%20the%20FLP%20Sandbox

Tile of the sample app in the FLP Sandbox

Opened%20Sample%20App%20in%20the%20FLP%20Sandbox

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%20integrated%20sample%20app

The integrated sample app

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

User%20action%20menu

User action menu

Now you can remove entire sections and save your modification.

Removal%20of%20an%20section

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%20entitlement%20for%20step%204

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%20the%20new%20role%20collection%20%26%23x60%3BDeveloper%26%23x60%3B

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%20the%20scope%20to%20the%20role%20collection

Add the scope to the role collection

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

Navigate%20to%20the%20default%20IdP%20%28SAP%20ID%20Service%29

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%20the%20role%20collection%20to%20your%20user

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%20to%20the%20key-user%20mode

Switch%20to%20the%20key%20user%20mode

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%20the%20key%20user%20changes%20for%20all%20users

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

Assigned Tags

      38 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Ranjithkumar Ayyavu
      Ranjithkumar Ayyavu

      Hi Marius Obert,

      Thanks for the information. I tried to change the FLP setting using the CommanDataModel.json file. But its changing only in the run time FLP configuration. But i want to change the theme setting of FLP which is created in the site manager by using the portal services. I tried to give the sitedirectory Launchapad ID. But its not working.

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Thanks!

      I'm sorry I haven't found the time to get back to you on this question. I'm working on it.

      Author's profile photo Ranjithkumar Ayyavu
      Ranjithkumar Ayyavu

      Thanks Marius Obert.

      Author's profile photo Volker Buzek
      Volker Buzek

      one word: supercool!

      this ties together many pieces of the puzzle lots of UI5 devs struggle with. thanks a ton!

      Author's profile photo Jorge Sousa Villafaina
      Jorge Sousa Villafaina

      Amazing!! One of my new favourite bookmarks for ui5 dev!!
      As always, thanks a lot for your contribution Marius, this simplify a lot the cf services functionality understanding.

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      I'm glad you like it, thanks!

      Author's profile photo Jhodel Cailan
      Jhodel Cailan

      Awesome blog post Marius Obert !

      This is exactly what I need! I followed the steps and it worked like a charm! Thanks a lot for sharing!

      Cheers!

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Great that it worked, and thanks for your kind words!

      Author's profile photo Mio Yasutake
      Mio Yasutake

      Thank you for this post. It helps me understand basic structure of Cloud Foundry app.

      I have a small question.

      In approuter/xs-app.json, you specified '/cp.portal' as welcome file.

      Where does this file (or folder) come from?

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      This is a very good question! You are right, this route comes somewhat magically into play here.
      You can run "cf html5-list -a <approuter>" (given that you installed the CLI plugin) to see the full content of the HTML5 app repo.

      There, you will see that there is a web app named "cpportal" which has been inserted during the deployment phase and the route redirects traffic to this web app.

      Author's profile photo Jeremy Chabert
      Jeremy Chabert

      Hello Marius,

      Thanks for this blog ! It works like a charm and when using the specific approuter, I’m able to retrieve my application and place in my portal site at subaccount level.

      Now, what if instead of using an approuter specific to my application, I want to use the approuter managed by SAP Cloud Platform ?

      I’ve created the project as an MTA module, then inside it I ran this command@sap/fiori-elements to generate a Fiori Elements module.

      Then, this command npm run deploy to generate the mta for deploy.

      I thought adjusting the mta by deleting the approuter and pointing to the subaccount approuter would do the trick but it’s not. The project has no issue to be deployed, I can see it in the HTML5 Applications on subaccount level and it’s event recognized in the content provider on portal.

      BUT, when i try to open the application from the portal, i get this:

      com/test/myapp/Component.js’ from /comtestmyapp/~220920083911+0000~/Component.js: 502 – Bad Gateway

      Here’s my mta.yaml

      _schema-version: "3.2"
      ID: myapp
      version: 0.0.1
      modules:
      - name: myApp-destination-content
        type: com.sap.application.content
        requires:
        - name: uaa_myApp
          parameters:
            service-key:
              name: uaa_myApp-key
        - name: myApp_html_repo_host
          parameters:
            service-key:
              name: myApp_html_repo_host-key
        - name: myApp-destination-service
          parameters:
            content-target: true
        parameters:
          content:
            subaccount:
              destinations:
              - Name: com_test_myApp_myApp_html_repo_host
                ServiceInstanceName: myApp-html5-app-host-service
                ServiceKeyName: myApp_html_repo_host-key
                sap.cloud.service: com.test.myapp
              - Authentication: OAuth2UserTokenExchange
                Name: com_test_myapp_uaa_myApp
                ServiceInstanceName: myApp-xsuaa-service
                ServiceKeyName: uaa_myApp-key
                sap.cloud.service: com.test.myapp
              existing_destinations_policy: update
        build-parameters:
          no-source: true
      - name: myApp_ui_deployer
        type: com.sap.application.content
        path: .
        requires:
        - name: myApp_html_repo_host
          parameters:
            content-target: true
        build-parameters:
          build-result: resources
          requires:
          - artifacts:
            - comtestlyapp.zip
            name: comtestmyapp
            target-path: resources/
      - name: comtestmyapp
        type: html5
        path: myapp
        build-parameters:
          build-result: dist
          builder: custom
          commands:
          - npm install
          - npm run build:cf
          supported-platforms: []
      resources:
      - name: myApp-destination-service
        type: org.cloudfoundry.managed-service
        parameters:
          service: destination
          service-name: myApp-destination-service
          service-plan: lite
      - name: myApp_html_repo_host
        type: org.cloudfoundry.managed-service
        parameters:
          service: html5-apps-repo
          service-name: myApp-html5-app-host-service
          service-plan: app-host
      - name: uaa_myApp
        type: org.cloudfoundry.managed-service
        parameters:
          path: ./xs-security.json
          service: xsuaa
          service-name: myApp-xsuaa-service
          service-plan: application
      build-parameters:
        before-all:
        - builder: custom
          commands:
          - npm install

      and my xs-app.json

      {
          "welcomeFile": "/manifest.json",
          "authenticationMethod": "route",
          "routes": [
            {
              "source": "^/sap/(.*)$",
              "target": "/sap/$1",
              "destination": "GATEWAY_PP",
              "authenticationType": "xsuaa",
              "csrfProtection": false
            },
            {
              "source": "^(.*)$",
              "target": "$1",
              "service": "html5-apps-repo-rt",
              "authenticationType": "none"
            }
          ]
        }
      

      Do you have any ideas what could be wrong ?

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Jeremy,

      I'm glad you liked this post.
      The scenario that you described should work and I don't see an obvious issue in the MTA.yaml. A possible cause could be that the destinations are incorrect because they might refer to the wrong namespace or cloud service but that's hard to assess from here.

      By a happy coincidence, I'm currently writing another blog post about the same topic. I'd suggest waiting a week or two until I published that one as it will (hopefully) answer all your questions.

      Author's profile photo Jeremy Chabert
      Jeremy Chabert

      Great ! I'm looking forward to it.
      For now, I'll still dig on my own and try to find my issue.

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      I just published to post that explains what modules you need when you want SAP Cloud Platform to manage your HTML5 apps.

      Author's profile photo Jeremy Chabert
      Jeremy Chabert

      Great ! I'm reading it right now.

      Author's profile photo Badhusha Akhthaar
      Badhusha Akhthaar

      Hi Marius,

      This worked well for me. But if I want to add another app to the same lauchpad_portal, what are the things that remain the same or in other words, what files/configuration is common between both the application.

       

      Thanks,

      Badhusha

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi,

      this is a good question. There's not a lot of code that you need to adapt. It is important that both web apps have a unique ID to be able to differentiate them and then you need to add the second ID to the CommonDataModel file to include it to the Fiori Launchpad.

      You can use easy-ui5 to create an FLP web app and then you can use the sub-generator to add a second web app to the same project.

      Author's profile photo Badhusha Akhthaar
      Badhusha Akhthaar

      So this means both the apps should be in the current directory, in my case it will be like

      -ExampleApp
           - approuter
           - launchpad
           - uimodule1
           - uimodule2
           - deployer
           - mta.yaml

      or can we just refer the webapp's unique id in the CommonDataModel.json, after the HTML5 applications are deployed in the Repository ?

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      I haven't tested this before but it should also be possible

      Author's profile photo Manu Gupta
      Manu Gupta

      Hello Marius ,

      Can we achieve Key User UI adaptation for standalone app as well ? I don’t want to use fiori launchpad.

      Thanks,

      Manu

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Manu,

      yes, this is absolutely possible! For this reason, we offer the service as a separate service on SAP Cloud Platform. The integration would then work differently but I need to confess that I haven't done this yet. So I'm not sure how the setup would look.

      Author's profile photo Amey Mogare
      Amey Mogare

      Hello Marius,

       

      Thank you for such a wonderful blog!

      I have 2 standalone SAPUI5 applications running in subaccount#1 and I have activated Portal service on subaccount#2. (Both are Cloud Foundry).

      Now, I want to embed these two apps as tiles in Launchpad site I created in Portal service.

      Could you please let me know:

      1. Is it mandatory to to adapt these two apps as you mentioned in order to use them as in-place apps?
      2. How do I configure this subaccount#1 as HTML5 app provider for my Portal service?

       

      Warm Regards,

      Amey

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Amey,

      thanks for your kind words 🙂
      Are you using the Portal or the Launchpad service (there are slight differences between these two)?

      In general, there are two ways to add apps to the catalog. Option 1 is easier as the content explorer allows you to simply select the app from the HTML5 application repository. As of today, this can only be used when the apps are deployed to the same subaccount - but the team is working on a cross-subaccount feature.

      Option 2 requires a little bit more work but has the advantage that you can add any type of application. That includes web apps that are hosted on another subaccount or even a totally different platform. This is probably the more interesting option for you.

      Author's profile photo Amey Mogare
      Amey Mogare

      Hello Marius,

      Thank you for reply. I am using "Portal" service on my SAP Cloud Platform Cloud Foundry subaccount ==> this one https://discovery-center.cloud.sap/serviceCatalog/portal

      1. Options 1 & 2 you shared, I see those are for "Launchpad" service. Could you please let me know the same for "Portal" service too?
      2. Portal and Launchpad, is it safe to create instance of "Portal" service & use it? I hope there are no immediate plans to retire it.

      Warm regards,

      Amey

       

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Option 2 should also be possible with the Portal subscription and there are afaik no plans to retire it.

      Please note that the portal service instance that I mentioned in the post above is about the removed from trial (only from trial).

      Author's profile photo Amey Mogare
      Amey Mogare

      Thank you Marius, I will try this option 2 in my "Portal" service.

      Warm regards,

      Amey

      Author's profile photo Thomas Swolfs
      Thomas Swolfs

      Hi Marius,

      We are trying to use a Variant Manager inside a UI5 application deployed on the Fiori Launchpad Service (SCP CF).

      Our code works perfectly on on-premise S4Hana systems, but on SCP, we stumble on some issues.

      I added some screenshots and information in the question below. Have you encountered a similar problem? Do you have any insight that could help us?

      https://answers.sap.com/questions/13221476/variant-manager-personalization-service-not-workin.html

      Kind regards,

      Thomas

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Thomas,

      Thanks for pointing me to this issue. It is strange that it won't work in the Cloud environment. But I'm afraid this question is too deep for me. I'd follow Gregors suggestion and open an SAP Support Incident.

      Author's profile photo Frank Zhu
      Frank Zhu

      Hi Marius,

      Thanks for your excellent post. It's very useful.

      When I integrate with UI5 flexibility service, I encounter the below error message with our UI application. Do you have any idea about this error.

       

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi,

      I don't see an error message. Can you please add that again?

      Author's profile photo Frank Zhu
      Frank Zhu

      Hi Marius,

      Thanks for your reply. I find the two errors from browser console.

      when I access the UI application from fiori lanuch pad, it would load the key user settings from below endpoint and encounter the internal server error. The entire url shoud be : subscription host + domain + /keyuser/flex/keyuser/v1/settings

      when I try to click the 'Adapt UI' button, I am getting the below errors, I just wonder what the role shoud be granted. Since I find the role you add to user is 'FlexKeyUser', I only define the 'KeyUser' in xs-security.json, I can't find the 'FlexKeyUser' from subscribed sub-account.

      I only find these two roles from subscribed sub-account.

      from provider sub-account, I find all the relevant roles.

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      You mentioned that the URL should include your subscription host. Does that mean you use the managed approuter? If so, please note that you cannot integrate the key-user service there. This post here describes how to integrate the service with the approuter manually.

      Author's profile photo Frank Zhu
      Frank Zhu

      Hi Marius,

      Thanks very much. I'm just curious about why we can't integrate the key-user service with managed approuter, do you have any documentation we can refer, I just find some guidelines from sap helper(https://help.sap.com/viewer/0f8b49c4dfc94bc0bda25a19aa93d5b2/Cloud/en-US/a0aa4a0d62834a62b827fc97929405ba.html).

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Technically, this approach of this post won't work as you cannot bind a service instance to a subscription. So the features of the service instance would need to be embedded natively in the subscription (similar to how custom filter variants are supported).

      But for this discussion, I'd suggest reaching out internally to the product team.

      Author's profile photo Frank Zhu
      Frank Zhu

      Sure, thanks very much.

      Author's profile photo Abhinay Dogiparthi
      Abhinay Dogiparthi

      Hi Marius,

      In my case SAP UI5 App is created using SAP Business Application Studio with UI5 Version (1.71.41).
      Once the app is integrated to launchpad service(cloud) the goal here is hide the Fiori launchpad header.

      In SAP UI5's Component.js we are trying to hide the header as below code.

      if (sap.ushell.Container) {
      var oRenderer = sap.ushell.Container.getRenderer("fiori2");
      oRenderer.setHeaderVisibility(false);
      }

      But when I try to reopen the app again it gives duplicate id issue also if I click another tile the same app opens rather that different app.

      Is there any setting that we can auto hide the shell header of Fiori launchpad ?

      Regards,

      Abhi

      Author's profile photo Aleksandar Mijailovic
      Aleksandar Mijailovic

      Hi Abhi,

       

      interesting requirement, since usually one's goal is to have the Launchpad header, Navigation Buttons etc. and therefore the whole integration into the Launchpad Service..

      BR,

      Aleks

      Author's profile photo Abhinay Dogiparthi
      Abhinay Dogiparthi

      Hi Aleks,

      Yes since we have almost too many apps in one group and the header actually allows user to navigate to different apps while performing ongoing operations it is one of the use case to hide it in which we have separate BACK button functionality to go to shell home. It is perfectly working fine in SAP WEBIDE with ECC on premise systems with UI5 Version 1.52.46.

      Strangely the same logic is not working in 1.71.41 with Launchpad service.

      Regards,

      Abhi