Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.
Open
64 changes: 64 additions & 0 deletions bookshop/db/data/sap.capire.bookshop-Contents.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
ID;parent_ID;name;page;book_ID
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not pollute our central getting-started sample, but move that to the fiori / bookstore project.

f846b0b9-01d4-4f6d-82a4-d79204f62514;;Foreword;3;207
f846b0b9-01d4-4f6d-82a4-d79204f62515;;Chapter 1;4;207
f846b0b9-01d4-4f6d-82a4-d79204f62516;f846b0b9-01d4-4f6d-82a4-d79204f62515;Section 1.1;5;207
f846b0b9-01d4-4f6d-82a4-d79204f62517;f846b0b9-01d4-4f6d-82a4-d79204f62515;Section 1.2;28;207
f846b0b9-01d4-4f6d-82a4-d79204f62518;f846b0b9-01d4-4f6d-82a4-d79204f62517;Subsection 1.2.1;30;207
f846b0b9-01d4-4f6d-82a4-d79204f62519;f846b0b9-01d4-4f6d-82a4-d79204f62517;Subsection 1.2.2;33;207
f846b0b9-01d4-4f6d-82a4-d79204f62520;f846b0b9-01d4-4f6d-82a4-d79204f62515;Section 1.3;36;207
f846b0b9-01d4-4f6d-82a4-d79204f62521;;Chapter 2;54;207
f846b0b9-01d4-4f6d-82a4-d79204f62522;f846b0b9-01d4-4f6d-82a4-d79204f62521;Section 2.1;56;207
f846b0b9-01d4-4f6d-82a4-d79204f62523;f846b0b9-01d4-4f6d-82a4-d79204f62521;Section 2.2;58;207
f846b0b9-01d4-4f6d-82a4-d79204f62524;;Conclusion;63;207
f846b0b9-01d4-4f6d-82a4-d79204f62525;;Endnotes;65;207
f846b0b9-01d4-4f6d-82a4-d79204f62526;;Copyright notice;2;251
f846b0b9-01d4-4f6d-82a4-d79204f62527;;Chapter 1;3;251
f846b0b9-01d4-4f6d-82a4-d79204f62528;f846b0b9-01d4-4f6d-82a4-d79204f62527;Section 1.1;5;251
f846b0b9-01d4-4f6d-82a4-d79204f62529;f846b0b9-01d4-4f6d-82a4-d79204f62527;Section 1.2;13;251
f846b0b9-01d4-4f6d-82a4-d79204f62530;;Chapter 2;20;251
f846b0b9-01d4-4f6d-82a4-d79204f62531;f846b0b9-01d4-4f6d-82a4-d79204f62530;Section 2.1;21;251
f846b0b9-01d4-4f6d-82a4-d79204f62532;f846b0b9-01d4-4f6d-82a4-d79204f62530;Section 2.2;25;251
f846b0b9-01d4-4f6d-82a4-d79204f62533;f846b0b9-01d4-4f6d-82a4-d79204f62530;Section 2.3;27;251
f846b0b9-01d4-4f6d-82a4-d79204f62534;;Chapter 3;30;251
f846b0b9-01d4-4f6d-82a4-d79204f62535;;Endnotes;41;251
f846b0b9-01d4-4f6d-82a4-d79204f62551;;Acknowledgements;1;271
f846b0b9-01d4-4f6d-82a4-d79204f62552;;The Flight;2;271
f846b0b9-01d4-4f6d-82a4-d79204f62553;;Hexwood Farm;8;271
f846b0b9-01d4-4f6d-82a4-d79204f62554;f846b0b9-01d4-4f6d-82a4-d79204f62553;Castle Saburac;13;271
f846b0b9-01d4-4f6d-82a4-d79204f62555;f846b0b9-01d4-4f6d-82a4-d79204f62553;The Curse of Rapkyn;27;271
f846b0b9-01d4-4f6d-82a4-d79204f62556;f846b0b9-01d4-4f6d-82a4-d79204f62553;The Mannikin;35;271
f846b0b9-01d4-4f6d-82a4-d79204f62557;;The Eye of Time;44;271
f846b0b9-01d4-4f6d-82a4-d79204f62558;;The Enchanting;59;271
f846b0b9-01d4-4f6d-82a4-d79204f62559;f846b0b9-01d4-4f6d-82a4-d79204f62558;The Telling Bone;73;271
f846b0b9-01d4-4f6d-82a4-d79204f62560;f846b0b9-01d4-4f6d-82a4-d79204f62558;The Power of Adamcos;86;271
f846b0b9-01d4-4f6d-82a4-d79204f62561;f846b0b9-01d4-4f6d-82a4-d79204f62558;The House of the Sorcerer;98;271
f846b0b9-01d4-4f6d-82a4-d79204f62562;;The Changeling;105;271
f846b0b9-01d4-4f6d-82a4-d79204f62563;f846b0b9-01d4-4f6d-82a4-d79204f62562;The Flying Broomsticks;118;271
f846b0b9-01d4-4f6d-82a4-d79204f62564;f846b0b9-01d4-4f6d-82a4-d79204f62563;The Fish Out of Water;126;271
f846b0b9-01d4-4f6d-82a4-d79204f62565;;The Final Magic;138;271
f846b0b9-01d4-4f6d-82a4-d79204f62566;;Copyright;159;271
f846b0b9-01d4-4f6d-82a4-d79204f62567;;Editor's Note;1;201
f846b0b9-01d4-4f6d-82a4-d79204f62568;;Chapter I;2;201
f846b0b9-01d4-4f6d-82a4-d79204f62569;;Chapter II;31;201
f846b0b9-01d4-4f6d-82a4-d79204f62570;f846b0b9-01d4-4f6d-82a4-d79204f62569;Section II.I;47;201
f846b0b9-01d4-4f6d-82a4-d79204f62571;f846b0b9-01d4-4f6d-82a4-d79204f62569;Section II.II;62;201
f846b0b9-01d4-4f6d-82a4-d79204f62572;f846b0b9-01d4-4f6d-82a4-d79204f62569;Section II.III;75;201
f846b0b9-01d4-4f6d-82a4-d79204f62573;f846b0b9-01d4-4f6d-82a4-d79204f62569;Section II.IV;87;201
f846b0b9-01d4-4f6d-82a4-d79204f62574;;Chapter III;105;201
f846b0b9-01d4-4f6d-82a4-d79204f62575;f846b0b9-01d4-4f6d-82a4-d79204f62574;Section III.I;128;201
f846b0b9-01d4-4f6d-82a4-d79204f62576;f846b0b9-01d4-4f6d-82a4-d79204f62575;Subsection III.I.I;156;201
f846b0b9-01d4-4f6d-82a4-d79204f62577;f846b0b9-01d4-4f6d-82a4-d79204f62575;Subsection III.I.II;173;201
f846b0b9-01d4-4f6d-82a4-d79204f62578;f846b0b9-01d4-4f6d-82a4-d79204f62574;Section III.II;185;201
f846b0b9-01d4-4f6d-82a4-d79204f62579;;Chapter IV;203;201
f846b0b9-01d4-4f6d-82a4-d79204f62580;;Acknowledgments;250;201
f846b0b9-01d4-4f6d-82a4-d79204f62582;;Foreword;1;252
f846b0b9-01d4-4f6d-82a4-d79204f62583;;Chapter 1;3;252
f846b0b9-01d4-4f6d-82a4-d79204f62584;f846b0b9-01d4-4f6d-82a4-d79204f62583;Section 1.1;5;252
f846b0b9-01d4-4f6d-82a4-d79204f62585;f846b0b9-01d4-4f6d-82a4-d79204f62583;Section 1.2;8;252
f846b0b9-01d4-4f6d-82a4-d79204f62586;;Chapter 2;10;252
f846b0b9-01d4-4f6d-82a4-d79204f62587;f846b0b9-01d4-4f6d-82a4-d79204f62586;Section 2.1;12;252
f846b0b9-01d4-4f6d-82a4-d79204f62588;f846b0b9-01d4-4f6d-82a4-d79204f62587;Subsection 2.1.1;14;252
f846b0b9-01d4-4f6d-82a4-d79204f62589;f846b0b9-01d4-4f6d-82a4-d79204f62587;Subsection 2.1.2;16;252
f846b0b9-01d4-4f6d-82a4-d79204f62590;f846b0b9-01d4-4f6d-82a4-d79204f62586;Section 2.2;18;252
f846b0b9-01d4-4f6d-82a4-d79204f62591;f846b0b9-01d4-4f6d-82a4-d79204f62590;Subsection 2.2.1;21;252
f846b0b9-01d4-4f6d-82a4-d79204f62592;;Endnotes;25;252
11 changes: 11 additions & 0 deletions bookshop/db/schema.cds
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ entity Books : managed {
price : Price;
currency : Currency;
image : LargeBinary @Core.MediaType: 'image/png';
contents : Composition of many Contents on contents.book = $self;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not pollute our central getting-started sample, but move that to the fiori / bookstore project.

}

entity Authors : managed {
Expand All @@ -30,6 +31,16 @@ entity Genres : sap.common.CodeList {
children : Composition of many Genres on children.parent = $self;
}

/** Hierarchically organized entity for Contents */
entity Contents {
key ID : UUID;
name : String;
page : Integer;
parent : Association to Contents;
children : Composition of many Contents on children.parent = $self;
book : Association to Books;
}

Comment on lines +34 to +43
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not pollute our central getting-started sample, but move that to the fiori / bookstore project.

type Price : Decimal(9,2);


Expand Down
1 change: 1 addition & 0 deletions bookshop/srv/admin-service.cds
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ service AdminService @(path:'/admin') {
entity Authors as projection on my.Authors;
entity Books as projection on my.Books;
entity Genres as projection on my.Genres;
entity Contents as projection on my.Contents;
Comment on lines 4 to +6
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to expose that explicitly?
Composition targets are auto-exposed, as part of their roots. Only root entities should be exposed explicitly.

}
6 changes: 3 additions & 3 deletions bookshop/srv/cat-service.cds
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ service CatalogService @(path:'/browse') {

/** For displaying lists of Books */
@readonly entity ListOfBooks as projection on Books
excluding { descr };
excluding { descr, contents };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert when we move Contents to bookstore


/** For display in details pages */
@readonly entity Books as projection on my.Books { *,
author.name as author
} excluding { createdBy, modifiedBy };
} excluding { createdBy, modifiedBy, contents };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert when we move Contents to bookstore


@requires: 'authenticated-user'
action submitOrder ( book: Books:ID, quantity: Integer ) returns { stock: Integer };
event OrderedBook : { book: Books:ID; quantity: Integer; buyer: String };
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep empty lines at the end of files

15 changes: 11 additions & 4 deletions fiori/app/admin-books/fiori-service.cds
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using { AdminService } from '@capire/bookstore';
using from '../common'; // to help UI linter get the complete annotations

annotate sap.capire.bookshop.Genres with @fiori.draft.enabled;
annotate AdminService.Genres with @odata.draft.enabled;
annotate AdminService.Genres with @odata.draft.bypass;
Comment on lines +4 to +6
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need that here, in admin-books, at all?
And why all three?



////////////////////////////////////////////////////////////////////////////
Expand All @@ -11,10 +14,11 @@ using from '../common'; // to help UI linter get the complete annotations
annotate AdminService.Books with @(
UI: {
Facets: [
{$Type: 'UI.ReferenceFacet', Label: '{i18n>General}', Target: '@UI.FieldGroup#General'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Translations}', Target: 'texts/@UI.LineItem'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Details'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Admin}', Target: '@UI.FieldGroup#Admin'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>General}', Target: '@UI.FieldGroup#General'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Translations}', Target: 'texts/@UI.LineItem'},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please stick to consistent 2-spaces indent in samples

{$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Details'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Admin}', Target: '@UI.FieldGroup#Admin'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Contents}', Target: 'contents/@UI.PresentationVariant'}
],
FieldGroup#General: {
Data: [
Expand Down Expand Up @@ -71,6 +75,7 @@ annotate AdminService.Genres with {
ID @UI.Hidden;
};


////////////////////////////////////////////////////////////
//
// Draft for Localized Data
Expand Down Expand Up @@ -110,3 +115,5 @@ extend service AdminService {

// Workaround for Fiori popup for asking user to enter a new UUID on Create
annotate AdminService.Books with { ID @Core.Computed; }

using from './tree-view';
42 changes: 42 additions & 0 deletions fiori/app/admin-books/tree-view.cds
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using { AdminService } from '@capire/bookstore';

////////////////////////////////////////////////////////////////////////////
//
// Contents Tree Table Annotations
//

// Tell Fiori about the structure of the hierarchy
annotate AdminService.Contents with @Aggregation.RecursiveHierarchy #ContentsHierarchy : {
ParentNavigationProperty : parent, // navigates to a node's parent
NodeProperty : ID, // identifies a node, usually the key
};

// Fiori expects the following to be defined explicitly, even though they're always the same
extend AdminService.Contents with @(
// The columns expected by Fiori to be present in hierarchy entities
Hierarchy.RecursiveHierarchy #ContentsHierarchy : {
LimitedDescendantCount : LimitedDescendantCount,
DistanceFromRoot : DistanceFromRoot,
DrillState : DrillState,
LimitedRank : LimitedRank
},
// Disallow filtering on these properties from Fiori UIs
Capabilities.FilterRestrictions.NonFilterableProperties: [
'LimitedDescendantCount',
'DistanceFromRoot',
'DrillState',
'LimitedRank'
],
// Disallow sorting on these properties from Fiori UIs
Capabilities.SortRestrictions.NonSortableProperties : [
'LimitedDescendantCount',
'DistanceFromRoot',
'DrillState',
'LimitedRank'
],
) columns { // Ensure we can query these fields from database
null as LimitedDescendantCount : Int16,
null as DistanceFromRoot : Int16,
null as DrillState : String,
null as LimitedRank : Int16,
};
28 changes: 28 additions & 0 deletions fiori/app/admin-books/webapp/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@
"pattern": "Books({key}/author({key2}):?query:",
"name": "AuthorsDetails",
"target": "AuthorsDetails"
},
{
"pattern": "Books({key})/contents({key2}):?query:",
"name": "ContentsDetails",
"target": "ContentsDetails"
}
],
"targets": {
Expand Down Expand Up @@ -112,11 +117,34 @@
"detail" : {
"route" : "AuthorsDetails"
}
},
"contents": {
"detail": {
"route": "ContentsDetails"
}
}
},
"controlConfiguration": {
"contents/@com.sap.vocabularies.UI.v1.LineItem": {
"tableSettings": {
"hierarchyQualifier": "ContentsHierarchy",
"type": "TreeTable"
}
}
}
}
}
},
"ContentsDetails": {
"type": "Component",
"id": "ContentsDetails",
"name": "sap.fe.templates.ObjectPage",
"options": {
"settings": {
"contextPath": "/Books/contents"
}
}
},
"AuthorsDetails": {
"type": "Component",
"id": "AuthorsDetailsList",
Expand Down
22 changes: 11 additions & 11 deletions fiori/app/appconfig/fioriSandboxConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,6 @@
"title": "Browse Books",
"targetURL": "#Books-display"
}
},
{
"id": "BrowseGenres",
"tileType": "sap.ushell.ui.tile.StaticTile",
"properties": {
"title": "Browse Genres",
"targetURL": "#Genres-display"
}
}
]
},
Expand All @@ -43,6 +35,14 @@
"title": "Manage Books",
"targetURL": "#Books-manage"
}
},
{
"id": "ManageGenres",
"tileType": "sap.ushell.ui.tile.StaticTile",
"properties": {
"title": "Manage Genres",
"targetURL": "#Genres-manage"
}
},
{
"id": "ManageAuthors",
Expand Down Expand Up @@ -114,10 +114,10 @@
"url": "/admin-authors/webapp"
}
},
"BrowseGenres": {
"ManageGenres": {
"semanticObject": "Genres",
"action": "display",
"title": "Browse Genres",
"action": "manage",
"title": "Manage Genres",
"signature": {
"parameters": {
"Genre.ID": {
Expand Down
48 changes: 48 additions & 0 deletions fiori/app/common.cds
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,54 @@ annotate my.Books with {
image @title: '{i18n>Image}';
}

annotate my.Contents with @(
cds.search: {name}
);

////////////////////////////////////////////////////////////////////////////
//
// Contents List
//
annotate my.Contents with @UI: {
PresentationVariant : {
$Type : 'UI.PresentationVariantType',
RequestAtLeast: [name],
Visualizations: ['@UI.LineItem'],
},
LineItem : [{
$Type: 'UI.DataField',
Value: name,
Label : '{i18n>Name}'
},
{
$Type: 'UI.DataField',
Value: page,
Label : '{i18n>Page}'
}],
HeaderInfo : {
$Type : 'UI.HeaderInfoType',
TypeName : '{i18n>ContentsLevel}',
TypeNamePlural: '{i18n>ContentsLevels}',
Title : {
$Type: 'UI.DataField',
Value: name,
}
},
FieldGroup : {
$Type: 'UI.FieldGroupType',
Data : [{
$Type: 'UI.DataField',
Value: page,
Label : '{i18n>PageNumber}'
}],
},
Facets : [{
$Type : 'UI.ReferenceFacet',
Target: '@UI.FieldGroup',
Label : '{i18n>Informations}',
}],
};

////////////////////////////////////////////////////////////////////////////
//
// Authors List
Expand Down
1 change: 0 additions & 1 deletion fiori/app/genres/fiori-service.cds
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using { sap.capire.bookshop.Genres } from '@capire/bookstore';

annotate Genres with @cds.search: {name};
annotate Genres with @readonly;
annotate Genres with {
name @title: '{i18n>Genre}';
}
Expand Down
2 changes: 1 addition & 1 deletion fiori/app/genres/webapp/i18n/i18n.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#XTIT
appTitle=Browse Genres
appTitle=Manage Genres
#XTXT
appDescription=Genres as Tree View
4 changes: 2 additions & 2 deletions fiori/app/genres/webapp/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@
},
"crossNavigation": {
"inbounds": {
"Genres-display": {
"Genres-manage": {
"signature": {
"parameters": {},
"additionalParameters": "allowed"
},
"semanticObject": "Genres",
"action": "display"
"action": "manage"
}
}
}
Expand Down
Loading