Technical Articles
Custom Tiles with Cloud Foundry Portal – Cloud Platform
I like to write some notes down, from my findings how to implement custom tiles with in Portal service on Cloud Foundry (SCP / Cloud Platform). Unfortunately, the current documentation is limited and doesn’t show a good end-to-end sample. I only could get it running with a lot of trial and error.
Updates
03/27/2020 – added end-to-end sample with one Portal, two custom tiles, one basic UI5 app as target and CAP based service as backend for the charts: https://github.com/citoki/portal-custom-tile
This is the result. You’ll get a tile, where you can put in your controls of choice. In my sample below, I use two ComparisonMicroChart controls in the left tile and in the right one two HarveyBallMicroChart controls. For the first tile I used a JS-View and for the second a XML-View, just for demonstration. You can choose what fits better to your coding style.
Contents
- Create a Starter Project
- Create a Tile App
- Tile Content
- Reading Data Continuously
- Parameterise Custom Tile via FLP Config
- Code – End-To-End Sample
Create a Starter Project
As a starting point for a new FLP project I like to generate the necessary artefacts by the WebIDE. You can follow the steps described by Iris Sasson in her detailed blog: SAP Fiori launchpad site with portal service on SAP Cloud Platform
One thing which is crucial to get a minimal project running on CF (Cloud Foundry), is that the custom tile points to an existing UI5 app. That is the target app which will be defined in business app file baCustomTile.json
later in this blog.
In my case, I called the target app like this: tutorial.app.one.app1
Create a Tile App
Now let’s jump into the code!
For the new custom tile we need a separate UI5 app. There are a lot of ways to scaffold an UI5 app. One thing I can recommend is the Yo-plugin by Marius Obert. He started developing the Yo plugin Generator-Easy-UI5. With that plugin you’ll be fast on the track.
The only thing you need to add in the UI5 app, is the FLP configuration This tells the Portal service that the app should be handled as a Tile with a specific tileSize
of 1×1.
"sap.flp": {
"type": "tile",
"tileSize": "1x1"
},
tileSize
currently only supports 1x1
(square tile) and 1x2
(wide rectangle tile).
Fiori Launchpad Configuration
Below you can see the structure we need in the end.
flp/portal-site/CommonDataModel.json
flp/portal-site/business-apps
└── baCustomTile.json
flp/portal-site/i18n
└── i18n.properties
The configuration for the Launchpad (FLP) is done via the flp/portal-site/CommonDataModel.json
file. In config path “payload.catalogs.payload.viz“ add following object to the viz
array:
File: CommonDataModel.json
viz: [{
"id": "tutorial.app.one.app1", // has to be equal to 'appId' wihtin groups
"vizId": "customTile-displayToCustom" // visualization from business app configuration
}]
This tells the FLP runtime, that there is a special visualisation for app1
available.
In the same file (CommonDataModel.json
), we need to set the specific visualisation for the tile. That is done in the object path “payload.groups.payload“. Just add the following code there:
File: CommonDataModel.json
"viz": [{
"id": "tutorial.app.one.app1-0-1573035031268",
"appId": "tutorial.app.one.app1",
"vizId": "customTile-displayToCustom" // visualisation ID from business app configuration
}]
The configuration and the target mapping, when clicking on the custom tile has to be made in a specific folder flp/portal-site/business-apps
. Just create a JSON file (in my example: baCustomTile.json
) with following code:
File: baCustomTile.json
{
"_version": "3.0.0",
"identification": {
"id": "tutorial.app.one.app1", // app which should be opened by the custom tile
"entityType": "businessapp",
"i18n": "i18n/i18n.properties"
},
"payload": {
"visualizations": { // multiple visualisations are possible to be defined here
"customTile-displayToCustom": { // one sample of visualization for our 'app1'
"vizType": "project.namespace.customTile", // type has to be set to the app name of our customTile
"vizConfig": {
"sap.app": {
"title": "{{notifList.tile.title}}",
"subTitle": "{{notifList.tile.subtitle}}"
},
"sap.flp": {
"target": {
"inboundId": "data-display" // inbound config for the target app 'app1'
}
}
}
}
}
}
}
And that’s it. Just deploy the FLP like normal and the custom tile should appear right there.
Tile Content ?
Please read the Fiori guidelines on tiles, for further details on when to use tiles and which content should be shown.
Do not play videos in their and do not provide any interactive controls like buttons, polls, list. ?
In some use cases the OVP (Overview Page) could be the better choice.
Reading data continuously
Now, for tiles are quickly coming up questions like “How can read the data continuously every X seconds?” Well, you might have seen the dynamic tile. For that you can configure an interval to update the data in the tile. Unfortunately, there is no API to tell the Portal that your custom tile wants to hook into the events like “dashboardTileClick”, “setTilesNoVisibility”, “onHiddenTab”. These events are managed only for DynamicTiles by DashboardLoadingManager.js.
Well, as a workaround you could handle some window/documents events by your own, like “window.blur”, “window.focus” and “document.hidden”.
But, that’s not enough. When you have an update loop running (e.g. via setInterval()
to refresh data in your custom tile, it would run the whole time. It also runs when the user has click, on a different tile, endless.
Parameterise Custom Tile via FLP Config – now it’s getting dirty!!
DON’T TRY THIS AT HOME or in PRODUCTION!! ?
Imagine you want to dynamically load data in you custom tile, e.g. a specific type of notifications, within the custom tile. And you don’t want to create another tile app and parameterise the OData/REST call.
Then you could add just another visualisation to the business app configuration, into the visualizations
object:
"customTile2-display": {
"vizType": "project.namespace.customTile2",
"vizConfig": {
"sap.app": {
"title": "{{customTile2.title}}",
"subTitle": "{{customTile2.subtitle}}"
},
"sap.flp": {
"target": {
"inboundId": "data-display",
"parameters": {
"param1" : {
"value": {
"value": "new param value1",
"format": "plain"
}
}
}
}
}
}
The parameters
property is read via a readVisualizations function readVisualizations.getOutbound().
During debugging the custom tile, the _oProperties
object now has created the target URL with the configured param1
parameter:
targetURL: “#data-display?param1=new%20param%20value1&sap-ui-app-id-hint=tutorial.app.one.app1“
Debug code line: https://github.com/citoki/portal-custom-tile/blob/0d91424d1f373307d49d605d66ed33f69fe7db86/app-custom-tile/webapp/DynamicTile.controller.js#L10
Technically this is the hash/link which should be called after clicking on the custom tile.
You could now parse this string and extract the param1
parameter and use this during the initialisation for the custom tile.
Code – End-To-End Sample
See code sample for an End-To-End sample project: https://github.com/citoki/portal-custom-tile
Many thanks! It is something I was trying days ago, good contribution!
Hi Bradguver Jesus Villavicencio Rojas,
Are you able to create the custom tile? I am getting deployement fail.Please check my code in below comment.
Regards
Charan
Hello CHARANRAJ THARIGONDA, What I could recommend and what in my case solved my problem is that for example in your business-apps.json you put as id not businesscustomapp but something like businesscustomapp.app (keep in mind that you must update the rest and change businesscustomapp by businesscustomapp.app) and after this change create an HTML5 Module where the name of your application would be app and its namespace would be businesscustomapp, after making all these changes make your build and deploy.
Regards.
Hi Steffen,
Nice blog. I have tried to replicate the same.However, I got below error. Could you please tell me what could be the reason
Please check my sample file. Maybe the catalogs definition isn't correct.
https://github.com/citoki/portal-custom-tile/blob/master/flp/portal-site/CommonDataModel.json#L17-L20
Hi Steffen,
I have tried same way but my deployement is failling.
manifest.json
business-apps
CMD file.json
undefined Error : "Failed to search all appHostIds, missing apps: businesscustomapp""
I think there isn't an UI5 app 'businesscustomapp' deployed in your space/HTML5 repository. The app appui5.appui5 is only the UI5 app for the visualisation of the custom tile. The target app is also needed.
Hello CHARANRAJ THARIGONDA, What I could recommend and what in my case solved my problem is that for example in your business-apps.json you put as id not businesscustomapp but something like businesscustomapp.app (keep in mind that you must update the rest and change businesscustomapp by businesscustomapp.app) and after this change create an HTML5 Module where the name of your application would be app and its namespace would be businesscustomapp, after making all these changes make your build and deploy.
Regards.
Hi Steffen,
It is very useful to me, I have done it like your code, but once I deploy BTP, there are always errors, I don't know what happened, do you have the same situation?
Best regards,
Lucia
Hi Lucia Wu , were you able to resolve this error?
Hello Steffen,
The blog is very useful, i tried implementing the custom tile to our application, but while deploying its throwing an error
"Error: Failed to import site, tenantId: 745e90f7-790b-4daf-aad6-c1a2a050d34d, instanceId: 52bb9099-d9a6-4a08-8be2-e4ccb29a0a56, appHostIds: {"appHostIds":["4e4e21d4-0869-4573-8eba-c0b932b0f1f8"],"boundAppHostIds":[],"instanceId":"52bb9099-d9a6-4a08-8be2-e4ccb29a0a56"}, xsAppNameServicesMap: {"html5-apps-repo-dt":"4e4e21d4-0869-4573-8eba-c0b932b0f1f8!b10875|html5-apps-repo-uaa!b1129","com.sap.portal.no.business.service":"irouting-sandbox-bd-internal!b10875"}, blueBoxMetadataStr: undefined Error : "The following IntentHintId defined in CommonDataModel.json do not exists - verify the existence of the following Intents: Set(1) { 'cs.customtile#customtile-manage' }"', error type 'TsInternalServerErrorException'
Process failed."
and not allowing to deploy.
Can you kindly help me in resolving the issue ?
Thanks and Reagrds,
Alam
Hi Alam,
I am also facing the same issue, can you help me how you resolved this issue,
thanks and regards
Zameer Ahamad
Hi Steffen,
thank you for this post. I would suggest you make clear that this is talking about the Launchpad Module that can be used in MTA's and for multi tenant apps. It's not about the Launchpad Service.
Best Regards
Gregor
Hi Steffen,
How to Implement Refresh Interval feature in custom tile, as shown in bellow snapshot?
Hi Shivaraj,
Can you explain more about how you did it?
Thanks in Advance!!!
Hi, how do i test this in local?