Technical Articles
MyInbox UI generation using CDS views and UI.facet annotation
Intro
Many of you probably may have observed that the MyInbox has an option to generate the UI based on the annotations but the information you may get from the help or online(questions&blogs) is very limited.
So recently there was this question in the community about generating the UI based on the annotations in the MyInbox app. So I started to check the possibility by searching the old questions and blogs..Then I came across this well written blog by Ragini Upadhyay which kick started my understanding the UI generation via annotations.. Then I started to dig the MyInbox app code and the purchase order annotations and was able to create a basic app.
Target
This blog will give you a basic idea of how to generate the UI for MyInbox based on the annotations and is targeted for those how have good understanding of ABAP Programming model for Fiori
We will discuss two things in this blog.
- How to use the UI.Facet annotations in the CDS view
- How to generate the UI using the annotations in the MyInbox
System I used is S4HANA 1809. Not sure if the annotations that I used will work in the older systems.
I’ve taken the Flight data model as I was lazy to create a proper example 😀 and so I am using the same code base which I used for testing.
End Result:
At the end of following all the steps, we will be able to generate the annotation based UI in the MyInbox app as shown above
BTW SAP team designed the annotation based UI very nicely which is based on XML templating. Kudos to the team behind it!! You can check the code in the “annotationsBasedTaskUI” folder of the MyInbox app.
Break down of the annotations used to generate the above UI
I will breakdown the UI into 4 parts
- Header information
- Body -> where we will show the actual data of the root CDS view
- Footer(Associated child entities)-> we will show the associated child data
- Child navigation to Detail page(from the footer/associated child entities)
Header Information:
In the header, to show the title & description, we will use the regular headerInfo annotation,
@UI.headerInfo:{
title.value: 'carrid',
title.url: 'url',
description.value: 'carrname'
}
Body:
For showing the data in the body, I used field groups. Even after using them, the UI will not generate as it requires Facet annotation.
@UI.fieldGroup: [{
// Qualifier is mandatory as this is
// the way to distinguish between
// Multiple groups
qualifier: 'one',
position: 10
}]
@UI.identification: [{position: 10 }]
key scarr.carrid,
@UI.fieldGroup: [{
qualifier: 'two',
position: 10
}]
@UI.identification: [{position: 20 }]
scarr.carrname,
@UI.fieldGroup: [{
qualifier: 'two',
position: 20
}]
So after adding the fieldGroup, we need to add the Facet information to the CDS view.
UI.facet
The example that I referred was purchase order release approval workflow where they generate the Facet releated annotations in the MPC Extension class.
I was lazy and didn’t want to code in the MPC_EXT class 😀 so started searching for the facet annotations in the CDS view level and again very limited information on this topic. (Not sure if it is released for the customer). But anyway ended up spending a lot of time 😀 should have gone with the MPC_EXT based annotations 😀
So after multiple trail & errors I’ve found that it should be added like show below:
@UI.facet: [
// This is for the body
{ // This tells it is a collection of facet
// under that we will have reference facets
id: 'GeneralInformation',
// Summary is mandatory,
// MyInbox generetes the Body based on this
isSummary: true,
type: #COLLECTION
},
// The below two are reference facets
{
// Need to mention the parent Id so the field group
// that is linked to below qualifier will be added to the facet
parentId: 'GeneralInformation',
id:'group1Information',
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'two',
label: 'Group 1'
},
{
parentId: 'GeneralInformation',
id:'group2Information',
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'one',
label: 'Group 2'
}
// Items will be added below, will show later
]
The above code is self explanatory and this information will be general and not specific to myinbox. We can use the Facet annotation to create the facets in the listreport object page as well.
Footer(Associated child entities)
In the above code, I’ve mentioned in the comment at the end that “Items will be added below”, we have to add the items facet annotations there.
{
id:'lineItems',
type: #LINEITEM_REFERENCE,
targetElement: '_Flight',
label: 'Flights'
}
Now one thing I’ve noticed is that the Items should have the Importance as High or else it is not displaying the fields as the table columns. Also, it seems you can display the Form as well in the footer(child)(If you have 1:1 cardinality child)
Child Navigation to Detail Page
If you navigate to detail page from the line Items, you will see a blank page. So to show the information, we need to maintain the similar facet information in the flights CDS view.
@UI.facet: [
// This is for the body
{
id: 'GeneralInformationFlights',
isSummary: true,
type: #COLLECTION
},
{
parentId: 'GeneralInformationFlights',
id:'group1Information',
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'one',
label: 'Item Group 1'
}]
@UI.fieldGroup: [{
// Qualifier is mandatory as this is
// the way to distinguish between
// Multiple groups
qualifier: 'one',
position: 10
}]
key spfli.carrid,
@UI.fieldGroup: [{
qualifier: 'one',
position: 20
}]
@UI.lineItem:{position: 10, importance: #HIGH}
key spfli.connid,
@UI.fieldGroup: [{
qualifier: 'one',
position: 30
}]
@UI.lineItem:{position: 20, importance: #HIGH}
spfli.countryfr,
CDS Views Code
I am pasting all the CDS views code for the reference.
@AbapCatalog.sqlViewName: 'ZVCCARRIER'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Carrier'
@VDM.viewType: #CONSUMPTION
@OData:{
publish: true
}
@UI.headerInfo:{
title.value: 'carrid',
title.url: 'url',
description.value: 'carrname'
}
define view ZC_Carrier
as select from scarr
association [0..*] to ZC_Flight as _Flight on _Flight.carrid = $projection.carrid
{
@UI.facet: [
// This is for the body
{
id: 'GeneralInformation',
isSummary: true,
type: #COLLECTION
},
{
parentId: 'GeneralInformation',
id:'group1Information',
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'two',
label: 'Group 1'
},
{
parentId: 'GeneralInformation',
id:'group2Information',
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'one',
label: 'Group 2'
},
// This is for the Items
{
id:'lineItems',
type: #LINEITEM_REFERENCE,
targetElement: '_Flight',
label: 'Flights'
}]
@UI.fieldGroup: [{
// Qualifier is mandatory as this is
// the way to distinguish between
// Multiple groups
qualifier: 'one',
position: 10
}]
@UI.identification: [{position: 10 }]
key scarr.carrid,
@UI.fieldGroup: [{
qualifier: 'two',
position: 10
}]
@UI.identification: [{position: 20 }]
scarr.carrname,
@UI.fieldGroup: [{
qualifier: 'two',
position: 20
}]
@UI.identification: [{position: 30 }]
@Semantics.currencyCode: true
scarr.currcode,
@UI.identification: [{position: 40 }]
scarr.url,
@ObjectModel.association.type: [#TO_COMPOSITION_CHILD]
_Flight
}
@AbapCatalog.sqlViewName: 'ZVC_FLIGHT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Flights'
@UI.headerInfo:{
typeNamePlural: 'Flights',
typeName: 'Flight'
}
define view ZC_Flight
as select from spfli
association [1..1] to ZC_Carrier as _carrier on _carrier.carrid = $projection.carrid
{
key spfli.carrid,
@UI.lineItem:{position: 10, importance: #HIGH}
key spfli.connid,
@UI.lineItem:{position: 20, importance: #HIGH}
spfli.countryfr,
@UI.lineItem:{position: 30, importance: #HIGH}
spfli.countryto,
@UI.lineItem:{position: 40, importance: #HIGH}
spfli.cityfrom,
@UI.lineItem:{position: 50, importance: #HIGH}
spfli.cityto,
@UI.lineItem:{position: 60, importance: #HIGH}
spfli.distance,
@ObjectModel.association:{ type: [ #TO_COMPOSITION_PARENT, #TO_COMPOSITION_ROOT ] }
_carrier
}
Task Configuration
Now once our CDS view is created it will generate the OData service, which will need to provide in the SWFVISU task.
APPLICATION_PATH | |
COMPONENT_NAME | cross.fnd.fiori.inbox.annotationBasedTaskUI |
QUERY_PARAM00 | service=/sap/opu/odata/sap/ZC_CARRIER_CDS |
QUERY_PARAM01 | entity=/ZC_Carrier(‘{&CARRIER_ID&}’) |
QUERY_PARAM02 | annotations=/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Annotations(TechnicalName=’ZC_CARRIER_CDS_VAN’,Version=’0001′)/$value/ |
SCHEME | Sapui5 |
BTW I created this dummy test workflow and a copied the decision task 😀
Conclusion
So using this approach, we can generate the UI based on annotations for specific tasks without using the custom UI5 application UI integration(Intent based navigation).
The generation of the body & footer(child associations) parts are tightly integrated with the UI.facet annotation. We can also generate them by coding manually in the MPC_EXT class which the standard PO release app is doing.
The UI.facet annotations can be used in the regular list report template apps as well.
One thing I found difficult is that I was not able to show the Number & Currency at the right side of the view in the header section as they are using the UI.dataPoint annotations with some hardcoded “Qualifiers”. I tried to give the qualifier annotation under UI.dataPoint in the CDS view but it seems that option is not available. So I guess this has to be done at the MPC_EXT class only or Maybe someone can help?
I also have not covered all the annotations that will be utilized by the MyInbox app like the links & data field navigation which are working fine.
Please do leave a comment if you think I’ve missed anything in my analysis and your feedback is highly appreciated 🙂
This is a genral information which will be very useful for those who are in the older versions.. (Not specifically related to MYInbox)… By Krishna Kishor Kammaje comment
I had done this sometime back but on a non-HANA lower than 740 NW system. So went for a regular OData service (not CDS based). I created all my annotations in an XML file, uploaded it as a BSP project in GW system so that I have a URL to access the annotation file (to mention in the SWFIVISU). Another use case to do this way is in a case where you already have an OData service and you just want to reuse it for My-Inbox with annotations.
Thanks & Regards,
Mahesh
Super blog your this blog and the one referred enhanced my understanding of the structure thanks. Annotations are being used in the big way whether it is ABAP Programming model for Fiori or CAPM.
Thanks for the feedback Nabheet Madan !! CDS and annotations are sure playing a major role.. in the UI5 it's the XML templating, which is used to generate the UI dynamically.. I think i will start digging that topic and maybe will write a blog as well 🙂
yes that will be great!
Hey Mahesh
Excellent blog!! Thanks for sharing knowledge on UI facets...really helps!!!
Thanks,
Ragini
Thanks Ragini!!
Excellent Blog...!!! I very much liked the way you presented it too...
Thanks Pawan 🙂
Great blog Mahesh. This will be a very good reference. Wanted to share my experience here quick.
I had done this sometime back but on a non-HANA lower than 740 NW system. So went for a regular OData service (not CDS based). I created all my annotations in an XML file, uploaded it as a BSP project in GW system so that I have a URL to access the annotation file (to mention in the SWFIVISU). Another use case to do this way is in a case where you already have an OData service and you just want to reuse it for My-Inbox with annotations.
Thanks Krishna Kishor Kammaje
I never thought of this approach, cool way to do this 🙂 I will include your comment in the blog 🙂
BTW any reason why you have not extended the MPC_EXT class to provide the metadata annotations? (The only reason I think of is the vocabulary annotations are not available, please correct me if I am wrong)
BR,
Mahesh
That's right. Annotations which you can add using MPC_EXT are limited.
Hi Mahesh
I read your blog, and I found it very informative but confusing, I still have many doubts, for example, how do I start an annotation or how do I configure it and which directly affects my inbox, in the view I need?
Also, does the fact that some things take them without much explanation cause me conflict, I do not know if it would be possible some indication or some brief explanation of how it was that it was possible to reach that?
I hope not to cause a lot of hassle, since in this of the extensions of standard apps on Fiori, I am a novice, reason why I am very lost.
Regards
Edson.
Hi Edson Bravo Zapata
Actually this blog is aimed for the people who have a good understanding of the ABAP Programming model for Fiori. I am not giving much information on facets and all as it is a common term for those who has already created the List report template based apps(As already mentioned in the blog).
I would strongly recommend you to go through all the blogs about the CDS View annotations, Fiori Elements, List report template based apps etc.., then it will be very easy for you to understand this.
https://blogs.sap.com/2017/04/21/how-to-add-annotations-to-an-odata-service-using-code-based-implementation/
https://wiki.scn.sap.com/wiki/display/Fiori/Fiori+elements
Many blogs are there just a search away.. If you get any questions you can always create a question in the community 🙂
BR,
Mahesh
Hi Mahesh
As I said, I'm new to extending Fiori's applications, so I did not know where to start looking or what to look for to start extending.
Thanks for your response, now I have a hint how to start.
Regards
Edson.
Hi Mahesh,
Nice blog…! Thanks for sharing.
I have gone through the blog and took the reference of @UI.facet, But I am not getting correct output(In landing page getting the label for table column, but when navigating to Object page that time not getting label which I have written in @Ui.identification.
I have attached the CDS view code ,metadata extension file and output screen.
Please could you check if I am missing anything.
Thanks in advance.
Thanks & Regards,
Dhiraj
You are welcome 🙂
It is not picking from the identification as you are showing the UI using the field group and so the label should be maintained in the field group else it will pick from the table field.
BR,
Mahesh
Thanks! Its working.
I want to hide the facet based on user name. I have added the hiden: #(Enable) in facet.
{
label: 'Skills Details',
id : 'EMPSKILL',
type : #LINEITEM_REFERENCE,
targetElement: '_skillInfo',
//hidden: true
hidden: #(EMPSKILLFacetIsHidden)
}
Please could you suggest how to control the facet.
Regards,
Dhiraj
Hi Dhiraj Kumar Barnwal
Sorry.. I've never tried this scenario.. You can create a question for this in the community, surely someone might help you.. Meanwhile If i get time, I will try this out.
BR,
Mahesh
Hey Mahesh,
Excellent blog!! Very well portrayed and is really useful!!
Regards,
Shiva Shankar
? Thanks for the feedback Shiva!!
Hi Mahesh,
I`m trying to create a transactional app with a header with 2 children (one item table and one text table) only by using annotations like: (@ObjectModel.association.type: [#TO_COMPOSITION_CHILD] / [#TO_COMPOSITION_PARENT, #TO_COMPOSITION_ROOT]) and @UI.facet options.
After creating the project in WebIDE and choosing my consumption view + to_item navigation I get the following behavior:
The item (Handle Part Type) has the navigation to the detail screen + the insert functionality but my Text table, so the second child, doesn`t have it. By any chance do you know if this is a normal behavior? Did I miss some annotations in order to enable this insert and navigation for my Text Table?
Thanks in advance!
Alex
can you check if your interface view(BO view) for the texts entity has the create enabled annotation defined? Also check in the BOPF BO for that entity if the create enabled check box is checked.
Hi Mahesh,
My text interface view has the createEnable set to true.
Also my BOPF -> Text entity has the create enabled.
Also I`ve checked and generate my bopf and deleted and re-created my fiori app using the same OData.
In one testing scenario I`ve created the project in WebIDE with OData collection YFIORI_FB_C_300 and OData Navigation: to_Htext (my text table). In result I got my navigation from header to item -> text table working fine, also with insert functionality but my other child C_310 was missing the "insert" functionality. That is why I`ve thought I miss some annotation to activate the third facet... Or maybe is not possible?
Thanks
Alex
This looks weird, as far as i know it should display the create button without any additional annotations to be passed.. just for testing, can you remove the 2 navigation and only use the c_310 navigation only and see if it's working or not(i know it is dumb 😀 but let's try that)
Hi Mahesh,
Yes, I agree, it looks weird. 🙂
I have tried the following:
I`m pretty confused .. :))
Regards
Alex
Is it due to the facets being from MDE?
I`ve managed to make it work!! 🙂
From what I`ve learned is that when creating the project in WebIDE and selecting the OData with its navigation, example to_Item, then this will generate coding only for that particular navigation.
In my case I have 2 children: to_Item and to_HText and only to_Item navigation was enabled.
What I`ve did to enable the to_HText navigation and CRUD operations, beside the coding related to UI.facet from MDE file:
As result:
Thanks for your replies Mahesh!
Alex
Awesome Alex Caruntu
I don't know why it din't cross my mind.. Actually for enabling the navigation to the sub page we need that config in manifest.json and yeah if you try to add an item, it will obviously needs to go to the second page(so that config is mandatory).
Br,
Mahesh
Hello Mahesh and Alex,
I have the same issue , my third facet creation button is not displaying , everything else is working fine , I did all changes that ALEX mentioned but still not displaying ,
I edited manifest.json and annotation file.
First change was not clear for me what do you mean by this
enable the to_HText navigation and CRUD operations, beside the coding related to UI.facet from MDE file
Where i can find this MDE file, how to edit this ?
can you please help me on this i am new to this UI world
Thank you so much
Hello Alex, could you solve ??, I also have the same problem.
Hello Mahesh,
First of all, thank you for this great blog.
We have implemented My Inbox 2.0 on Hana 1610 SP06 and Approve Purchase Order and Approve Requisition works fine. But we want to add a custom field to both approving detail views. I read Ragini blog but my mind confuse. Which approach is the best practice for extending standard annotation? Could you share best practice tutorial or any official document about the modifying or extending of standard annotation file, especially adding new field? thanks
Hi Mehmet Ozkafa,
Hello Mahesh,
Thanks for this blog post. Actually, I'm new to ABAP programming model. I created a consumption view and consume it in Web IDE using list report template.
Everything is fine but I had a problem displaying the facets.
I defined the required annotations in the same way as you. Everything looks fine and right, but I don't get any section displayed on the Object page even the section title:
Here is my code:
....
@UI.facet: [
{
label: ‘General Information’,
id:’GeneralInformation’,
isSummary: true,
type: #COLLECTION,
position: 10
},
{
label: ‘Customer Info’,
id: ‘CustomerInfo’,
parentId: ‘GeneralInformation’,
type: #FIELDGROUP_REFERENCE,
position: 20,
targetQualifier: ‘Company’
}
]
key Item.SalesOrder,
key Item.SalesOrderItem as ItemPosition,
@UI.fieldGroup: [{
qualifier: ‘Company’,
position: 10
}]
@UI.selectionField.position: 20
@Search: {defaultSearchElement: true, fuzzinessThreshold: 0.7}
@UI.lineItem.position: 20
Item._SalesOrder._Customer.CompanyName as CompanyName,
.....
Do you think, this code should be enough to display a section or I missed something.
I checked different blog posts, and in all of them, we just need like the above definition. in my app, I don't see anything displayed even the title of the section.
Thanks for your help,
Ayham
I attached a picture of the updated code.
@UI.identification and @UI.fieldGroup are defined also in the code:
@UI.identification.position: 10
Item._Supplier.Country,
@UI.identification.position: 20
Item._Supplier.CityName,
@UI.fieldGroup: { qualifier: ‘Product’, position: 10}
Item.Supplier,
@UI.fieldGroup: { qualifier: ‘Product’, position: 20}
Item.ProductType,
@UI.fieldGroup: { qualifier: ‘Product’, position: 30}
Item.ProductCategory,
Maybe when you generated the List report template app, it will auto generate the facet annotations, try removing them in the fiori app and see once/
Hello Mahesh,
Thanks very much. It works perfectly.
The Web IDE generates default facets which overwrite my UI.facet.
Again Thanks very much for your help and your great Blog Post
Thanks Ayham 🙂
Thanks a lot for sharing this Mahesh,
Really useful. Saved a lot of time.
Regards,
Sarbjeet Singh
Thanks Sarbjeet for the feedback!!..
Hi,
Thank you for the nice blog.
I want to ask for the annotation, how do you get the name the annotation name ZC_CARRIER_CDS_VAN to be maintained in SWFVISU QUERY_PARAM01?
Thank you
Hi Suwandi Cahyadi, really appreciate the feedback.. Thank you so much 🙂
THe annotation service name can be found in the /n/Iwfnd/mant_service.. for there you can navigate to annotation service by clicking some button with will take you to DPC classes and stuff,, from there a button at the bottom i think.. Don;t remember exacly..
BR,
Mahesh
Awesome post Mahesh.
🙂 Thanks for the feedback Sreehari V Pillai
Hi Mahesh,
Did you try adding a new tab using annotations?
Thanks & BR, P
Sorry, just saw ur comment. I don't think we can add a new tab, and it's been sometime since I checked it, so no idea if it is possible now. 🙁 But you can always add a new section, kinda looks like a tab.
Mahesh Palavalli great blog. I have a question, from where the CARRIER_ID in entity=/ZC_Carrier(‘{&CARRIER_ID&}’) came from? because in your cds this is not the field name.
Thanks 🙂
That variable is part of SAP Workflow container