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: 
Martin-Pankraz
Active Contributor

Dear all,

Have you been wondering when you would finally be able to put comments on your Design Studio dashboards in a decent and tremendously customizable way for free? Well, that day is today!

In the following sections I will showcase my new component ConVista EasyComment which is published open-source on GitHub, talk about the backend integration, comment saving & loading and the overall commentary architecture involved.

What do you get?

Obviously to put some comments you need a place where you can do that. I decided to use a WYSIWYG (What You See Is What You Get) HTML editor. There are a couple of libraries out there providing editors like that. My choice was CKEditor because of a well documented API, a suitable developer license and the ability to Paste from MS Word. You could also look into tinymce and Froala just to mention a few more.

You can extend gracefully by implementing your own editor plugins by the way.

     Fig.1 Demo dashboard

My SDK component ConVista EasyComment comes with lots of built in functionality like spell-checking, multi-language support, the ability to add images, an option to adjust the reading direction and many more. These features are provided by the CKEditor library out of the box.

The save button (icon on the bottom right of the toolbars) exposes its functionality to the DesignStudio SDK component event On Save Button Clicked. You can also extract/modify HTML content on the editor using the scripting methods getHTMLString and setHTMLString.

You can customize the toolbars to be shown through the component property Toolbar Settings. I used the new SDK 1.6 feature that allows to put complex objects on the contribution file for that. That way DesignStudio creates a table like input window:

     Fig 2 Properties


You can activate/deactivate the toolbars one by one. For the Document section which contains the save button you can decide even on item level (but you can’t hide the save button ;-). Let’s put false on every item except for Editing and see what we get.

     Fig 3 Reduced editor toolbar view


If you need more fine grained customization you will need to get back to me or adjust the coding on the SDK component yourself. Now let’s jump to the fun part.

On Saving and Loading

At first I am going to tell you about the frontend part which is covered by the EasyComment component and how to model a data structure to store our DesignStudio comments before actually moving over to the backend part to show you possible starting points to implement your individual solution.

To be able to actually persist and successfully load a comment for a specific DesignStudio object you need to identify the object itself and maybe its filter state. For static content this very easy and straightforward. We could just take the technical name of the targeted object as key and save our HTML-string along with it on a table on our backend. For dynamic content like charts with arbitrary complex filter possibilities this can be a very complicated task.

Some of the commercial DesignStudio commentary components approach this topic on the SAP backend by evaluating for example BEx query state and learn the object state from there. That way they can identify the right comment to load or with what key to store it. To get this done for all of the possible DesignStudio data sources like BEx queries, BW cubes, Universes, Custom SDK data sources, CSV files and HANA views is quite a lengthy task for an ABAP developer.

Don’t make this harder as it needs to be!

My approach is not going to cover all kinds of complex scenarios but it will be as easy as it gets and get the job done for many cases. At first I make the assumption that it is sufficient to store only a limited number of characteristics values to successfully identify the breakdown of a value on a component like a DesignStudio chart, crosstab, KPI-View or Scorecard. Let’s differentiate two cases:

  • Static only content like DesignStudio texts or objects themselves and
  • dynamic content like data breakdowns and key figures on Crosstabs or Charts.

All of the static content can be covered by its technical object name and the dashboard they are on for example:

Key Fields

HTML Content

DashboardID

Object Technical Name

MYDASH_1

Demo_dashboard

<h1>This a comment for a dashboard itself</h1>

MYDASH_1

SOME_QUERY

<i>This is a general comment on a query</i>

MYDASH_2

TEXT_TITLE

<h2><b>This is a comment for a standard text</b></h2>

     Table 1 Static objects comment saving


Now on the dynamic stuff. From my experience many cases that need comments for key figure release processes for example, there is only a limited number of filter values involved. Often you can get away with an accounting basis, an accounting entity and a key date (single date, date ranges and etc.).

Key Fields

HTML Content

DashboardID

Obj tech. Name

Acc. Basis


Acc. Entity

Key date

MYDASH_1

QUERY1

GAAP

COMP1

10.03.2016

<p>some html content</p>

MYDASH_1

HANA_CALC_VIEW

GAAP

COMP1

01.01.2016

<p>year end forecasts are looking good</p>

MYDASH_1

CHART_1

COMP2

10.03.2016

<p> Please check the spike! </p>

     Table 2 Dynamic objects comment saving


How do you provide this data to the WebService?

DesignStudio offers lots of scripting methods that already provide what we need:

  • DashboardID: Accessible through APPLICATION.getInfo().name


  • Object technical Name: All SAP data sources (except SDK data sources) provide the method getInfo() which gives you access to the underlying meta data. The technical name is part of it.

  • Accounting Basis, Accounting Entity and Key date: Data sources offer methods to retrieve key-value pairs for given dimensions and DesignStudio components like the Dimension Filter give the user the ability to filter certain values on demand. When working with filter variables you can for example use the following script to learn their current setting influenced by the user input during runtime:

    

     var vars = DS_1.getVariables();

     vars.forEach(function(element, index) {

       if(element.inputEnabled){

         DS_1.getVariableValueExt(element.name);

    }

});


You could save the values for later usage with the ConVista EasyComment using the SCN community SDK component ARRAY.

Now that we learned how to retrieve keys to identify our data sets, we are ready to send some HTML-strings to the backend. Exciting, isn’t it!? Let me give you a simplified example.

As I already told you before, there is an event provided by the EasyComment component which gets triggered when you click the save button on the editor. Here is a script from a demo application:

             //cache busting

var ccid = APPLICATION.getTickCount();

//retrieve an accounting entity

var bukrs = DROPDOWN_1.getSelectedValue();

//set http request method

      me.setHttpMethod("POST");

      me.setServerUrl(

     "http://<sap backend>:<port>/sap/bc/<WebService Endpoint>?bukrs="+bukrs+"&ccid="+ccid

);

//Actually Trigger the save

      me.saveHTMLOnServer();


This DesignStudio script sets up the HTTP parameters and sends a POST request to the server. The method saveHTMLOnServer internally retrieves the current HTML-string from the editor on execution. If everything on the backend went good, you just saved your first comment!

To retrieve it again you need some more scripting and an approach how to expose that functionality. Usually people go for selection events in some sort of way. Let’s check out an example with a Dropdown.

     Fig 4 Editor full cycle interaction


Once the user selects an entity from the dropdown, the components On Select method fires. In there I put the following scripting:

            //Get the currently selected entity

var bukrs = me.getSelectedValue();

//Cache busting

var ccid = APPLICATION.getTickCount();

COMMENT_1.setServerUrl(

     "http://<sap backend>:<port>/sap/bc/<WebService Endpoint>?bukrs="+bukrs+"&ccid="+ccid

);

//Set HTTP request method

COMMENT_1.setHttpMethod("GET");

//Actually trigger the load

COMMENT_1.loadHTMLFromServer();

The above script loads the saved comment into the editor according to the selection on the dropdown. If you need to more than just an accounting entity to select your comment, like in my example, you will have to enrich this scripting slightly (e.g. put some more URL parameters etc.).

In light of above you can easily imagine how to extend this approach to serve your specific needs without aiming for a general solution for every possible scenario and putting hundreds of hours. Now let’s have a look at a possible SAP backend WebService class implementation to take care of the saving and loading of our precious HTML-strings.

Integration of the SDK component with a server

In order to be able to save the HTML content you add to the editor, I implemented the DesignStudio SDK component to be ready to integrate with a RESTful Web Service. I am using the standard JavaScript object XMLHttpRequest to manage the communication from the browser to the backend. Of course Cross-Origin Resource Sharing (CORS) problems might apply at this point if you are hosting your dashboard on a different server than the backend. To overcome that browser security problem you have to setup your backend code to supply two HTTP headers on the HTTP response:

Access-Control-Allow-Origin: true

Access-Control-Allow-Credentials: true

I will show an easy ABAP example below. At first you have to provide an ABAP class which will serve as the handler for the WebService communication.

  • ABAP class setup

Create a standard class and put it on your local objects or a development package.

    

Put the following two interfaces to provide your custom implementation for the SAP standard HTTP interfaces.

    

Once you save, the class structure will immediately be generated and look something like this:

    

In order to put your custom WebService behavior you will have to implement the method HANDLE_REQUEST. Before that there is one more step. We need to register this class with an ICF node. To do so, call transaction SICF and create a new node under default_host > sap > bc.

    

Put your class under the handler list and save. Go back and activate the ICF node. Hit test to learn your WebService endpoint URL and check if the registration worked. You will need that URL for the DesignStudio scripting and also for easy testing purposes with your browser.

Note that every user induced URL call on a browser is basically an HTTP GET request.

  • HTTP CORS setup and HANDLE_REQUEST implementation

Now I am going to show you the essential ABAP code to get started. You need to be able to retrieve URL parameters from the HTTP requests, put CORS headers on your response and send the response to the client. This is done using SAP standard interface methods:

constants:
lc_header_mimetype_name      
type string value 'Content-Type',
lc_header_mimetype_value_html
type string value 'text/HTML; charset=utf-8',
lc_header_aca_origin         
type string value 'Access-Control-Allow-Origin',
lc_header_aca_credentials    
type string value 'Access-Control-Allow-Credentials',

lc_true                      
type string value 'true'.

data: _request_method    type string,
lt_inputparams       
type tihttpnvp,
ls_inputparams       
like line of lt_inputparams,
ld_bukrs             
type i,
ld_html_string       
type string,
ld_cors_callee       
type string,
ld_request_payload   
type string.

  "Get passed parameters
call method server->request->get_form_fields
changing
fields = lt_inputparams.
"Get passed payload, HTML data
call method server->request->get_cdata
receiving
data = ld_request_payload.
“ CORS setup
ld_cors_callee
= 'http://<server hosting DesignStudio>:<port>'.

  "Translate Input Parameters to Uppercase
loop at lt_inputparams assigning <ls_inputparams>.

translate: <ls_inputparams>-name  to upper case.
case <ls_inputparams>-name.
when 'BUKRS'.
ld_bukrs
= <ls_inputparams>-value.
endcase.
endloop.

_request_method
= server->request->get_header_field( name = '~request_method' ).
"Determine if method is get or post.
if _request_method = 'GET'.
"set the response mimetype to HTML
server
->response->set_header_field
( name  = lc_header_mimetype_name
value = lc_header_mimetype_value_html ).
"Set CORS access control to avoid browser policy restrictions
server
->response->set_header_field
( name = lc_header_aca_origin
value = ld_cors_callee ).
server
->response->set_header_field
( name = lc_header_aca_credentials
value = lc_true ).


“Do your table loading implementation here and assign to ld_html_string


"set the cdata response to the text
server
->response->set_cdata( data = ld_html_string ).

elseif _request_method = 'POST' .

"set the response mimetype to HTML
server
->response->set_header_field
( name  = lc_header_mimetype_name
value = lc_header_mimetype_value_html ).

"Set CORS access control to avoid browser policy restrictions
server
->response->set_header_field( name = lc_header_aca_origin
value = ld_cors_callee).
server
->response->set_header_field
( name = lc_header_aca_credentials
value = lc_true ).
“Do your table saving implementation here and send given html back to have a graceful answer since the SDK component is “assigning back the data coming from the server to the editor “right away
"set the cdata response to the text
server
->response->set_cdata( data = ld_request_payload ).

endif.

Make sure you send the send HTML-string back on POST requests because the EasyComment component relies on setting the HTML response to the editor as assurance that the saving worked. You could write a message here if something is wrong too. Further error handling is not implemented yet.

  • Tables

To get you started have a look at the table examples in the previous section. Put the table coding at the sections highlighted in red above on the ABAP code.

Once all of that is done, put an example value on your table and make a browser GET request using the URL we remembered before. If that works, your WebService is ready to serve and you can start integrating with EasyComment. Now start saving some comments even with images attached! :smile:

     Fig 5 EasyComponent editor with image on comment


Commentary Lifecycle (Commentary Solution Architecture)

To sum up the technical part I would like to provide a high level view on what I showed you in detail before.

     Fig 6 Commentary Lifecycle Deployment View


In DesignStudio you need to put some logic to trigger the RESTful WebService and think about how to make that accessible to the user during runtime. On the backend you need to provide the communication endpoint for the RESTful WebService to deal with the HTTP requests. In my case that was SAP BW but the implementation is by no means limited to that. You could call any other system.

     Fig 7 Commentary Lifecycle Implementation View

This sequence diagram visualizes the function calls on the involved software instances. DesignStudio scripting and events trigger internal methods on the EasyComment SDK component. As a result the component communicates with the backend to actually save and load HTML content. The callbacks deliver the content to the frontend.

What’s next?

As a next step I want to implement, what I call “Live-Commentary”. This means you no longer need to save your html content actively by hitting the save button but just start typing and save immediately. This will be achieved using WebSockets which enable full-duplex communication. User-Authorization at a side, this will allow users to edit comments even in parallel, seeing what their colleague does right away. Some of you might be familiar with that behavior from google docs or similar applications. I will keep you posted as development progresses.

Final Words

You are now able to enrich your DesignStudio dashboards with shiny comments up to a complexity that suits your needs. The frontend technology to get you started is already setup and implemented. The only open task is to decide how to store your HTML content. I have shown you a possible starting point to get this done quick and easy. Now find yourself an ABAP developer or roll up your own sleeves and have fun commenting.

You can get the component by installing the ConVista SDK components package which is available on GitHub:

ConVista-ds-sdk-visualizations by MartinPankraz

As always feel free to leave comments and ask lots of follow up questions.

Yours

Martin

45 Comments
Labels in this area