Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
Mr-Musa
Explorer
17,249
Currently SAP didn’t provide any tools to track the usage of the application (Tiles) in the launchpad. I came across several option & suggestions but none of them were really giving the real usages.

Example:
SE38–>Enter Report name /IWFND/R_METERING_VIEW

This report will show the usage of the OData service. Fiori apps will consume the service several times during execution and you can’t relate from which app this call is coming from.


 


So I decided to try utilize the following to achieve my goal:



  • Use Web APIs Windows hashchange event which will help us to monitor the target mapping changes.

  • Use FLP API sap.ushell.services.LaunchPage (ondemand.com) to get  user’s tiles & groups & catalogs.

  • Fiori launchpad plugin to run my tracking script.

  • Custom Odata service to post user tracking logs

  • Table to store the logs

  • Use of standard table SUI_TM_MM_APP to get some extra information of the used app that is not available in the sap.ushell.services.LaunchPage services.


 

 

This way it will log every app had been used even HTML GUI , Webdynpro , Custom SAPUI5 apps maintained as target mapping.

It will exclude the navigation that change the hash within the the same app, so we will not over record the usage of an app.

 

 

 

 

 

Let’s start now :



1- WEBIDE Create a plugin, please refer to the following for detailed steps Creating SAP Fiori Launchpad Plugins in SAP Web IDE - SAP Help Portal



  • Add below code to the plugin allowing with predefined code.
    		init: function () {
    var oComponent = this;
    var rendererPromise = this._getRenderer();

    //Trakcing the usage is working upon 'hashchange' event triggers
    window.addEventListener("hashchange", oComponent._onHashChange.bind(this), true);

    //Waiting for the FLP shell container to be ready to start plugin methods
    rendererPromise.then(function (oRenderer) {
    oComponent._onFioriTracker();
    oComponent._initTrackerOdataService();
    });

    },

    _initTrackerOdataService: function() {
    //initialization of Tracking service (OData) --> ZFLPTRACKING
    var sServiceUrl = '/sap/opu/odata/sap/ZFLPTRACKING_SRV/';
    var oModel = new sap.ui.model.odata.v2.ODataModel(sServiceUrl, true);
    oModel.setUseBatch(false);
    this.setModel(oModel);
    },

    _onFioriTracker: function(oEvent) {
    // Bullding the array of the tiles once the FLP is loaded
    // The belwo array will be used to be refreced to get the tiles details upon clicking of a tile
    this.UserTiles = [];

    //Custom Tiles had to be treated diffrently to get its informaiton
    //it's pushed inside the below array to be treated thend again pushed back to this.UserTiles array
    this.MenuTileArray = [];



    //Here we will get the tiles from groups & catalogs then start collecting required
    //information (title , catalog id , group id , target mapping .. etc)
    sap.ushell.Container.getService("LaunchPage").getGroups().then(function(aGroups) {
    sap.ushell.Container.getService("LaunchPage").getCatalogs().done(function (oCatalogs) {
    for (var i = 0; i < aGroups.length; i++) {
    var aGrpTiles = sap.ushell.Container.getService("LaunchPage").getGroupTiles(aGroups[i]);

    for (var j = 0; j < aGrpTiles.length; j++) {
    var sTileTitle = sap.ushell.Container.getService("LaunchPage").getTileTitle(aGrpTiles[j]);
    if(sTileTitle === "App Launcher – Static")
    {
    if( sap.ushell.Container.getService("LaunchPage").getCatalogTilePreviewSubtitle(aGrpTiles[j]) ){
    sTileTitle = sap.ushell.Container.getService("LaunchPage").getCatalogTilePreviewTitle(aGrpTiles[j])
    + " ( "
    + sap.ushell.Container.getService("LaunchPage").getCatalogTilePreviewSubtitle(aGrpTiles[j])
    + " )";
    }else{
    sTileTitle = sap.ushell.Container.getService("LaunchPage").getCatalogTilePreviewTitle(aGrpTiles[j]);
    }

    }
    var sTileTarget = sap.ushell.Container.getService("LaunchPage").getCatalogTileTargetURL(aGrpTiles[j]);
    this.sTileCatalogeId = sap.ushell.Container.getService("LaunchPage").getCatalogTileId(aGrpTiles[j]);



    var aCatalogTile = oCatalogs.filter(function (c) {
    return this.sTileCatalogeId.includes(c.id);
    }.bind(this));

    if(aCatalogTile.length > 0){
    var sTileCataloge = aCatalogTile[0].title;
    }else{
    var sTileCataloge = sap.ushell.Container.getService("LaunchPage").getCatalogTileTitle(aGrpTiles[j]);
    }



    if(sTileTitle === "Menu Custom Tile"){
    //Handle Menu Tile: push them in array to handle them later
    this.MenuTileArray.push(aGrpTiles[j]);

    }else{
    this.UserTiles.push({
    tileTitle : sTileTitle,
    catalogeId : this.sTileCatalogeId,
    cataloge : sTileCataloge,
    groupTitle : aGroups[i].getTitle(),
    groupId : aGroups[i].getId(),
    target : sTileTarget
    });

    }//-------------if(sTileTitle === "Custom Tile"){

    sTileTitle = "";
    sTileTarget = "";
    this.sTileCatalogeId = "";
    sTileCataloge = "";

    }//----------for (var j = 0; j < aGrpTiles.length; j++) {
    aGrpTiles = [];
    }//-------for (var i = 0; i < aGroups.length; i++) {


    //Handle Menu Tile
    for(var x=0; x <this.MenuTileArray; x++ ){
    sap.ushell.Container.getService("LaunchPage").getTileView(this.MenuTileArray[x]).then(function(oTileView) {
    var tileApi = oTileView.getViewData().chip;
    var tileConfigurationData = sap.ushell.components.tiles.utilsRT.getConfiguration(tileApi);

    if(tileConfigurationData){
    sTileTitle = tileConfigurationData.display_title_text;
    this.UserTiles.push({
    tileTitle : sTileTitle,
    catalogeId : this.sTileCatalogeId,
    cataloge : sTileCataloge,
    groupTitle : aGroups[i].getTitle(),
    groupId : aGroups[i].getId(),
    target : sTileTarget
    });
    } //---------if(tileConfigurationData){
    }.bind(this)); //--------sap.ushell.Container.getService("LaunchPage").getTileView(aGrpTiles[j]).then(function(oTileView) {
    }


    window.dispatchEvent(new HashChangeEvent("hashchange"));

    }.bind(this)); //--- sap.ushell.Container.getService("LaunchPage").getCatalogs().done(function (oCatalogs) {
    }.bind(this)); //-- sap.ushell.Container.getService("LaunchPage").getGroups().then(function(aGroups) {
    },

    _onHashChange: function(oEvent) {
    //This method will handle the target mappinng change 'HASH'
    var oComponent = this;
    var sOldHash = sap.ushell.utils.getBasicHash(this._getHashFromURL(oEvent.oldURL));
    var sNewHash = sap.ushell.utils.getBasicHash(this._getHashFromURL(oEvent.newURL));
    var tile = [];


    //handle open in new tab or by direct link
    if(sOldHash == "" && sNewHash == ""){
    sNewHash = sap.ushell.utils.getBasicHash(window.location.hash);
    }

    //handle the change of URL while navigation within the app or within same target mapping
    if (sOldHash !== sNewHash) {
    this.sHash = sNewHash;

    tile = this.UserTiles.filter(function(o) {
    if (o.target) {
    return sap.ushell.utils.getBasicHash(o.target).indexOf(sap.ushell.utils.getBasicHash(oComponent.sHash)) === 0;
    }
    });

    if(sNewHash === "Shell-home" && tile.length === 0 && true ){ // This to consider or not to consider the FLP home usage
    tile.tileTitle = "Fiori Launchpad Access";
    tile.cataloge = "";
    tile.catalogeId = "";
    tile.groupId = "";
    tile.groupTitle = "";
    tile.target = "#Shell-home";
    this._postTracking(tile);

    }else{
    this._postTracking(tile[0]);
    }

    }
    },

    _getHashFromURL: function(URL) {
    return URL.substring(URL.indexOf('#'));
    },


    _postTracking: function(tile) {
    //Posting the application usage recored to backend
    if(tile){
    var oData = {
    TrackNo : "", // <--- dummy,
    Tile : tile.tileTitle,
    Cataloge : tile.cataloge,
    Catalogeid : tile.catalogeId,
    Tgroupid : tile.groupId,
    Tgroup : tile.groupTitle,
    Target : tile.target
    };

    this.getModel().create("/TrackSet", oData, {
    success: function(oSuccess) {

    }.bind(this),
    error: function(oError) {

    }.bind(this)
    });
    }
    },​



As I mentioned we use the hashchange event to track the used app. and to get the app information at the initialization I’m building an array of all users tiles along with available information (Tile Title, cataloge,group, target(#SemanticObject-Action), …etc) and a method to handle the change hash then get the clicked tile form our array then prepare the data to be posted at the back end.

*Best thing is debuge the code to have full understanding for the solution and if you have any question please feel free.

 

 

  • Deploy the BSP application.


 

 

 

2- Create Shell plugin Target Mapping in the launchpad designer. Activating Plug-Ins on the ABAP Platform - SAP Help Portal


 

3- Assignee the catalog which contain the shell plugin to a role. And assign the role to people who you want to track.


 

 

4- Create Table to hole data (Below is suggested structure):


MANDT	MANDT	CLNT	3	0	0	Client
TRACK_NO GUID RAW 16 0 0 Globally Unique Identifier
FIORI_ID /UI2/AD_MM_FIORI_ID CHAR 20 0 0 SAP Fiori ID
TILE CHAR 100 0 0 Tile
FLP_USER SYUNAME CHAR 12 0 0 User Name
FDATE SYDATUM DATS 8 0 0 System Date
FTIME SYUZEIT TIMS 6 0 0 System Time
CATALOGEID /UI2/PAGE_ID CHAR 100 0 0 Catalog ID
CATALOGE CHAR 200 0 0 Cataloge Title
TGROUPID /UI2/GROUP_ID CHAR 100 0 0 Group ID
TGROUP CHAR 200 0 0 Group Title
TARGET CHAR 200 0 0 Target
SEMANTICOBJECT CHAR 40 0 0 Semantic Object
ACTION CHAR 40 0 0 Action
PARAMETERS CHAR 200 0 0 Parameters

 

 

 

5- Create Odata Service : and implement the create method to post the logs.


Below is the create entity
    DATA : ls_output       LIKE er_entity,
ls_zflptracking TYPE zflptracking.

io_data_provider->read_entry_data(
IMPORTING es_data = ls_output
).

MOVE-CORRESPONDING ls_output TO ls_zflptracking.

CALL FUNCTION 'GUID_CREATE'
IMPORTING
ev_guid_16 = ls_zflptracking-track_no
* EV_GUID_22 =
* EV_GUID_32 =
.


ls_zflptracking-flp_user = sy-uname.
ls_zflptracking-fdate = sy-datum.
ls_zflptracking-ftime = sy-uzeit.


* X-SAP-UI2-PAGE:X-SAP-UI2-CATALOGPAGE:SAP_SFIN_BC_AA_DOC_PROC:00O2TPKTQCDUX5DENYJNYYXTU
SPLIT ls_zflptracking-catalogeid AT ':' INTO TABLE DATA(lt_segments).
SPLIT ls_zflptracking-target AT '#' INTO TABLE DATA(lt_target).
READ TABLE lt_target INTO DATA(lv_targetval) INDEX 2.
SPLIT lv_targetval AT '-' INTO TABLE DATA(lt_semact).
READ TABLE lt_semact INTO DATA(lv_action2) INDEX 2.
SPLIT lv_action2 AT '?' INTO TABLE DATA(lt_action).
READ TABLE lt_action INTO DATA(lv_action) INDEX 1.
READ TABLE lt_semact INTO DATA(lv_semobj) INDEX 1.

ls_zflptracking-semanticobject = lv_semobj.
ls_zflptracking-action = lv_action.
ls_zflptracking-catalogeid = lt_segments[ 3 ].



"Get FIORI APP ID
SELECT SINGLE fiori_id FROM sui_tm_mm_app
INTO @DATA(lv_fiori_id)
WHERE sem_obj = @lv_semobj AND sem_act = @lv_action.
IF sy-subrc = 0 and lv_fiori_id is NOT INITIAL.
ls_zflptracking-fiori_id = lv_fiori_id.
ENDIF.

INSERT zflptracking FROM ls_zflptracking.

 

 

6- You are ready to go.


 

 

Here is my ALP Report based CDS query.


 

 

 

Ideas to enhance the plugin:



  • Add switch on/off flag

  • cash the array of the tile in the browser cashe


 

looking to hear all your suggestions to improve:)

 

 

Thanks to my friend for his help and contribution: vivek.anandhan


 
15 Comments
gregorw
SAP Mentor
SAP Mentor
Hi Musa,

have you thought about sharing your project on a public Git repository using abapGit?

Best Regards
Gregor
ahmed_almudaweb
Discoverer

Nice job  musa.

former_member445317
Discoverer
0 Kudos
Hi, Good Day!

Thanks for the wonderful blog, i have one query regarding app type.

With ECC 6.0 i am not able to figure out the app type if it is transaction, custom or web dynpro.
Will you be able to advise here?
Mr-Musa
Explorer
0 Kudos
Hi ,,

it's one of the Fiori Floorplans.
Check this.
Analytical List Page | SAP Fiori Design Guidelines
crepmaster
Participant
0 Kudos
Hello and thanx for the great blog.

I'm quite new with Fiori apps. Did you create a consumption CDS from the zflptracking table? if yes witch annotation did you use to achieve your goal?

Thank you
Mr-Musa
Explorer
0 Kudos
Actually I have used app. "Manage KPIs & Reporting". You need to get your data as Anaytical CDS to supply the report.

check: https://blogs.sap.com/2018/03/18/create-an-analytical-model-based-on-abap-cds-views/

 

Then using the app. "Manage KPIs & Reporting" you creat a group then KPI then from KPI you can create you ALP report easily drag drop.
Mr-Musa
Explorer
I'm not much familier with how to 🙈 but for sure I will try improve the idea and do so.

Sorry for my late response.
crepmaster
Participant
0 Kudos
Hello Musa and thanx for your reply the link was really hepfull, i'm wondering how you have build your cube. Have you make son specific association?

Thanx again.

Hi,

Thanks for this wonderful blog, Can you please suggest an alternate way to achieve same functionality or at least getting tile name and target mapping clicked by the user in spaces and pages as this sap.ushell.services.LaunchPage (ondemand.com) seems to be deprecated for fiori 2020.

Thanks in advance!

Mr-Musa
Explorer
0 Kudos

Thanks for your comment. Soon I will update with the blog with latest changes (to handle both cases: Groups or Spaces)

Mr-Musa
Explorer
0 Kudos
Sorry for my late response.


CDS should have the following annotation -->  @Analytics.dataCategory: #CUBE

At lease on field should be having the following annotation (Measures  --> @DefaultAggregation: #SUM



Then Consume the cub CDS in new CDS (@Analytics.query: true ) and publish Odata then you will be able to use this in KPI & Report app.


CDS Analytical Projection Views – the new Analytical Query Model | SAP Blogs
semanti1
Member
0 Kudos
Hello Musa,

 

Thanks for the wonderful blog!

I am referring to your blog to implement a similar solution. But we are facing issue when user clicks shell tiles. When a shell tile is clicked once, two records are being saved in the database table, though network trace shows single POST call, but for other tiles : for custom reports or SAP standard applications this is working fine.

Can you please suggest a probable root case and how can we fix this?

Thanks and Regards

Semanti Sinha Mahapatra
0 Kudos
Hello Musa,

Thanks for the wonderful blog!

We are facing issue when user clicks shell tiles. Whenever the app opens in a new tab, two records are being saved in the database table, though network trace shows single POST call, but for other tiles : for custom reports or SAP standard applications this is working fine.

Can you please suggest a probable root case and how can we fix this?

Thanks,

Roshni
damu_a
Explorer
0 Kudos
Hi Musa,

 

Did you update the Plug-in related source code to support latest versions of Fiori w.r.t to below error?

"Deprecated as of version 1.99. This service has been deprecated as it only works for the classic homepage."

Thanks

Damodara
hussain_p
Participant
0 Kudos

HI Musa,

can you update with the blog with latest changes (to handle both cases: Groups or Spaces)

Labels in this area