Skip to Content
Technical Articles
Author's profile photo Soeren Holst

Developing a Shell Plugin for SAP Fiori Launchpad Service on SAP BTP (Multi-Cloud Environment) with SAP Business Application Studio

Developers can extend the functionality of SAP Fiori Launchpad using Shell Plugins. The concept of plugins allows SAP Fiori implementers to hook into the Launchpad Shell and add new elements like menu items, custom footers, header extensions and many more.

In this blog post I will show you how to extend your SAP Fiori Launchpad on SAP BTP (Multi-Cloud Environment) via a HTML5 Application/Shell Plugin managed by SAP BTP (Multi-Cloud Environment).

In this example we will add a button to the SAP Fiori Launchpad header, which opens a pop-up with some basic information.

Following steps are necessary to deploy your shell plugin successfully to SAP BTP (Multi-Cloud Environment).

You can find the Source Code in this GIT Repository.

1. Open the SAP Business Application Studio

Open the SAP Business Application Studio in your SAP BTP (Multi-Cloud Environment) Subaccount.

Create a new Dev Space and select “SAP Fiori” for application type and click on the created item header afterwards.

2. Create the Shell Plugin Project

Select “Create project from template”. Choose “SAP Fiori Freestyle – Project Generator” and confirm with “Next”.

Select “Cloud Foundry” as target running environment and choose “SAPUI5 Application”.

Enter a Project Name and continue with “Next”.

Select “Managed by SAP Cloud Platform” as HTML5 application and enter a service name.

Enter some basic attributes.

Enter a view name.

Create the project and select “Open in New Workspace” afterwards.

3. Modify the created project to use it as a Shell Plugin

Please develop your own custom Shell Plugin code in the component.js file.

For my example you can modify the “init” Method as well as the Method “_getRenderer”.

Please also adjust the “manifest.json” as follows:

4. Build and deploy your Multi Target Application

Right click on “mta.yaml” and select “Build MAT”.

The folder “mta_archives” is created automatically. Please select the .mtar file and select “Deploy MTA Archive”.

Enter the Cloud Foundry endpoint, followed by username and password. Afterwards please select the organization and your space.

5. Check if deployment process was successful

Please go back to the SAP BTP (Multi-Cloud Environment) Cockpit and check if the following was created:

5.1 Service instances in your selected space

5.2 Destination

6. Assign your Shell Plugin to a SAP Fiori Launchpad

Open your Site-Manager and navigate to the Provider-Manager. Please refresh the “HTML5 Apps” content provider.

Afterwards you can see your Shell Plugin in the “Content-Explorer” and you can add it to your content.

Assign your Shell Plugin to the “Everyone” Role.

Please create a new Website (or choose an existing one).

Open the URL. You will see an additional button in the Shell Header.

I hope this blog post provides the necessary information to develop and deploy your Shell Plugins successful to SAP BTP (Multi-Cloud Environment). Please leave a comment if you have further questions.

If you prefer using Web IDE please check this blog post.

Assigned tags

      30 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Murali Shanmugham
      Murali Shanmugham

      Hi Soren,

      Thank you for posting this. I've been waiting for this feature.

      Author's profile photo Sagar Mantri
      Sagar Mantri

      Hi Soeren,

      We have followed same steps but couldn't find plugin in content provider.

      I have doubt about step 5, destinations in screenshots needs to be created manually or it will be created automatically ?

       

      Regards,

      Sagar

      Author's profile photo Soeren Holst
      Soeren Holst
      Blog Post Author

      Hi Sagar,

      the destination is created automatically. Did you refresh the HTML5 Content-Provider (Screenshot 2 - Step 6)

      Best regards,

      Soeren

      Author's profile photo Sagar Mantri
      Sagar Mantri

      Dear Soeren

      yes, I have refreshed HTML5 Content-provider.

      Only difference is we are using portal service not Launchapad does that make difference ?

       

      Regards,

      Sagar

      Author's profile photo Sagar Mantri
      Sagar Mantri

      Hi Soeren,

      Thank you for your help, our issue is resolved after adding "sap.cloud" in manifest.json.

      Best Regards,

      Sagar

      Author's profile photo Jorge Sousa Villafaina
      Jorge Sousa Villafaina

      I was looking for this! Thanks for sharing!

      Author's profile photo Revathi Raju
      Revathi Raju

      Hi Soeren, Thank you for the information, I am able to follow your blog and implemented successfully. 🙂 Is it possible to explain how do we call a on-prem destination created in the subaccount from this project?

      Thanks,

      Revathi Raju.

      Author's profile photo Soeren Holst
      Soeren Holst
      Blog Post Author

      Hi Revathi,

      does this help?

      https://blogs.sap.com/2020/07/15/developing-sap-ui5-app-using-sap-business-application-studio/ ?

      Regards,

      Soeren

      Author's profile photo Krishna Kammaje
      Krishna Kammaje

      This feature was overdue but happy that we got it. Thank you.

      Author's profile photo Krishna Kammaje
      Krishna Kammaje

      Could not get the destinations created even after refreshing the HTML5 content-provider. I am using VSCode instead of BAS.

      The deployment went fine (I am even able to access the component.js of the plugin using the approuter URL). What else might have gone wrong?

      I am using the Fiori Launchpad inside the 'Portal' service, (not the Fiori Launchpad service). So this does not work on Fiori Launchpad inside the 'Portal' service?

      Any idea is welcome, please.

      Author's profile photo Krishna Kishor Kammaje
      Krishna Kishor Kammaje

      Found the issue. When you develop via BAS, it automatically created the required configuration within the mta.yaml to create SCP destinations to consume the plugin as a content provider.

      But if you develop locally, you need to manually create a module within mta.yaml that has all the destinations you require (I copied them from BAS). This module has "no-source: true" parameter so that MBT will not complain while building. I had to upgrade my MBT for this to happen. (Otherwise it always errored out).

      Author's profile photo Deniz Cengiz
      Deniz Cengiz

      Hi Krishna Kishor Kammaje ,

      we are trying to run the plugin as part of the fiori portal service, too, and are experiencing some issues with it. We have tried wrapping the plugin in a module like described by you and quite similar to the example service found here: https://github.com/SAP-samples/launchpad-service-samples/blob/main/MyShellPluginProject/mta.yaml

      Could you maybe provide some tips or sample code as to how you set up your mta.yaml so that you got the shell plugin to work with the launchpad as part of the portal service?

      Kind regards
      Deniz

      Author's profile photo Sriram V
      Sriram V

      Thanks Soeren for the great blog. I have added the subheader to the shell header want to display the username and the role name of the user. Any idea on how to retrieve the logged in user from plugin? Thanks.

      Author's profile photo Soeren Holst
      Soeren Holst
      Blog Post Author

      Hi Sriram,

      does this help?

      https://sapui5.netweaver.ondemand.com/sdk/#/api/sap.ushell.services.UserInfo

      Best regards,

      Soeren

      Author's profile photo Antonette Venter
      Antonette Venter

      Hi Soeren,

      Thanks for the great blog.

      Select “Managed by SAP Cloud Platform” as HTML5 application and enter a service name.

      There are many cases where we would need a custom app router in the plugin project, like for example activating the Notification Centre, however I can't seem to get the plugin to work if I choose to have a custom app router.

      Have you been able to achieve this?

      Regards

      Antonette

      Author's profile photo Ingmar Lemke
      Ingmar Lemke

      Same problem here. I am struggling to understand of how to integrate a Shell plugin when not using a managed HTML5 repo/managed app router. The manual part just allows to create an App in the Content Manager but no specific Shell-plugin. Integrating a content provider with the html5-rt and html5-dt services is also not working. Any idea of how to achieve this?

      Author's profile photo Navya Krishna
      Navya Krishna

      Hello Soeren,

      I followed all the steps and deploy was also successful, but it is not working and i get the below error in the browser console.

      Thanks and Regards,

      Navya

      Author's profile photo Michael Jess
      Michael Jess

      Hey Navya,

       

      Please check your manifest.json. It appears that lately, the "sap.cloud.service" property isn't rendered by the template for some reason. The issue went away when I added the value. Note that I believe it needs to be the same value as in the destination.

       

      Cheers,

      Michael

      Author's profile photo Gregor Wolf
      Gregor Wolf

      Hi Soeren,

      thank you for this post. Would it be possible that you provide your sample project in a public Git repository? That would help to avoid all the tedious manual steps.

      Best regards
      Gregor

      Author's profile photo Soeren Holst
      Soeren Holst
      Blog Post Author

      Hi Gregor,

      we are working on it. I will inform you here.

      Best regards,

      Soeren

      Author's profile photo Soeren Holst
      Soeren Holst
      Blog Post Author

      Hi Gregor,

      you can find the source code in this GIT Repository:

      https://github.com/SAP-samples/launchpad-service-samples

      Best regards,

      Soeren

      Author's profile photo Gregor Wolf
      Gregor Wolf

      Hi Soeren,

      it seems that the "SAP Fiori Freestyle – Project Generator" was changed and creates the parameters for the destination-content module as 'instance'. But for the Launchpad it should be 'subaccount'. Thanks to Holger Schäfer  for this tip on Twitter.

      Best regards
      Gregor

      Author's profile photo Deniz Cengiz
      Deniz Cengiz

      Hi Gregor Wolf

      do you happen to have also tried running the shell plugin within a launchpad via the portal service? Any parameter that need changing from the sample code provided to get that working?

      Best regards
      Deniz

       

      Author's profile photo Taranamjit Kaur Dhindsa
      Taranamjit Kaur Dhindsa

      hi Soeren

      Thanks for explaining in detail . But now in BAS Trial account SAP Fiori freestyle template now shows deprecated listed here . So now what is the alternative for it as seems this option will be removed as its showing deprecated   ?

       

      Regards

      Taranam

      Author's profile photo Soeren Holst
      Soeren Holst
      Blog Post Author

      Hi Taranam,

      please use "SAP Fiori application" and select "SAPUI5 freestyle" as Application Type in the next step.

      Best regards,

      Soeren

      Author's profile photo Taranamjit Kaur Dhindsa
      Taranamjit Kaur Dhindsa

      Thanks Soeren for your help .

      Author's profile photo Holger Schäfer
      Holger Schäfer

      Hi Soeren,

      thanks for the BTP update!

      How do you test it locally?

      I think BAS misses the localSandbox preview scenario like in NEO.

      Since the index.html is not used, i changed it to the follwoing code, the be able to use start script to preview my coding inside SandBox FLP before deploying it to CF.

      <!DOCTYPE html>
      <html>
      
      <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>MyShellPluginModule</title>
      
          <script>
              window['sap-ushell-config'] = {
                  defaultRenderer: 'fiori2',
                  bootstrapPlugins: {
                      "ShellPlugin": {
                          "component": "ns.MyShellPluginModule",
                          "url": "./"
                      }
                  },
                  applications: {
                      "App1-display": {
                          title: "Wikipedia",
                          description: "Embedded",
                          applicationType: "URL",
                          url: "https://de.wikipedia.org/wiki/Wikipedia:Hauptseite",
                          navigationMode: "embedded"
                      },
                      "App2-open": {
                          title: "Heise Ext",
                          description: "New Window",
                          applicationType: "URL",
                          url: "https://www.heise.de"
                      }
                  }
              };
          </script>
      
          <script src="https://sapui5.hana.ondemand.com/1.88.1/test-resources/sap/ushell/bootstrap/sandbox.js"></script>
          <script src="https://sapui5.hana.ondemand.com/1.88.1/resources/sap-ui-core.js" data-sap-ui-libs="sap.m, sap.ushell"
              data-sap-ui-theme="sap_fiori_3" data-sap-ui-compatVersion="edge" data-sap-ui-frameOptions="allow"
              data-sap-ui-bindingSyntax="complex"></script>
          <script>
              sap.ui.getCore().attachInit(function () {
                  sap.ushell.Container.createRenderer().placeAt('content');
              });
          </script>
      
      </head>
      
      <body class="sapUiBody" id="content"></body>
      
      </html>

      Using bootstrapPlugins section inside sandbox config auto loads the plugin into the sandbox flp.

      Even the services can be used/tested while local previewing it.

      Maybe there is a better way of local test/previewing shell plugin, but this one fits my needs.

       

      Best Regards
      Holger

       

      Maybe these snippets are also quite useful for others...

      User Info

      that._oShellContainer = jQuery.sap.getObject("sap.ushell.Container");
      
      // UserInfo service
      that._oShellContainer.getServiceAsync("UserInfo").then(function (oUserInfo) {
        console.log("oUserInfo", oUserInfo, oUserInfo.getUser(), oUserInfo.getUser().getId());
        that._oUser = oUserInfo;
      });

      Intercept Portal Navigation

      registerPortalSiteNavigationEvents: function () {
                  // Track app and page navigation events
                  var oAppLifeCycle = sap.ushell.Container.getService("AppLifeCycle");
      
                  oAppLifeCycle.attachAppLoaded(function (oEvent) {
                      var oParameters = oEvent.getParameters();
                      oParameters.getIntent().then(function (event) {
                          var sSemanticObject = event.semanticObject;
      
                          console.log("AppLifeCycle", event, sSemanticObject);
                      });
                  }.bind(this));
      }

      Sticky Sidebar

      renderStickySidebar: function () {
                  if (!document.getElementById(sId)) {
                      var sId = "sticky-sidebar";
                      var domContainer = document.createElement("div");
                      domContainer.setAttribute("id", sId);
                      domContainer.setAttribute("style", "display: none; position: fixed; top: 3.5rem; right: 1rem; bottom: 1rem; width: 320px; border: 1px solid rgba(0, 0, 0, 0.3); box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); border-radius: 0.25rem;");
                      document.body.appendChild(domContainer);
      
                      var domView = document.createElement("iframe");
                      domView.setAttribute("id", sId + "-iframe");
                      domView.setAttribute("src", "https://de.wikipedia.org/wiki/Wikipedia:Hauptseite");
                      domView.setAttribute("style", "width: 100%; height: 100%; border: 0; border-radius: 0.25rem;");
      
                      domContainer.appendChild(domView);
      
                      this._domStickySidebar = domContainer;
                  }
      },
      
      onToggleSidebar: function () {
                  if (!this._domStickySidebar) {
                      this.renderStickySidebar();
                  }
      
                  if (this._domStickySidebar.style.display === "none") {
                      this._domStickySidebar.style.display = "block";
                  } else {
                      this._domStickySidebar.style.display = "none";
                  }
      },
      
      // inside init
      rendererPromise.then(function (oRenderer) {
                      oRenderer.addHeaderEndItem({
                          icon: "sap-icon://documents",
                          tooltip: "Open Files",
                          press: function () {
                              that.onToggleSidebar();
                          }
                      }, true, false);
      });
      Author's profile photo Soeren Holst
      Soeren Holst
      Blog Post Author

      Thank you Holger!

      Author's profile photo Ankur Babu
      Ankur Babu

      Hi Holger Schäfer ,

      Nice examples to test the app locally. As with the code,

      applications: {
                      "App1-display": {
                          title: "Wikipedia",
                          description: "Embedded",
                          applicationType: "URL",
                          url: "https://de.wikipedia.org/wiki/Wikipedia:Hauptseite",
                          navigationMode: "embedded"
                      },

      the website (wikipedia) is loading inside Fiori launchpad page using this approach for local Sandbox file. Do you know if it is possible to do this on On-Premise Fiori launchpad. How can I configure a tile/target mapping for an external URL to load the website inside Fiori launchpad?

      Best regards,

      Ankur

      Author's profile photo abhishek tiwari
      abhishek tiwari

      Hello Soeren Holst,

      I had a requirement where I am fetching a JSON file and displaying it in my FLP using the shell plugin. I tried using the destination( cannot use URL directly to fetch the JSON as cross-site origin error) but the shell plugin was not able to get the destination configured in neo-app.json. Is there a way to fetch my JSON file via a URL, containing a message to be displayed in a popup, via a shell plugin?