Technical Articles
XSA Fiori Launchpad On-Premise Configuration With Cross-MTA Dependencies and UAA.
If you have read a couple of my previous blogs you will be able to follow my journey configuring the Fiori Launchapd on XSA. This most recent post presents what I feel is the ideal configuration, allowing the use of multiple MTA’s for your applications while retaining UAA support.
If you have been trying to setup a Fiori Launchpad on XSA, I am sure you are familiar with the official SAP documentation in the following link: https://help.sap.com/viewer/4505d0bdaf4948449b7f7379d24d0f0d/2.0.04/en-US/8a583342d1c64822837fe49efbafdb53.html
While much of the information is present in the documentation, I feel the instructions are incomplete and unclear.
I have a working sample configuration prepared and available in my github: https://github.com/bigsmity/xsalaunchpaddemo
“launchpaddemoapp2” is where all the magic happens for this blog. I have left the previous configurations available even though they are now obsolete.
The main difference is the change from using the @sap/approuter to using @sap/site-app-server. At the time of writing no working templates appear to exist in the public domain for this configuration.
With this setup, you only need to write config in the MTA of the UI5 application. This implementation is independent of the launchpad configuration.
Let’s get into it.
UI5 Application Setup
Create a new MTA called “launchpaddemoapp2” and add a SAPUI5 HTML5 Module called “launchpaddemoapp2_ui”.
Create a folder called “site” directly in the UI5 module folder.
Create a file called “site-content.json” in the “site” folder you just created.
Your folder structure should look as follows:
Paste in the example site-content.json content from the SAP provided documentation as a starting point. Please note the source provided in the official documentation is missing the last closing bracket ‘}’. There is also a leading space in the group Id field. Both of these have been corrected in the snippet below
site-content.json Starting point (corrected from SAP documentation)
{
"roles": {
"Everyone": {
"_version": "1.0",
"identification": {
"id": "Everyone",
"namespace": "",
"entityType": "role"
},
"payload": {
"catalogs": [],
"groups": [{
"id": "MyGroupId"
}]
}
}
},
"applications": {
},
"groups": {
"MyGroupId": {
"identification": {
"id": "MyGroupId",
"i18n": "i18n/i18n.properties",
"namespace": "",
"title": "{{ MyGroupId_GROUP_TITLE}}"
},
"payload": {
"tiles": [{
"id": "SampleTile",
"subTitle": "{{SampleTile_SUB_TITLE}}",
"appId": "MyUniqueAppID",
"target": {
"semanticObject": "myApp",
"action": "show",
"parameters": []
}
}]
}
}
}
}
Update the site-content.json with your Group, Tile and Application configuration
site-content.json complete, configured
{
"roles": {
"Everyone": {
"_version": "1.0",
"identification": {
"id": "Everyone",
"namespace": "",
"entityType": "role"
},
"payload": {
"catalogs": [],
"groups": [{
"id": "launchpaddemoapp2_ui_GroupId"
}]
}
}
},
"applications": {
"launchpaddemoapp2_ui": {
"sap.app": {
"_version": "1.3.0",
"id": "launchpaddemoapp2_ui",
"title": "Launchpad Demo App2",
"i18n": "i18n/i18n.properties",
"tags": {
"keywords": []
},
"crossNavigation": {
"inbounds": {
"launchpaddemoapp2_uiShow": {
"semanticObject": "launchpaddemoapp2_ui",
"action": "show",
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"signature": {
"parameters": {},
"additionalParameters": "allowed"
}
}
},
"outbounds": {}
}
},
"sap.ui": {
"_version": "1.3.0",
"technology": "UI5"
},
"sap.ui5": {
"componentName": "launchpaddemoapp2_ui",
"_version": "1.2.0"
},
"sap.platform.runtime": {
"componentProperties": {
"url": "/"
}
}
}
},
"groups": {
"launchpaddemoapp2_ui_GroupId": {
"identification": {
"id": "launchpaddemoapp2_ui_GroupId",
"i18n": "i18n/i18n.properties",
"namespace": "",
"title": "Launchpad Demo App"
},
"payload": {
"tiles": [{
"id": "launchpaddemoapp2_ui_tile",
"title": "Launchpad Demo App2",
"subTitle": "launchpad demo app2",
"icon": "sap-icon://share-2",
"appId": "launchpaddemoapp2_ui",
"target": {
"semanticObject": "launchpaddemoapp2_ui",
"action": "show",
"parameters": []
}
}]
}
}
}
}
Update the manifest.json and add the cross navigation settings to the “sap.app” section
"crossNavigation": {
"inbounds": {
"launchpaddemoapp2_uiShow": {
"title": "Launchpad Demo App2",
"icon": "sap-icon://share-2",
"semanticObject": "launchpaddemoapp2_ui",
"action": "show",
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
}
}
},
"outbounds": {}
}
Update the manifest.json and add the component properties to the root level object.
"sap.platform.cf": {},
"sap.platform.runtime": {
"componentProperties": {
"url": "/resources/webapp"
}
}
Update the manifest.json file to add the component name to the “sap.ui5” object
"componentName": "launchpaddemoapp2_ui",
manifest.json complete, configured
{
"_version": "1.1.0",
"sap.app": {
"_version": "1.1.0",
"id": "launchpaddemoapp2_ui",
"type": "application",
"i18n": "i18n/i18n.properties",
"applicationVersion": {
"version": "1.0.0"
},
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"ach": "ach",
"sourceTemplate": {
"id": "hanatemplates.basicSAPUI5ApplicationProject",
"version": "0.0.0"
},
"crossNavigation": {
"inbounds": {
"launchpaddemoapp2_uiShow": {
"title": "Launchpad Demo App2",
"icon": "sap-icon://share-2",
"semanticObject": "launchpaddemoapp2_ui",
"action": "show",
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
}
}
},
"outbounds": {}
},
"dataSources": {
"appDataSource": {
"uri": "launchpaddemoapp2_js_dest/xsodata/APP_DATA.xsodata/",
"type": "OData",
"settings": {
"odataVersion": "2.0"
}
}
}
},
"sap.ui": {
"_version": "1.1.0",
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone@2": "",
"tablet": "",
"tablet@2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": [
"sap_hcb",
"sap_bluecrystal"
]
},
"sap.ui5": {
"_version": "1.1.0",
"componentName": "launchpaddemoapp2_ui",
"rootView": {
"viewName": "launchpaddemoapp2_ui.view.View1",
"type": "XML"
},
"dependencies": {
"minUI5Version": "1.30.0",
"libs": {
"sap.ui.core": {},
"sap.m": {},
"sap.ui.layout": {},
"sap.ushell": {},
"sap.collaboration": {},
"sap.ui.comp": {},
"sap.uxap": {}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "launchpaddemoapp2_ui.i18n.i18n"
}
},
"app_data": {
"dataSource": "appDataSource"
}
},
"resources": {
"css": [{
"uri": "/css/style.css"
}]
},
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"async": true,
"viewPath": "launchpaddemoapp2_ui.view",
"controlAggregation": "pages",
"controlId": "idAppControl"
},
"routes": [{
"name": "RouteView1",
"pattern": "RouteView1",
"target": ["TargetView1"]
}],
"targets": {
"TargetView1": {
"viewType": "XML",
"transition": "slide",
"clearAggregation": true,
"viewName": "View1"
}
}
}
},
"sap.platform.cf": {},
"sap.platform.runtime": {
"componentProperties": {
"url": "/resources/webapp"
}
}
}
Open the package.json file, you will see the following approuter configuration:
{
"name": "launchpaddemoapp2_ui-approuter",
"engines": {
"node": ">=4.0.0 <9.0.0"
},
"dependencies": {
"@sap/approuter": "6.1.0"
},
"scripts": {
"start": "node node_modules/@sap/approuter/approuter.js"
}
}
We will need to replace this with a site-app-server configuration:
{
"name": "launchpaddemoapp2_ui",
"engines": {
"node": ">=4.0.0 <9.0.0"
},
"dependencies": {
"@sap/site-app-server": "^1.9.x"
},
"scripts": {
"start": "node node_modules/@sap/site-app-server/index.js"
}
}
Open the xs-app.json file, enable UAA and add the standard route
{
"welcomeFile": "webapp/index.html",
"authenticationMethod": "route",
"routes": [{
"source": "^/(.*)$",
"localDir": "resources/webapp"
}]
}
Open the mta.yaml file and add the reference to the target Fiori Launchpad
- name: flp-launchpaddemoapp2-client
type: com.sap.portal.site-content
parameters:
config:
siteId : launchpaddemo
The siteId property is the ID value of the mta.yaml containing the Fiori Launchpad
Add the requires reference to the UI5 application
- name: launchpaddemoapp2_ui
type: html5
path: ui
requires:
- name: flp-launchpaddemoapp2-client
- name: launchpaddemoapp2_uaa
- name: launchpaddemoapp2_js_api
group: destinations
properties:
name: launchpaddemoapp2_js_dest
url: '~{url}'
forwardAuthToken: true
mta.yaml complete, configured
ID: launchpaddemoapp2
_schema-version: '2.1'
version: 0.0.1
modules:
- name: launchpaddemoapp2_db
type: hdb
path: db
properties:
SAP_JWT_TRUST_ACL:
- clientid: '*'
identityzone: '*'
requires:
- name: launchpaddemoapp2_uaa
- name: hdi_launchpaddemoapp2_db
properties:
TARGET_CONTAINER: '~{hdi-container-name}'
- name: launchpaddemoapp2_js
type: nodejs
path: js
properties:
CORS:
- uriPattern: .
allowedMethods:
- GET
- POST
allowedOrigin:
- host: '*'
SAP_JWT_TRUST_ACL:
- clientid: '*'
identityzone: '*'
provides:
- name: launchpaddemoapp2_js_api
public: true
properties:
url: ${default-url}
requires:
- name: launchpaddemoapp2_uaa
- name: hdi_launchpaddemoapp2_db
- name: launchpaddemoapp2_db
- name: launchpaddemoapp2_ui
type: html5
path: ui
properties:
CORS:
- uriPattern: .
allowedMethods:
- GET
- POST
allowedOrigin:
- host: '*'
SAP_JWT_TRUST_ACL:
- clientid: '*'
identityzone: '*'
requires:
- name: flp-launchpaddemoapp2-client
- name: launchpaddemoapp2_uaa
- name: launchpaddemoapp2_js_api
group: destinations
properties:
name: launchpaddemoapp2_js_dest
url: '~{url}'
forwardAuthToken: true
resources:
- name: hdi_launchpaddemoapp2_db
properties:
hdi-container-name: ${service-name}
type: com.sap.xs.hdi-container
- name: launchpaddemoapp2_uaa
parameters:
service: xsuaa
service-plan: space
type: com.sap.xs.uaa
- name: flp-launchpaddemoapp2-client
type: com.sap.portal.site-content
parameters:
config:
siteId : launchpaddemo
Build and deploy your application, then run your launchpad.
The group and Tile can now be seen.
Click the Tile to launch the UI5 application.
There you have it, you now have a correctly configured Fiori Launchpad! Tiles are self contained, and UAA is available!
It should be noted when using the site-app-server, you lose the ability to run the UI5 application in the workspace context. My current solution is to modify the package.json file when developing in Web IDE:
{
"name": "launchpaddemoapp2_ui",
"engines": {
"node": ">=4.0.0 <9.0.0"
},
"dependencies": {
"@sap/site-app-server": "^1.9.x",
"@sap/approuter": "6.1.0"
},
"scripts": {
"start": "node node_modules/@sap/site-app-server/index.js",
"dontstart": "node node_modules/@sap/approuter/approuter.js"
}
}
I keep the dependency for both node modules, but switch the name of the start script from “start” to “dontstart”.
Hi Bradley,
Thank you for your very informative samples and explanation. With your help I have manage to setup my own fiori launchpad with its tiles. However, I have lucked out on the roles part. If i set the roles to Everyone, the tiles are displayed but if assigned to a certain roles, it goes missing. Any idea on how we can control tile display on the fiori launchpad ? Have you had success on role level control at fiori launchpad either displaying the tile or launching the tile application.
i raised the question in the community as well.
https://answers.sap.com/questions/13048624/xsa-fiori-launchpad-not-displaying-application-til.html
Hope you can help or give some hints or even how to trace it. Your help is greatly appreciated.
Thanks.
Anand
Hi Anand,
I am glad you have found my blog useful. I have configured the tile visibility successfully in the past and have replied directly to your question with some details that should help.
Thanks,
Brad.
Anand,
Did you make this solution work? If so can you share some code snippet?
Hi Anil,
Yes I did. As per suggest by Bradley we need to update both xs-security.json for both in the application and also in the fiori launchpad mta.
In the application following is needed. The "granted-apps" and "grant-as-authority-to-apps" needs to reference the fiori launchpad id.
"scopes": [{
"name": "$XSAPPNAME.Display",
"description": "display",
"granted-apps": ["dcmhubflp","dcmhubflp!i2","dcmhubflp!i8"],
"grant-as-authority-to-apps": ["dcmhubflp","dcmhubflp!i2","dcmhubflp!i8"]
}, {
In the fiori Launchpad xs-security.json
"foreign-scope-references":["$ACCEPT_GRANTED_SCOPES"],
"authorities":["$ACCEPT_GRANTED_AUTHORITIES"]
Anand Muthu
I have updated my code to include the tile visibility changes.
With tile visibility controlled by scopes (This will require you to setup a role collection and assign it to your user):
https://github.com/bigsmity/xsalaunchpaddemo
Tile always visible:
https://github.com/bigsmity/xsalaunchpaddemo/tree/without-tiles-controlled-by-uaa-scope
Hi Bradley,
This is great stuff!
Your example works perfectly. But I have problems adapting this to our existing development. Would you have any ideas, why would an additional/second MTA would replace portal service content with its site-content.json entirely instead of merging it with the existing site content in the portal service? I seem to be following the example to the letter.
Sigitas
Hi Sigitas,
I am glad my blog has helped! I have seen this issue before, and the cause in my case was quite strange.
Do you have more than one i18n.properties file in your ui5 app? When I removed all my language variants i18n_en and i18n_en_US etc leaving only the base i18n.properies file the launchpad returned to normal.
let me know if that works.
Thanks,
Brad.
Hey, Bradley,
Your suggestion to look into i18n.properies was spot on!
Though I did not go to the very bottom of this. But it seems the request header Accept-Language acts as a sort of selection/filtering criterion as to which site content will be served (well.. kinda obvious once you know it 🙂 ). Accept-Language: * will show the complete merged set with texts from i18n.properies file. But whenever some specific language is requested and the language is missing or especially if it is just partially present then this will definitely produce some unexpected results.
Specifying several languages along with their priorities in Accept-Language does not seem to have an effect. It is only the first language that is used.
So I guess the safe bet is to either have just the i18n.properties or makes sure to include the same set of languages in i18n_*.properties files in every component involved.
Thanks!
Sigitas
Hi Bradley,
If i Follow the above steps, will the Fiori Launchpad also come, or we have to follow the steps in your other blog to get the FLP running. ?
Thanks,
Mudit
Hi Mudit,
These steps will allow you to add your ui5 application to any existing FLP.
If you do not have a launchpad already, a new FLP created straight from the template in webide will work for you.
Thanks,
Bradley.
Hi Bradley,
Thank you for the useful blog.
I exactly cloned your project from GIT and just deployed to XSA without any change. I also created role collection and assigned to my user. However the second app tile is not displaying. It just shows the group.
Can you please guide me.
Hi Manikandan,
It looks like there is a problem with your role collection as we can see the group but no tile. I have a branch containing the code without this restriction to get you started.
https://github.com/bigsmity/xsalaunchpaddemo/tree/without-tiles-controlled-by-uaa-scope
Thanks,
Brad.
Hi Bradley, Very informative blog, we are working on a similar requirement and tried this example as is but we are getting the following error. Any pointer will help.
App could not be opened because the SAP UI5 component of the application could not be loaded.
Hi Anil,
Unfortunately, your screenshot is not giving me much information to go on. Could you get the detailed error message from the console?
What version of Hana are you running? The provided code was last tested on SAP HANA 2.0 SPS 04 on premise and express.
Thanks,
Brad.
Hi Brad, Thanks for the quick response, here is the console error. Also we are on HANA 2.0 SPS04 Patch 8
Site-content.json
{
"roles": {
"Everyone": {
"_version": "1.0",
"identification": {
"id": "Everyone",
"namespace": "",
"entityType": "role"
},
"payload": {
"catalogs": [],
"groups": [{
"id": "flpuitest_ui_GroupId"
}]
}
}
},
"applications": {
"flpuitest_ui": {
"sap.app": {
"_version": "1.3.0",
"id": "flpuitest_ui",
"title": "Launchpad Demo App2",
"i18n": "i18n/i18n.properties",
"tags": {
"keywords": []
},
"crossNavigation": {
"inbounds": {
"flpuitest_uiShow": {
"semanticObject": "flpuitest_ui",
"action": "show",
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"signature": {
"parameters": {},
"additionalParameters": "allowed"
}
}
},
"outbounds": {}
}
},
"sap.ui": {
"_version": "1.3.0",
"technology": "UI5"
},
"sap.ui5": {
"componentName": "flpuitest_ui",
"_version": "1.2.0"
},
"sap.platform.cf": {
},
"sap.platform.runtime": {
"componentProperties": {
"url": "/"
}
}
}
},
"groups": {
"flpuitest_ui_GroupId": {
"identification": {
"id": "flpuitest_ui_GroupId",
"i18n": "i18n/i18n.properties",
"namespace": "",
"title": "Launchpad Demo App"
},
"payload": {
"tiles": [{
"id": "flpuitest_ui_tile",
"title": "Launchpad Demo App2",
"subTitle": "launchpad demo app2",
"icon": "sap-icon://share-2",
"appId": "flpuitest_ui",
"target": {
"semanticObject": "flpuitest_ui",
"action": "show",
"parameters": []
}
}]
}
}
}
}
Manifest.json
{
"roles": {
"Everyone": {
"_version": "1.0",
"identification": {
"id": "Everyone",
"namespace": "",
"entityType": "role"
},
"payload": {
"catalogs": [],
"groups": [{
"id": "flpuitest_ui_GroupId"
}]
}
}
},
"applications": {
"flpuitest_ui": {
"sap.app": {
"_version": "1.3.0",
"id": "flpuitest_ui",
"title": "Launchpad Demo App2",
"i18n": "i18n/i18n.properties",
"tags": {
"keywords": []
},
"crossNavigation": {
"inbounds": {
"flpuitest_uiShow": {
"semanticObject": "flpuitest_ui",
"action": "show",
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"signature": {
"parameters": {},
"additionalParameters": "allowed"
}
}
},
"outbounds": {}
}
},
"sap.ui": {
"_version": "1.3.0",
"technology": "UI5"
},
"sap.ui5": {
"componentName": "flpuitest_ui",
"_version": "1.2.0"
},
"sap.platform.cf": {
},
"sap.platform.runtime": {
"componentProperties": {
"url": "/"
}
}
}
},
"groups": {
"flpuitest_ui_GroupId": {
"identification": {
"id": "flpuitest_ui_GroupId",
"i18n": "i18n/i18n.properties",
"namespace": "",
"title": "Launchpad Demo App"
},
"payload": {
"tiles": [{
"id": "flpuitest_ui_tile",
"title": "Launchpad Demo App2",
"subTitle": "launchpad demo app2",
"icon": "sap-icon://share-2",
"appId": "flpuitest_ui",
"target": {
"semanticObject": "flpuitest_ui",
"action": "show",
"parameters": []
}
}]
}
}
}
}
Hi Anil,
Looking at your error, it's a 404 to your component.js. You aren't using my codebase so I cannot be sure where the problem is. This configuration is extremely sensitive, and there could be many sources of error. You will need to recheck everything.
I would recommend loading up a copy of my source first, running it and seeing how it all fits together. After that, add your application to the launchpad comparing your files to mine. You may even like to use a tool like kdiff on each of our files to find any clear differences?
This is the branch with the simplest example: https://github.com/bigsmity/xsalaunchpaddemo/tree/without-tiles-controlled-by-uaa-scope
This is by far the most difficult Fiori launchpad to configure that I have seen to date. We can only hope that SAP address this and implement something similar to the cloud based flp for XSA.
Best of luck,
Brad.
Thanks Brad . I will check with your source
Hi Brad, Thanks for your prompt replies Just FYI , I cloned your source code but no luck with launchpaddemoapp2. Though launchpaddemoapp worked as expected. I suspect something to do with versions but not sure exactly.
Hi Anil,
Did you have any solution for this ? We are encountering this issue now when we upgrade XSA to SP05 revision 57.
Thanks.
Anand Muthu
Hi Bradley,
Do you have any success using two different UI5 applications on the same group on the site-content.json ? I am having trouble deploying two different tiles on the same site-content.json
Thanks,
Anand Muthu
Hi Bradley,
I'm trying to use this guide but on XSA SPS06 the launchpaddemoapp2 return following error message:
App could not be opened because the SAP UI5 component of the application could not be loaded.
Did you have any solution?
Thanks,
Armando