Skip to Content
Technical Articles

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.

28 Comments
You must be Logged on to comment or reply to a post.
  • 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

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

    • Hi Revathi,

      does this help?

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

      Regards,

      Soeren

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

    • 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).

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

  • 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

    • 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?

  • 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

    • 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

  • 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

    • 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

       

  • 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

  • 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);
    });