-
Notifications
You must be signed in to change notification settings - Fork 1
03. Extending the model
We already created a CDS
file to carry the extension in the previous exercise. We will make this a usable extension now.
Please expand ths file to look like this:
using {sap.capire.incidents as my} from '@capire/incidents';
extend my.Customers with {
status : String(8) @title: 'Customer Status' default 'Silver';
};
extend service ProcessorService with {
@cds.redirection.target: false
entity CustomersProjection as
projection on my.Customers {
@readonly ID,
@readonly name,
status
};
}
extend ProcessorService.Incidents with columns {
@readonly customer.status as CustomerStatus
};
What are we doing here?
The Customers
entity has an additional attribute for a Customer Status
. Since the ProcessorService only as an autoexposed
entity Customers available (which is always read-only), we need to provide an additional, write-enabled entity, if we want to promote a customer in status. Since we want to expose the absolute minimum surface for writing, we use the @readonly
annotations, and only enable the status
attribute for writing.
Since we already have auto-exposed the entity Customers
, we must make sure that the redirection-target for the Customers
association in Incidents
is clear. We use @cds.redirection.target: false
for this.
We also extend the projection of the Incidents
entity to flatten the customer status into the attribute list.
In a typical use case, Application Developers would provide useful test data and other things via an extension project template.
We can shortcut this by copying the db/data
folder from our incidents application to the test/data
folder in our extension project.
Note
Initial data is handled automatically by CAP, if there are .csv
files present in the db/data
folder. In an extension project, this means that such files are also pushed with the extension, potentially overwriting data deployed to the productive tenant. In order to have useful initial test data, which is not pushed with the extension, simply put these files in the test
data` folder instead
In order to see the new attribute on the UI, we need to add some Fiori Elements annotations to our extension file:
annotate ProcessorService.Incidents with @(UI : {
LineItem : [
...,
{
Value : urgency.descr,
Criticality : (urgency.code = 'H' ? 1 : (urgency.code = 'M' ? 2 : 0)),
Label : 'Urgency',
@UI.Importance: #High
},
{
Value : CustomerStatus,
Label : 'Customer Status',
![@UI.Importance]: #High
},
{
$Type : 'UI.DataFieldForAction',
Action: 'ProcessorService.promoteCustomer(ProcessorService.Incidents)',
Label : 'promote Customer',
},
{
$Type : 'UI.DataFieldForAction',
Action: 'ProcessorService.promoteIncident',
Label : 'promote Incident',
},
],
FieldGroup #GeneratedGroup1: {Data: [..., {Value: CustomerStatus}]}
});
What are we doing here?
In the Incidents List view, the Customer Status needs to be added vial the LineItem
section. You can observe the delta annotations used to extend array values conveniently.
We are also adding a color coding to urgency
via Criticality
and leverage the fairly new support for expressions in annotations . The Customer Status is also added to the object page using FieldGroup
.
Instead of constantly pushing the extension to the MTX Sidecar, you can also start the extension project locally using cds watch
or cds run
command. You can immediately see the result of your changes, and control whether your UI changes look like expected. Once you are happy with your changes, you can push the extension to the actual application.
Note
A SaaS application usually already has soa fair amount of business logic deployed. Even though you pulled the base model from the application, the extension project does not get the source code of the application. If there is logic, which alters data or changes the flow of the UI (e.g. actions and events emitted in the background) these will not be observable in the local test of an extension. In such cases, the application developer either provides some stubs in the extension project template to emulate the deployed business logic, or extension developers test against a test tenant provided.
It is a good idea to shut down the base application and sidecar while testing locally to avoid the extension project competing against port 4004.
We want two buttons on our list page - one to promote a customer to Gold
, and one to promote selected incidents to high
. This is achieved with this snippet:
extend ProcessorService.Incidents with actions {
@(Common.SideEffects: {TargetEntities: ['/ProcessorService.EntityContainer/Incidents']}, )
action promoteIncident();
@(Common.SideEffects: {TargetEntities: ['/ProcessorService.EntityContainer/Incidents']
// TargetProperties: [in.CustomerStatus, in.urgency_code, in.urgency.descr],
})
action promoteCustomer(in : many $self,
@(
title: 'promote Customer to Gold',
Common: {
ValueListWithFixedValues: true,
ValueList : {
CollectionPath: 'CustomersProjection',
Parameters : [
{
$Type : 'Common.ValueListParameterInOut',
ValueListProperty: 'ID',
LocalDataProperty: Customer_ID
},
{
$Type : 'Common.ValueListParameterDisplayOnly',
ValueListProperty: 'name'
}
]
}
}
)
Customer_ID : String);
};
What are we doing here?
The actions are both bound to ProcessorService.Incidents
from a CDS perspective, but for Fiori Elements, promoteIncident
is entity bound
while promoteCustomer
is collection bound
, and requires a more complex annotation to achieve a value list for customer selection.
If you test the UI, you will observe two buttons:
-
promote Customer
should bring up a selection dialog -
promote Incident
should be disabled and only become active once you select one or more incidents from the list.
In the Fourth exercise — Creating the extension, we will bring these buttons to life.