Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added advanced/assets/hierarchical-tree-view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
87 changes: 55 additions & 32 deletions advanced/fiori.md
Original file line number Diff line number Diff line change
Expand Up @@ -745,9 +745,9 @@ Cache Control feature is currently supported on the Java runtime only.

## Hierarchical Tree Views

Recursive hierarchies are parent-child hierarchies, where each entity references its parent and through that defines the hierarchical structure. A common example is a company organization structure or HR reporting, where each employee entity references another employee as a direct report or manager.
Recursive hierarchies are parent-child related structures: each entity references its parent and through that defines the hierarchical structure. A common example is a company organization structure or HR reporting, where each employee entity references another employee as a direct report or manager.

A generic hierarchy implementation for hierarchies is available on all relational datases supported by the CAP runtimes.
A generic hierarchy implementation for hierarchies is available on all relational databases supported by the CAP runtimes.

::: warning
On H2, only small hierarchies should be used for performance reasons.
Expand All @@ -761,6 +761,7 @@ Let's assume we have the following domain model and its projection in a service:
namespace my.bookshop;

entity Genres { //...
ID : UUID;
parent : Association to Genres;
}
```
Expand All @@ -774,19 +775,67 @@ service AdminService {
```
:::

In this example, there is a managed to-one association `parent` that defines the parent-child hierarchy
based on a single key element. In such a situation you can define the Tree View via the annotation `@hierarchy`:

Annotate/extend the entity in the service as follows:
```cds
annotate AdminService.Genres with @hierarchy : parent;
```

If the entity contains only one such association, you can even omit the value:

```cds
annotate AdminService.Genres with @hierarchy;
```

Configure the TreeTable in UI5's _manifest.json_ file:

```jsonc
"sap.ui5": { ...
"routing": { ...
"targets": { ...
"GenresList": { ...
"options": {
"settings": { ...
"controlConfiguration": {
"@com.sap.vocabularies.UI.v1.LineItem": {
"tableSettings": {
"hierarchyQualifier": "GenresHierarchy", // [!code focus]
"type": "TreeTable" // [!code focus]
}
}
}
}
}
},
},
},
```

> Note: construct the `hierarchyQualifier` with the following pattern: <br>
> `<entity name in service>Hierarchy`

You can now start the server with `cds watch` and see the hierarchical tree view in action in the [_Browse Genres_](http://localhost:4004/fiori-apps.html#Genres-display) app.

![Fiori UI with hierarchical tree view.](assets/hierarchical-tree-view.png) {style="filter: drop-shadow(0 2px 5px rgba(0,0,0,.40));"}

The compiler automatically expands the shortcut annotation `@hierarchy` to the
following `annotate` and `extend` statements.

### Manual Approach

The following documents what happens behind the scenes, done by the compiler as described before. You can also use it, if you cannot use the `@hierarchy` annotation, for example, because you only have an unmanaged parent association.

```cds
// declare a hierarchy with the qualifier "GenresHierarchy"
annotate AdminService.Genres with @Aggregation.RecursiveHierarchy #GenresHierarchy : {
annotate AdminService.Genres with @Aggregation.RecursiveHierarchy #GenresHierarchy: {
NodeProperty : ID, // identifies a node, usually the key
ParentNavigationProperty : parent // navigates to a node's parent
};

extend AdminService.Genres with @(
// The computed properties expected by Fiori to be present in hierarchy entities
Hierarchy.RecursiveHierarchy #GenresHierarchy : {
Hierarchy.RecursiveHierarchy #GenresHierarchy: {
LimitedDescendantCount : LimitedDescendantCount,
DistanceFromRoot : DistanceFromRoot,
DrillState : DrillState,
Expand All @@ -797,7 +846,7 @@ extend AdminService.Genres with @(
'LimitedDescendantCount', 'DistanceFromRoot', 'DrillState', 'LimitedRank'
],
// Disallow sorting on these properties from Fiori UIs
Capabilities.SortRestrictions.NonSortableProperties : [
Capabilities.SortRestrictions.NonSortableProperties: [
'LimitedDescendantCount', 'DistanceFromRoot', 'DrillState', 'LimitedRank'
],
) columns { // Ensure we can query these columns from the database
Expand All @@ -811,31 +860,5 @@ extend AdminService.Genres with @(
> Note: When naming the hierarchy qualifier, use the following pattern: <br>
> `<entity name in service>Hierarchy`

Configure the TreeTable in UI5's _manifest.json_ file:

```jsonc
"sap.ui5": { ...
"routing": { ...
"targets": { ...
"GenresList": { ...
"options": {
"settings": { ...
"controlConfiguration": {
"@com.sap.vocabularies.UI.v1.LineItem": {
"tableSettings": {
"hierarchyQualifier": "GenresHierarchy", // [!code focus]
"type": "TreeTable" // [!code focus]
}
}
}
}
}
},
},
},
```

> Note: use the `hierarchyQualifier` declared earlier

<div id="reserved-words" />