Skip to Content

Let’s Build an Analytical Card for a Fiori Overview Page (with a HANA Backend)

Overview Pages are a core part of the Fiori 2.0 Vision, and if you are using the Fiori Launchpad to any great extent, you’ll find that demonstrating the Overview Page will immediately get people’s attention (albeit with a danger it gets overused in the wrong context, but that’s a different post that SAP should really address).

So let’s talk through the process of creating an Overview Page, with an example of building an Analytical Card with a filter.

The Proposed Process

Step 1: Identify the need

Step 2: Design

Step 3: Back-end development

Step 4: Front-end configuration (or really development at this point)

What’s most important (always) is Step 1 and Step 2; but this post will focus on Step 3 and Step 4 since I feel when doing these steps, the documentation is all there in places like and sapui5, but is still pretty cryptic for beginners. That said, this is guide to help you see a real example, and not really training material. Actually, it’s more just a dump of information but if you are persistent and give this a go yourself, it should at least help with knowing you’ve got all the bits to put it together.

Step 1 – Identify the Need

This is not a technology looking for a problem; but a technology that can address real User Experience issues and opportunities for some groups of people. I think the most obvious one is a People Manager Overview Page with a Smart Tile that highlights the need to look at it. E.g. Upcoming important dates like birthdays or contract end dates; Leave Calendar, Team Timesheet status.  These are all Smart Business Tiles at my current Customer, but Home Page Tiles are valuable real estate (like your smart phone’s screen), so let’s not force our functionality all to the home page.

Step 2 – Design has a fairly rudimentary version of the Overview Page; hence we ended up just using drawn pictures in a freestyle build project; and in reality, an Excel spreadsheet was the final mockup/documentation for each Card. Hopefully improves with the ability to shape the output over time; but at least producing this for end users; helps drive the discussion early to avoid rework after the build.

Step 2.5 – Design -> Build transition

Consider this Card design:

Here we have a few things to consider:

  1. A Heading
  2. A KPI Value with a Unit of Measure
  3. A Comparison KPI Value (for percentage increase/decrease)
  4. Some grouping information (Material Group A and EMEA)
  5. A graph title
  6. An x-axis dimension (year in this case)
  7. A y-axis measure (number of cancelled purchase orders in this case)
  8. A range of data (e.g. 4 data points, 1 for each year)
  9. Potentially the semantic navigation when you click on the header, or select a specific dimension (in this case, “year”).
  10. Potentially the global filter that should be applied at the Overview Page level (note – For multiple cards; the technical name of the fields to filter by needs to be consistent across cards).

Except for Titles and semantic navigation, this pretty much defines the type of data we need to expose via oData to the Card and helps drive the discussion of what needs to be developed.

If done right, the data that gets exposed can be used well beyond just the overview page card; and will make the Front-End configuration trivial.

Note – I will point out, I’m still confused by some design choices for the Card definitions (e.g. Trend calculations in the 1.40 UI5 version compared to 1.38) so your mileage may vary depending on your desired requirements.

Real World Example…

In order to write this post, I’ve taken the following semi-real requirement for an analytical Card.

What we want to see is an Analytical Card which highlights the % calculation for Preventative Maintenance versus Total Maintenance. We also want to filter it by Work Centre. E.g. It should look something like this.

Based on above, a quick summary of the information provided is:

Title: Preventative Maintenance hours versus Total Maintenance hours

x axis: month

y axis: Percentage

y axis unit: %

KPI Header Value: This month’s percentage

KPI Comparison Value: Last month’s percentage

Show: Last 4 months

Filter: By Work Centre

Order: By month ascending

Navigation: To intent “MaintenanceHours-Analysis” (for example)

… in a Trial World

Now I don’t like writing a tutorial that you can’t go try yourselves, so I’ve leveraged an MDC HANA instance on an HCP Trial account to create the XSOData service which will expose the right Calculation View for the above to be possible. This will let you test it inside the UI5 WebIDE, but don’t expect to be able to deploy this scenario as is.

FYI – The one thing required to run this is create a destination in the HCP Cockpit like follows then your destination can be referenced in the UI5 webide and can call XSOData services exposed from the MDC HANA instance:

Step 3 – Backend Development (in HANA)

For simplicity, I’ve created the following dummy tables and data representing the ERP data (create your own tables and data which is easy to do and worth learning if you don’t know how):

  1. Work Orders (simplified version of AUFK but artificially including Work Centre to simplify the data model)
  2. Time Entries (simplified version of CATSPM)


Work Orders (where Z1 is preventative, and Z2 is corrective):

Time Entries:

So in essence, we need a Calculation View in HANA which provides a month by month breakdown totalling all Z1’s hours and all Z2’s hours. We also need to calculate the percentage for each month; and be able to provide the current month’s percentage (KPI) and last month’s percentage (comparison KPI).

I’m not a HANA Calculation View modelling expert and you’re going to need to know some HANA modelling to get through this bit. For those who are experts, I’d love some feedback and I encourage you to blog about some complex calculation view problems you’ve solved.

So here’s the high level solution, with some screen shots.

The HANA solution consisted of the following files:


  • MaintenanceHoursOVP Calculation View which provides us a month by month view of preventative maintenance and corrective maintenance.
  • MaintenanceHoursGroupedByMonth table function which was created to group the previous calculation view by month consistently (the why will be explained below)
  • MaintenanceHoursOVPFinal Calculation View which is the final aggregation on top of the previous Table Function which also calculated the percentage, and “this month”’s percentage and “last month”’s percentage for the KPI value.
  • xsodata definition pointing at MaintenanceHoursOVPFinal Calculation View providing our odata endpoint

MaintenanceHoursOVP Calculation View looks like this:

Projection_1 is pretty much just a vanilla projection of the dummy Work Orders table.

Projection_2 is pretty much just a vanilla projection of the dummy Time Entries table but using some string manipulation; we’ve created 2 calculated columns (Year and Month).

Projection_4 is using the standard M_TIME_DIMENSION table in HANA (I’ve previously generated time information using the Eclipse wizard to do this).

I’m working with Month values so I’ve filtered by the 1st of each month; plus looking at only the last 24 months of data.  Note – To do a relative date, I’ve created a calculated column called MonthsBack (this is quite useful in a future calculation you’ll see shortly).

The join between Work order and Time Entry is a simple 1.n relationship from Work Order to Time Entry:

The join between Calendar and the above join uses the month/year and while in reality, there will always typically be a work order for every month; we need to mark it as a right outer join (which could occur if you ran this on a new month before any work time had been registered).

Now for the final Aggregation takes the output of Join_2, uses hours as one of the measure and creates a number of calculated columns:

  • MonthName – Made from the DATE_SQL by using the useful function “monthname”
  • PreventativeHours and CorrectiveHours (requires use of the IF statement tocalculated totals based upon work order type – in reality, it will be a few IF statements chained together)
  • Percent Preventative (calculated using the other 2 calculated values)
  • Ignore the UoM Calculated columns for the moment as that will be discussed shortly

Finally, adjust the semantics on each measure (semantic definitions aren’t actually required at this point):

Now this Calculation View would actually be quite useful for anlaysis but for now, this is just the source for our table function. Now why do I need a table function?  To be honest, it’s to get around anomalies with my understanding about how the above aggregation responds based upon what you select.

e.g. The Overview Page makes a few requests. One of these is the request for the graph data; and another is for the KPI values.  The funny thing if I added a calculated column called “This Month percentage” and “Last Month percentage”; and I select only these 2 columns from the calculation view, HANA optimises the request in a way that produces unusual results for me (e.g. Not grouping by month). To get around this, we create a Table Function with a group by clause hopefully forcing the outcome we want.


FUNCTION "HANA_USER"."ovp::MaintenanceHoursGroupedByMonth" ( ) 
	RETURNS TABLE ( "MonthName" VARCHAR(20), "MonthsBack" INT, "WORK_CENTRE" VARCHAR(10), 
"PreventativeHours" FLOAT, "CorrectiveHours" FLOAT, "PercentPreventative" FLOAT )
return SELECT	 
	 sum("PreventativeHours") AS "PreventativeHours",
	 sum("CorrectiveHours") AS "CorrectiveHours", 
	 sum("PercentPreventative") AS "PercentPreventative" 
FROM "_SYS_BIC"."ovp/MaintenanceHoursOVP" 
	 "DATE_SQL", "MonthsBack", "MonthName", "WORK_CENTRE"
order by "DATE_SQL";

With this, we can now make a dedicated Calculation View to expose to the Card. The bonus of a using a dedicated calculation view is we can do some prefiltering to return just the 4 values we want to display on the graph:


Project_1 looks like this (simply the Table Function as the data source, and 2 calculated fields:

This Month Percentage looks like this:

and “=1” instead of “=0” for Last Month’s calculated column.

I also added the filter “MonthsBack” < 4 to just return 4 results.

E.g. The use of MonthsBack makes the above calculations pretty easy!

Unit of Measures are actually shown in Cards based upon semantic definitions.  In HANA you can tag a measure with the semantic tag “Quantity with Unit of Measure”. It supports a constant value but it appears that the Overview Page only supports a Unit of Measure that is linked to another column, so this now explains why I’ve added PercentUoM columns.

Finally we set the dimensions/measures appropriately and we are ready to create the XSOData service.

First, we created a dedicated package (as shown above).  The package needs an .xsapp file and a .xsaccess file (new->File):

.xsapp contains:


.xsaaccess contains:



"exposed" : true,

"authentication": null,

"prevent_xsrf" : true,



"enabled": true,

"customHeaders": [ {"name":"X-Frame-Options","value":"SAMEORIGIN"} ]



Then finally the xsodata file itself (new file and call it [service name].xsodata)

Contents, something like this:



"ovp/MaintenanceHoursOVPFinal.calculationview" as "MaintenanceHoursPreventative"

keys generate local "GeneratedID"

aggregates always;


annotations {

enable OData4SAP;


At this point, you can run the XSOData service and start playing with the calculation view via the browser. At this point, note down the URL as you’ll use the relative path when setting up to enter into your HANA connection

Front End Configuration

Create an Overview Page Project (New Project from Template, Overview Page Application) pointing at your XSOData service . When the new project wizard shows the Annotation Selection screen, just press Next since we’re going to add a local annotation file after the wizard is finished. Note – If the Overview Page Application is not shown, you’ll need to activate it in the plugins folder in WebIDE settings.

Now you can add your analytical card (New-> Card from the root folder).

The only really thing to explain here is the following configuration:

First – What is an annotation? Put simply, imagine you are moving your furniture and you want boxes to be put in certain rooms.  What you do is write on the box, or put a sticky note on it and say “this goes in the lounge room”; or “this goes into bedroom 1”. Well this is what annotations are used for. To tell the mover (the UI) where to put the box (the field).

On top of this are qualifiers. A qualifier is like using the same sticky notes for 2 different moving jobs. They both say “this goes into bedroom 1” but maybe you add the qualifier “Fred’s house” and “Terry’s House” to ensure the boxes end up in the right house’s bedroom 1.

So while you could just press Next and not add anything; I’d suggest you add a qualifier to each of the above annotations.  In our case, let’s just add #preventative to each of these.

If you open the manifest file, it should look something like this:


"sap.ovp": {

"_version": "1.1.0",

                           "globalFilterModel": "OVP",

                           "globalFilterEntityType": "MaintenanceHoursPreventativeType",

"cards": {

"Example_card00": {

"model": "OVP",

"template": "",

"settings": {

"title": "{{Example_card00_title}}",

"entitySet": "MaintenanceHoursPreventative",

"selectionAnnotationPath": "",

"chartAnnotationPath": "",

"presentationAnnotationPath": "",

"dataPointAnnotationPath": "",

"identificationAnnotationPath": ""





The next step is to select the webapp folder and add a local annotation file to your project (with future CDS implementations in S4, you create annotations at the source).

Now make sure that in the WebIDE plugins you have the Annotation Modeller enabled then go ahead and open the annotation file in the Annotation Modeller.

Now this is the most cryptic part of annotating, and rather than describe it to you; I’ll give you the final version of the annotations used in this example:

The full annotation file looks like this:

<edmx:Edmx xmlns:edmx="" Version="4.0">

<edmx:Reference Uri="/sap/bc/ui5_ui5/ui2/ushell/resources/sap/ushell/components/factsheet/vocabularies/UI.xml">

<edmx:Include Alias="UI" Namespace=""/>


<edmx:Reference Uri="/sap/bc/ui5_ui5/ui2/ushell/resources/sap/ushell/components/factsheet/vocabularies/Communication.xml">

<edmx:Include Alias="vCard" Namespace=""/>


<edmx:Reference Uri="/sap/bc/ui5_ui5/ui2/ushell/resources/sap/ushell/components/factsheet/vocabularies/Common.xml">

<edmx:Include Alias="Common" Namespace=""/>


<edmx:Reference Uri="">

<edmx:Include Alias="Core" Namespace="Org.OData.Core.V1"/>


<edmx:Reference Uri="">

<edmx:Include Alias="CQP" Namespace="Org.OData.Measures.V1"/>


<edmx:Reference Uri="">

<edmx:Include Alias="Capabilities" Namespace="Org.OData.Capabilities.V1"/>


<edmx:Reference Uri="">

<edmx:Include Alias="Aggregation" Namespace="Org.OData.Aggregation.V1"/>



<Schema xmlns="">

<Annotations Target="ovp.xsodata.OVP.MaintenanceHoursPreventativeType">

<Annotation Term="UI.Chart" Qualifier="preventative">

<Record Type="UI.ChartDefinitionType">

<PropertyValue Property="ChartType" EnumMember="UI.ChartType/ColumnStacked"/>

<PropertyValue Property="Measures">






<PropertyValue Property="MeasureAttributes">


<Record Type="UI.ChartMeasureAttributeType">

<PropertyValue Property="Measure" PropertyPath="PreventativeHours"/>

<PropertyValue Property="Role" EnumMember="UI.ChartMeasureRoleType/Axis1"/>

<PropertyValue Property="DataPoint" AnnotationPath="@UI.DataPoint#preventativehours"/>


<Record Type="UI.ChartMeasureAttributeType">

<PropertyValue Property="Measure" PropertyPath="CorrectiveHours"/>

<PropertyValue Property="Role" EnumMember="UI.ChartMeasureRoleType/Axis2"/>

<PropertyValue Property="DataPoint" AnnotationPath="@UI.DataPoint#CorrectiveHours"/>




<PropertyValue Property="Dimensions">





<PropertyValue Property="DimensionAttributes">


<Record Type="UI.ChartDimensionAttributeType">

<PropertyValue Property="Dimension" PropertyPath="MonthName"/>

<PropertyValue Property="Role" EnumMember="UI.ChartDimensionRoleType/Category"/>




<PropertyValue Property="Actions">





<Annotation Term="UI.DataPoint" Qualifier="preventative">

<Record Type="UI.DataPointType">

<PropertyValue Property="Title" String="{@i18n&gt;@CURRENT_MONTH_PREVENTATIVE_PERCENTAGE}"/>

<PropertyValue Property="Value" Path="ThisMonthsPercentage"/>

<PropertyValue Property="CriticalityCalculation">

<Record Type="UI.CriticalityCalculationType">

<PropertyValue Property="ImprovementDirection" EnumMember="UI.ImprovementDirectionType/Maximize"/>

<PropertyValue Property="ToleranceRangeLowValue" String="50"/>

<PropertyValue Property="DeviationRangeLowValue" String="50"/>



<PropertyValue Property="TrendCalculation">

<Record Type="UI.TrendCalculationType">

<PropertyValue Property="ReferenceValue" Path="LastMonthsPercentage"/>

<PropertyValue Property="IsRelativeDifference" Bool="true"/>

<PropertyValue Property="UpDifference" Decimal="5"/>

<PropertyValue Property="StrongUpDifference" Decimal="10"/>

<PropertyValue Property="DownDifference" Decimal="5"/>

<PropertyValue Property="StrongDownDifference" Decimal="20"/>





<Annotation Term="UI.DataPoint" Qualifier="preventativehours">

<Record Type="UI.DataPointType">

<PropertyValue Property="Title" String="{@i18n&gt;@PREVENTATIVE_HOURS}"/>

<PropertyValue Property="Value" Path="PreventativeHours"/>



<Annotation Term="UI.DataPoint" Qualifier="CorrectiveHours">

<Record Type="UI.DataPointType">

<PropertyValue Property="Title" String="{@i18n&gt;@CORRECTIVE_HOURS}"/>

<PropertyValue Property="Value" Path="CorrectiveHours"/>



<Annotation Term="UI.SelectionFields">





<Annotation Term="UI.PresentationVariant" Qualifier="preventative">

<Record Type="UI.PresentationVariantType">

<PropertyValue Property="SortOrder">


<Record Type="Common.SortOrderType">

<PropertyValue Property="Property" PropertyPath="MonthsBack"/>

<PropertyValue Property="Descending" Bool="true"/>




<PropertyValue Property="GroupBy">



<PropertyValue Property="TotalBy">



<PropertyValue Property="Total">



<PropertyValue Property="InitialExpansionLevel" Int="1"/>

<PropertyValue Property="Visualizations">



<PropertyValue Property="RequestAtLeast">





<Annotation Term="UI.SelectionVariant" Qualifier="preventative">

<Record Type="UI.SelectionVariantType">

<PropertyValue Property="Parameters">



<PropertyValue Property="SelectOptions">





<Annotation Term="UI.Identification" Qualifier="preventative">


<Record Type="UI.DataFieldForIntentBasedNavigation">

<PropertyValue Property="Determining" Bool="false"/>

<PropertyValue Property="SemanticObject" String="Action"/>

<PropertyValue Property="RequiresContext" Bool="true"/>

<PropertyValue Property="Action" String="toappnavsample"/>









Wrap-Up and General Thoughts

Overview Pages should be (and to an extent are) easy to build/configure.  Though with limitations and changing card characteristics between releases, it’s still a bit disjointed between design and build since designers really need to understand the possibilities with the various versions of the card.  That said; providing insight to action; and once the link card is finally released; a place where a very generic “role” can come to work; this really will enhance people’s user experience compared to a Launchpad with Tiles alone. Personally, I hope more detailed real-world how-to guides (that go to much more detail than what I’ve skimmed over) are created. And for designers, more real-world and complete overview page examples are provided within

You must be Logged on to comment or reply to a post.
  • Hi Matt,

    thank you for this great walkthrough. Would you be up for to add it to the SAP Event Registration app to show the number of registered participants in a month compared to the previous month and a chart of the last 6 month? Do you know if the OVP is supported also in the HCP Fiori Launchpad?

    Best regards

    • Hi Gregor,

      It should work fine in the HCP Fiori Launchpad (it's more a standalone Fiori component project needing an FLP to run from but can probably be run even completely standalone if I think about it)...

      The actual development is trivial, though just need to see how it could fit in with the SAP Event Registration app.  What you are describing (I'm guessing) is probably better done as a Smart Business Tile (or pretend one at least if there's already a Fiori Launchpad) and it could either launch the app, or a Smart Business Report alternatively (or one of the hundred other graphing/analytical tools out there)...

      Maybe email me your thoughts on where this fits in (the scenario), the persona involved (is it for Organiser, participant, etc) and  whether it's just a landing page of info.

      e.g. I can see an Overview Page being interesting if it had 3 or 4 cards of value on it; otherwise it sounds like it might be better to be just a Smart Business Tile, or basic analytical graph/report.


      hmm. Wonder if anyone will ever have an SAP Event in Tasmania...

  • Hi Matt,

    such an excellent blog.... I should say, this is the only blog available in SCN with a clear explanation of the Annotations. I have been building an OVP with at least  8 analytical cards, and I cant explain in words, how much helpful you blog is. unfortunately, I found your blog at the end of my development 🙁



    • Probably not the post to ask that question since it's unrelated to above, but pretty sure the answer is no, unless you set-up a 2nd FLP instance...

  • HI Matt,
    Sorry my question is not related directly to blog but I have a question regarding dynamic json model load in a comparison microchart inside a generic tile. my customer is on s4hana 1511 with sapui5 runtime 1.38 so i cannot use OVP cards . thus i am creating tiles with odata services but i am not bale to bind the items in microchart to the entities in odata. Can you help me out here? It would be better if you can give me an example on xmlviews using generic tile

    • Hi Prabuddha,

      As most would tell you from a moderator perspective, please ask new questions like this as a separate question in, and I'd recommend including your code example here and what is not working and not just asking for example code. People are more inclined to tell you what you are doing wrong as opposed to telling you how to solve your problems.

      That said, the above was done in 1.38, so Overview Pages do work in your release and are an option.



  • Thanks Matt-

    Is it possible to follow same steps and build overview page for On premise Hana backend system using xsodata?

    I am able to connect webide to my On prem hana using through cloud connector. All works fine in webide mock server but I am stuck while deploying the overview page  application on Hana db.

    Test run in hana studio using index.html file show up blank . Am I missing something ?

    One problem I suspect is My Hana sapui5 runtime version is 1.28 whereas OV page requires higher. Is there a way to update my hana sapui5 runtime.

    Am I looking in right direction ??





  • Hi Tanveer,


    An OVP really just consists of a UI5 app, an OData source, and annotations which can exist within the UI5 app, or be provided from the OData source (which is what S4/CDS is all about); so there should be no problems creating your own OVP and deploying it.

    How you deploy it to HANA is probably the real question.  Typically, you deploy an OVP within a Fiori Launchpad, and yes, you should really be above 1.38 (but more realistically above 1.44) to run it.  That said, it sounds like you are deploying it as a standalone app, and in that case, feel free to use the akamai SAPUI5 libraries out there ( and you should be good to go. In essence, you'll be using HANA as just a web server hosting the source files.

    That all said, the OVP only really makes sense in the context of Fiori Launchpad and it serves as a stepping stone from the Home page of Fiori Launchpad, to the more detailed Fiori and reporting apps; so would suggest you start to think about the User Experience you are aiming to achieve for end users as the first point before worrying about deploying them. That is a huge topic in itself BTW.

    Anyway, I'd stick with running it in WebIDE till you figure out where you're heading with the Fiori Launchpad (one reason to suggest this is OVP relies a lot on the navigation via Fiori Launchpad.



    • Hi Matt,

      Thank you so much for  reply. Insights from you helps a lot. I attended your Lecture in TechEd Vegas this year and it is helping a lot in our current project.

      Yes, we have a plan to have OV page launched from Fiori launchpad and not as a stand alone application . I was using index.html just for testing.

      HANA that I am on still have have XS classic ui5 runtime 1.28 and to get the higher version I am process of installing XSA with higher version. So, that takes care of ui5runtime version problem. Will reach out if I run into issues 🙂 🙂

      I am new to this and still learning while developing, so just to confirm I am on right path ??

      1. Connected my On Premise Hana with SAP Webide (cloud) using cloud connector
      2. Built calculation view and exposed the Hana view thru XSODATA and get metadata into Webide
      3. Use Webide's Fiori template and annotation modeler to build Fiori applications (OV Page, Cards and Analytical list page )
      4. Export built application on my local system (zip file)  and then import application on to on premise HANA thru Hana studio
      5. Application is hosted in HANA but have Fiori launchpad as goto spot for all my xsodata based Fiori applications.

      Can you please confirm that my step 4 is correct ? and it is different from your comment -- " How you deploy it to HANA is probably the real question.  Typically, you deploy an OVP within a Fiori Launchpad"

      Because I struggled a little bit with that - (Pardon my ignorance but ) Initially I deployed my Fiori template based application on Gateway ABAP UI5 repository and was trying to create a service in gateway using xsodata as data feed. But then I learnt that xsodata based application can bypass gateways and we can host xsodata based fiori application on HANA db and just need web dispatcher to host HANA applications thru fiori launchpad .

      Thanks Again -



  • Hi Tanveer,

    Looks like you have it all there though sounds like your Fiori Launchpad might be on too low a version to deploy this on.  e.g. Make sure the target Fiori Launchpad is running something more recent (you would want to leverage Fiori 2.0 Launchpad anyway I would think).


    e.g. OVP should run within the same UI5 container as the Fiori Launchpad, otherwise it won't be nicely integrated.



  • Hi Matt,

    Really interesting post, mostly because you are explaining on a easy way what the official documentation don't.

    Question from my side is, how is determined which information is displayed in the Header KPI for the Card? I really don't get this point. Following your annotation file and using the same approach I can display the Header KPI on a Stacked Column Chart (Analytical Card). Unfortunately, if I try to follow the same approach for a Bar Chart List Card it doesn't work at all.

    Thanks for sharing your findings and knowledge.




    • Sorry about the delay in replying - Jocelyn Dart has made a few posts that help, but trial and error and reading the XML Templates was the "doco" I had to follow.  Plus it changes between releases so good fun!

      Sorry I'm not more help here (been a while since I've done any of this)...