From 5f5b32043c739bc245824b57b7cfbcca655bfb84 Mon Sep 17 00:00:00 2001 From: D070615 Date: Thu, 20 Mar 2025 16:20:20 +0100 Subject: [PATCH] add read only tree table and value help --- .../db/data/sap.capire.bookshop-Genres.csv | 48 ++++-- bookshop/db/schema.cds | 2 +- bookshop/srv/admin-service.cds | 1 + bookshop/srv/cat-service.cds | 6 + bookshop/srv/hierarchy.cds | 29 ++++ fiori/app/admin-books/fiori-service.cds | 63 +++++++- fiori/app/appconfig/fioriSandboxConfig.json | 2 +- fiori/app/browse/fiori-service.cds | 13 ++ fiori/app/common.cds | 4 +- fiori/app/genres/fiori-service.cds | 26 ++- fiori/app/genres/webapp/Component.js | 10 +- fiori/app/genres/webapp/i18n/i18n.properties | 4 +- .../app/genres/webapp/i18n/i18n_de.properties | 2 + fiori/app/genres/webapp/manifest.json | 149 +++++++++--------- fiori/db/common.cds | 14 -- .../sap.capire.bookshop-GenreHierarchy.csv | 16 -- 16 files changed, 249 insertions(+), 140 deletions(-) create mode 100644 bookshop/srv/hierarchy.cds create mode 100644 fiori/app/genres/webapp/i18n/i18n_de.properties delete mode 100644 fiori/db/common.cds delete mode 100644 fiori/db/data/sap.capire.bookshop-GenreHierarchy.csv diff --git a/bookshop/db/data/sap.capire.bookshop-Genres.csv b/bookshop/db/data/sap.capire.bookshop-Genres.csv index a3070fae..76a43bcf 100644 --- a/bookshop/db/data/sap.capire.bookshop-Genres.csv +++ b/bookshop/db/data/sap.capire.bookshop-Genres.csv @@ -1,16 +1,34 @@ ID,parent_ID,name -10,,Fiction -11,10,Drama -12,10,Poetry -13,10,Fantasy -14,10,Science Fiction -15,10,Romance -16,10,Mystery -17,10,Thriller -18,10,Dystopia -19,10,Fairy Tale -20,,Non-Fiction -21,20,Biography -22,21,Autobiography -23,20,Essay -24,20,Speech +8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,,Fiction +08467c69-4b69-4b30-bf51-998f9c4b8a12,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Action +c5247996-2516-40c5-b3ea-02492a1e1f4d,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Adventure +d74eb118-ff57-4776-96d3-0d649278bf6b,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Drama +b84a7e92-cc0c-4599-8b62-9e3ae39e343f,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Poetry +445a6c1e-071f-4e9d-b0bb-670ec73b0a49,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Fantasy +0d4f268f-c5c5-4a82-b54a-2120271cf54e,445a6c1e-071f-4e9d-b0bb-670ec73b0a49,Epic fantasy +5ccfe8e7-009f-4744-91fd-c1c1e9a0c9c6,445a6c1e-071f-4e9d-b0bb-670ec73b0a49,High fantasy +86e9f4d5-3e7c-4c06-8421-8b6d72fe9c93,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Science Fiction +9f8653a2-6d6d-4fd7-b02f-b90d15d6f67f,86e9f4d5-3e7c-4c06-8421-8b6d72fe9c93,Utopian and Dystopian +7c7b2c30-c24e-4627-bb84-0f9d09f9e91b,9f8653a2-6d6d-4fd7-b02f-b90d15d6f67f,Dystopia +34f6a939-2708-4cc0-9882-daf36a8ed5e6,7c7b2c30-c24e-4627-bb84-0f9d09f9e91b,Cyberpunk +4297bff9-c4b3-4097-b68f-5605f89c6e4c,34f6a939-2708-4cc0-9882-daf36a8ed5e6,Steampunk +f283b1b3-b763-42f9-95f0-38e1d78a1d7e,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Romance +5d2c5060-84cf-4a94-9118-8d9ad88f2a24,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Mystery +7d6cc413-cf8c-4cf9-b30a-bf8cf6f97b72,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Graphic Novel +f846b0b9-01d4-4f6d-82a4-d79204f62576,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Thriller +82f9a2d9-bd77-4cfd-9c76-d03b8f6827a3,f846b0b9-01d4-4f6d-82a4-d79204f62576,Suspense +a7b5b4d7-bff3-430d-9d7e-25fd67b66022,f846b0b9-01d4-4f6d-82a4-d79204f62576,Crime thriller +5f93c395-6f8a-43de-84c1-bf22cfba8f56,f846b0b9-01d4-4f6d-82a4-d79204f62576,Spy thriller +3ff51d9c-5ff5-421f-8d0d-d75b08e32a25,f846b0b9-01d4-4f6d-82a4-d79204f62576,Political thriller +a530cd31-b0cf-4a32-9f28-72ee7b9f29fc,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Short Story +5b091c64-8b4f-401a-a06d-61b19857635b,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Fairy Tale +7125da65-b3ae-4a0b-a735-1db410a3e079,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Horror +a02b5c9b-b79f-43ef-b2ab-28e4b431cc18,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Historical Fiction +d6c3448e-d771-47f0-b6c7-8d2159b29d2a,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Contemporary Fiction +7ed5cfab-8c4d-46a3-b89b-c5b8fa74f049,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Magical Realism +23e86990-66d3-4488-8272-98ed056710b5,8bbf14c6-b378-4e35-9b4f-5a9c8b8762da,Literary Fiction +85b5a640-7e9a-468e-80e2-e9268486031b,,Non-Fiction +10d19b1a-832b-4d60-bf9b-88dcd089db85,85b5a640-7e9a-468e-80e2-e9268486031b,Biography +1f1c8b5b-451e-48f6-bdbb-759be4ea1a8f,10d19b1a-832b-4d60-bf9b-88dcd089db85,Autobiography +4bc5ad4d-b7a3-47a7-9938-325c6fdf8041,85b5a640-7e9a-468e-80e2-e9268486031b,Essay +e0d350c2-1f42-45b5-b768-67cccd997b56,85b5a640-7e9a-468e-80e2-e9268486031b,Speech diff --git a/bookshop/db/schema.cds b/bookshop/db/schema.cds index 930f19eb..a6b2057e 100644 --- a/bookshop/db/schema.cds +++ b/bookshop/db/schema.cds @@ -25,7 +25,7 @@ entity Authors : managed { /** Hierarchically organized Code List for Genres */ entity Genres : sap.common.CodeList { - key ID : Integer; + key ID : UUID; parent : Association to Genres; children : Composition of many Genres on children.parent = $self; } diff --git a/bookshop/srv/admin-service.cds b/bookshop/srv/admin-service.cds index c5048e58..10fc6801 100644 --- a/bookshop/srv/admin-service.cds +++ b/bookshop/srv/admin-service.cds @@ -2,4 +2,5 @@ using { sap.capire.bookshop as my } from '../db/schema'; service AdminService @(requires:'admin', path:'/admin') { entity Books as projection on my.Books; entity Authors as projection on my.Authors; + entity GenreHierarchy as projection on my.Genres } diff --git a/bookshop/srv/cat-service.cds b/bookshop/srv/cat-service.cds index 2441db25..53910d46 100644 --- a/bookshop/srv/cat-service.cds +++ b/bookshop/srv/cat-service.cds @@ -1,4 +1,7 @@ using { sap.capire.bookshop as my } from '../db/schema'; +using {my.common.Hierarchy as Hierarchy} from './hierarchy'; + +extend my.Genres with Hierarchy; service CatalogService @(path:'/browse') { /** For displaying lists of Books */ @@ -10,6 +13,9 @@ service CatalogService @(path:'/browse') { author.name as author } excluding { createdBy, modifiedBy }; + @readonly + entity GenreHierarchy as projection on my.Genres; + @requires: 'authenticated-user' action submitOrder ( book: Books:ID, quantity: Integer ) returns { stock: Integer }; event OrderedBook : { book: Books:ID; quantity: Integer; buyer: String }; diff --git a/bookshop/srv/hierarchy.cds b/bookshop/srv/hierarchy.cds new file mode 100644 index 00000000..f6619d98 --- /dev/null +++ b/bookshop/srv/hierarchy.cds @@ -0,0 +1,29 @@ +namespace my.common; + +aspect Hierarchy { + virtual LimitedDescendantCount : Integer64; + virtual DistanceFromRoot : Integer64; + virtual DrillState : String; + virtual Matched : Boolean; + virtual MatchedDescendantCount : Integer64; + virtual LimitedRank : Integer64; +} + + +annotate Hierarchy with @Capabilities.FilterRestrictions.NonFilterableProperties: [ + 'LimitedDescendantCount', + 'DistanceFromRoot', + 'DrillState', + 'Matched', + 'MatchedDescendantCount', + 'LimitedRank' +]; + +annotate Hierarchy with @Capabilities.SortRestrictions.NonSortableProperties: [ + 'LimitedDescendantCount', + 'DistanceFromRoot', + 'DrillState', + 'Matched', + 'MatchedDescendantCount', + 'LimitedRank' +]; diff --git a/fiori/app/admin-books/fiori-service.cds b/fiori/app/admin-books/fiori-service.cds index dc820ea9..866a45e9 100644 --- a/fiori/app/admin-books/fiori-service.cds +++ b/fiori/app/admin-books/fiori-service.cds @@ -40,7 +40,68 @@ annotate AdminService.Books with @( } ); +//////////////////////////////////////////////////////////////////////////// +// +// Value Help for Tree Table +// +annotate AdminService.Books with { + genre @(Common: { + Label : 'Genre', + ValueList: { + CollectionPath : 'GenreHierarchy', + Parameters : [ + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty: 'name', + }, + { + $Type : 'Common.ValueListParameterInOut', + LocalDataProperty: genre_ID, + ValueListProperty: 'ID', + } + ], + PresentationVariantQualifier: 'VH', + } + }); +} +annotate AdminService.GenreHierarchy with @UI: { + PresentationVariant #VH: { + $Type : 'UI.PresentationVariantType', + Visualizations : ['@UI.LineItem'], + RecursiveHierarchyQualifier: 'GenreHierarchy' + }, + LineItem : [{ + $Type: 'UI.DataField', + Value: name, + Label : 'Genre' + }], +}; + +// Hide ID because of the ValueHelp +annotate AdminService.GenreHierarchy with { + ID @UI.Hidden; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Tree Table +// +annotate AdminService.GenreHierarchy with @Aggregation.RecursiveHierarchy#GenreHierarchy: { + $Type: 'Aggregation.RecursiveHierarchyType', + NodeProperty: ID, // identifies a node + ParentNavigationProperty: parent // navigates to a node's parent + }; + +annotate AdminService.GenreHierarchy with @Hierarchy.RecursiveHierarchy#GenreHierarchy: { + $Type: 'Hierarchy.RecursiveHierarchyType', + LimitedDescendantCount: LimitedDescendantCount, + DistanceFromRoot: DistanceFromRoot, + DrillState: DrillState, + Matched: Matched, + MatchedDescendantCount: MatchedDescendantCount, + LimitedRank: LimitedRank +}; //////////////////////////////////////////////////////////// // @@ -82,5 +143,3 @@ extend service AdminService { // Workaround for Fiori popup for asking user to enter a new UUID on Create annotate AdminService.Books with { ID @Core.Computed; } -// Show Genre as drop down, not a dialog -annotate AdminService.Books with { genre @Common.ValueListWithFixedValues; } diff --git a/fiori/app/appconfig/fioriSandboxConfig.json b/fiori/app/appconfig/fioriSandboxConfig.json index b3ec8246..c412e5ec 100644 --- a/fiori/app/appconfig/fioriSandboxConfig.json +++ b/fiori/app/appconfig/fioriSandboxConfig.json @@ -24,7 +24,7 @@ "id": "BrowseGenres", "tileType": "sap.ushell.ui.tile.StaticTile", "properties": { - "title": "Browse Genres (OData v2)", + "title": "Browse Genres", "targetURL": "#Genres-display" } } diff --git a/fiori/app/browse/fiori-service.cds b/fiori/app/browse/fiori-service.cds index 015e265b..eb294781 100644 --- a/fiori/app/browse/fiori-service.cds +++ b/fiori/app/browse/fiori-service.cds @@ -55,3 +55,16 @@ annotate CatalogService.Books with @(UI : { {Value : currency.symbol}, ] }, ); + +annotate CatalogService.GenreHierarchy with @UI: { + PresentationVariant : { + $Type : 'UI.PresentationVariantType', + RequestAtLeast: [name], + Visualizations: ['@UI.LineItem'], + }, + LineItem : [{ + $Type: 'UI.DataField', + Value: name, + Label : 'Genre' + }], +}; \ No newline at end of file diff --git a/fiori/app/common.cds b/fiori/app/common.cds index 3e5f748a..f14439ea 100644 --- a/fiori/app/common.cds +++ b/fiori/app/common.cds @@ -80,7 +80,8 @@ annotate my.Genres with @( LineItem : [ { Value: name }, { - Value : parent.name, + Value : name, + // TODO: i18n Label: 'Main Genre' }, ], @@ -115,7 +116,6 @@ annotate my.Genres with @(UI : { // Genres Elements // annotate my.Genres with { - ID @title: '{i18n>ID}'; name @title: '{i18n>Genre}'; } diff --git a/fiori/app/genres/fiori-service.cds b/fiori/app/genres/fiori-service.cds index 908ffdcc..2a72e589 100644 --- a/fiori/app/genres/fiori-service.cds +++ b/fiori/app/genres/fiori-service.cds @@ -1,8 +1,20 @@ -using { sap.capire.bookshop } from '../../db/common'; +/* + UI annotations for the Browse GenreHierarchy App +*/ +using CatalogService from '@capire/bookstore'; -annotate bookshop.GenreHierarchy { - ID @sap.hierarchy.node.for; - parent @sap.hierarchy.parent.node.for; - hierarchyLevel @sap.hierarchy.level.for; - drillState @sap.hierarchy.drill.state.for; -} +annotate CatalogService.GenreHierarchy with @Aggregation.RecursiveHierarchy#GenreHierarchy: { + $Type: 'Aggregation.RecursiveHierarchyType', + NodeProperty: ID, // identifies a node + ParentNavigationProperty: parent // navigates to a node's parent + }; + +annotate CatalogService.GenreHierarchy with @Hierarchy.RecursiveHierarchy#GenreHierarchy: { + $Type: 'Hierarchy.RecursiveHierarchyType', + LimitedDescendantCount: LimitedDescendantCount, + DistanceFromRoot: DistanceFromRoot, + DrillState: DrillState, + Matched: Matched, + MatchedDescendantCount: MatchedDescendantCount, + LimitedRank: LimitedRank +}; diff --git a/fiori/app/genres/webapp/Component.js b/fiori/app/genres/webapp/Component.js index a8c2a9d6..63ffcefd 100644 --- a/fiori/app/genres/webapp/Component.js +++ b/fiori/app/genres/webapp/Component.js @@ -1,7 +1,3 @@ -sap.ui.define(["sap/suite/ui/generic/template/lib/AppComponent"], (AppComponent) => - AppComponent.extend("genres.Component", { - metadata: { - manifest: "json", - }, - }) -); +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("genres.Component", { + metadata:{ manifest:'json' } +})) diff --git a/fiori/app/genres/webapp/i18n/i18n.properties b/fiori/app/genres/webapp/i18n/i18n.properties index b42a7a23..42da0671 100644 --- a/fiori/app/genres/webapp/i18n/i18n.properties +++ b/fiori/app/genres/webapp/i18n/i18n.properties @@ -1,4 +1,4 @@ #XTIT -appTitle=Genres +appTitle=Browse Genres #XTXT -appDescription=Browse Genres +appDescription=Genres as Tree View diff --git a/fiori/app/genres/webapp/i18n/i18n_de.properties b/fiori/app/genres/webapp/i18n/i18n_de.properties new file mode 100644 index 00000000..e8714e92 --- /dev/null +++ b/fiori/app/genres/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Zeige Genres +appDescription=Genres als Baumansicht diff --git a/fiori/app/genres/webapp/manifest.json b/fiori/app/genres/webapp/manifest.json index 4a4f33d8..8048179f 100644 --- a/fiori/app/genres/webapp/manifest.json +++ b/fiori/app/genres/webapp/manifest.json @@ -3,18 +3,31 @@ "sap.app": { "id": "genres", "type": "application", + "title": "Browse genres", + "description": "Sample Application", "i18n": "i18n/i18n.properties", "applicationVersion": { "version": "1.0.0" }, - "title": "Browse Genres Hierarchy (OData v2)", - "description": "{{appDescription}}", + "dataSources": { + "CatalogService": { + "uri": "browse/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, "tags": { "keywords": [] }, "crossNavigation": { "inbounds": { - "appShow": { + "Genres-display": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, "title": "{{appTitle}}", "semanticObject": "GenreHierarchy", "action": "display", @@ -29,25 +42,6 @@ }, "outbounds": {} }, - "ach": "", - "resources": "resources.json", - "dataSources": { - "main": { - "uri": "/odata/v2/browse", - "type": "OData", - "settings": { - "annotations": ["localAnnotations"], - "localUri": "localService/metadata.xml" - } - }, - "localAnnotations": { - "type": "ODataAnnotation", - "uri": "annotations/localAnnotations.xml", - "settings": { - "localUri": "annotations/localAnnotations.xml" - } - } - }, "offline": false, "sourceTemplate": { "id": "ui5template.smartTemplate", @@ -86,70 +80,79 @@ "type": "sap.ui.model.resource.ResourceModel", "uri": "i18n/i18n.properties" }, - "@i18n": { - "type": "sap.ui.model.resource.ResourceModel", - "uri": "i18n/i18n.properties" - }, - "json": { - "type": "sap.ui.model.json.JSONModel" - }, - "i18n|sap.suite.ui.generic.template.ListReport|Genres": { - "type": "sap.ui.model.resource.ResourceModel", - "uri": "i18n/ListReport/Genres/i18n.properties" - }, "": { - "dataSource": "main", - "preload": true, + "dataSource": "CatalogService", "settings": { - "useBatch": true, - "defaultBindingMode": "TwoWay", - "defaultCountMode": "Inline", - "refreshAfterChange": true, - "metadataUrlParams": { - "sap-value-list": "none" + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect": true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } } } } }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "GenreHierarchyList", + "target": "GenreHierarchyList" + }, + { + "pattern": "GenreHierarchy({key}):?query:", + "name": "GenreHierarchyDetails", + "target": "GenreHierarchyDetails" + } + ], + "targets": { + "GenreHierarchyList": { + "type": "Component", + "id": "GenreHierarchyList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings" : { + "contextPath" : "/GenreHierarchy", + "navigation" : { + "GenreHierarchy" : { + "detail" : { + "route" : "GenreHierarchyDetails" + } + } + }, + "controlConfiguration": { + "@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "hierarchyQualifier": "GenreHierarchy", + "type": "TreeTable" + } + } + } + } + } + }, + "GenreHierarchyDetails": { + "type": "Component", + "id": "GenreHierarchyDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "contextPath" : "/GenreHierarchy" + } + } + } + } + }, "contentDensities": { "compact": true, "cozy": true } }, - "sap.ui.generic.app": { - "_version": "1.3.0", - "settings": { - "forceGlobalRefresh": false, - "useColumnLayoutForSmartForm": false, - "showBasicSearch": false - }, - "pages": { - "ListReport|Genres": { - "entitySet": "GenreHierarchy", - "component": { - "name": "sap.suite.ui.generic.template.ListReport", - "list": true, - "settings": { - "condensedTableLayout": true, - "smartVariantManagement": true, - "tableType": "TreeTable", - "enableTableFilterInPageVariant": true, - "dataLoadSettings": { - "loadDataOnAppLaunch": "always" - } - } - } - } - } - }, "sap.fiori": { "registrationIds": [], "archeType": "transactional" - }, - "sap.platform.hcp": { - "uri": "" - }, - "sap.platform.cf": { - "oAuthScopes": [] } } diff --git a/fiori/db/common.cds b/fiori/db/common.cds deleted file mode 100644 index 38438e78..00000000 --- a/fiori/db/common.cds +++ /dev/null @@ -1,14 +0,0 @@ -namespace sap.capire.bookshop; - -using { sap.capire.bookshop } from '@capire/bookstore/srv/mashup'; - -entity GenreHierarchy : bookshop.Genres { - hierarchyLevel : Integer default 0; - drillState : String default 'leaf'; - parent : Association to GenreHierarchy; - children : Composition of many GenreHierarchy on children.parent = $self; -} - -extend service CatalogService with { - @readonly entity GenreHierarchy as projection on bookshop.GenreHierarchy; -} diff --git a/fiori/db/data/sap.capire.bookshop-GenreHierarchy.csv b/fiori/db/data/sap.capire.bookshop-GenreHierarchy.csv deleted file mode 100644 index f0d3743e..00000000 --- a/fiori/db/data/sap.capire.bookshop-GenreHierarchy.csv +++ /dev/null @@ -1,16 +0,0 @@ -ID;parent_ID;name;hierarchyLevel;drillState -10;;Fiction;0;expanded -11;10;Drama;1;leaf -12;10;Poetry;1;leaf -13;10;Fantasy;1;leaf -14;10;Science Fiction;1;leaf -15;10;Romance;1;leaf -16;10;Mystery;1;leaf -17;10;Thriller;1;leaf -18;10;Dystopia;1;leaf -20;;Non-Fiction;0;expanded -19;10;Fairy Tale;1;leaf -21;20;Biography;1;expanded -22;21;Autobiography;2;leaf -23;20;Essay;1;leaf -24;20;Speech;1;leaf