Compare commits

..

24 Commits

Author SHA1 Message Date
dependabot[bot]
6c97c7f601 Bump form-data from 4.0.2 to 4.0.4 in /.deploy/app-router
---
updated-dependencies:
- dependency-name: form-data
  dependency-version: 4.0.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-22 07:54:22 +00:00
Daniel Hutzel
78cea03ae7 test with chest 2025-07-20 01:17:53 +02:00
Daniel Hutzel
ef8702acf8 more folders cleanup 2025-07-19 09:16:15 +02:00
Daniel Hutzel
dcc74fbd10 . 2025-07-18 12:53:03 +02:00
Daniel Hutzel
d1353db705 . 2025-07-17 15:51:18 +02:00
Daniel Hutzel
c10ca17546 chore: Merged fiori into bookstore and tests into subprojects 2025-07-17 13:54:32 +02:00
dependabot[bot]
dcb0c0394a Bump the production-dependencies group across 1 directory with 2 updates (#845)
Bumps the production-dependencies group with 2 updates in the / directory: [@cap-js/hana](https://cap.cloud.sap/) and @sap/xssec.


Updates `@cap-js/hana` from 1.8.1 to 2.1.1

Updates `@sap/xssec` from 4.6.0 to 4.8.0

---
updated-dependencies:
- dependency-name: "@cap-js/hana"
  dependency-version: 2.1.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: production-dependencies
- dependency-name: "@sap/xssec"
  dependency-version: 4.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-08 09:53:54 +02:00
dependabot[bot]
c7d869ef62 Bump the development-dependencies group across 1 directory with 2 updates (#842)
Bumps the development-dependencies group with 2 updates in the / directory: [@cap-js/cds-test](https://github.com/cap-js/cds-test) and [@cap-js/sqlite](https://github.com/cap-js/cds-dbs).


Updates `@cap-js/cds-test` from 0.3.0 to 0.4.0
- [Release notes](https://github.com/cap-js/cds-test/releases)
- [Changelog](https://github.com/cap-js/cds-test/blob/main/CHANGELOG.md)
- [Commits](https://github.com/cap-js/cds-test/compare/v0.3.0...v0.4.0)

Updates `@cap-js/sqlite` from 1.10.0 to 2.0.1
- [Release notes](https://github.com/cap-js/cds-dbs/releases)
- [Changelog](https://github.com/cap-js/cds-dbs/blob/hana-v2.0.1/release-please-config.json)
- [Commits](https://github.com/cap-js/cds-dbs/compare/sqlite-v1.10.0...hana-v2.0.1)

---
updated-dependencies:
- dependency-name: "@cap-js/cds-test"
  dependency-version: 0.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: "@cap-js/sqlite"
  dependency-version: 2.0.1
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-08 09:51:38 +02:00
Christian Georgi
991b672e53 chore(dependabot): ignore express 5 2025-07-08 09:49:20 +02:00
Christian Georgi
a7b4a23163 Remove Node 18 2025-07-08 09:45:19 +02:00
Heiko Witteborg
36d58664c9 Merge pull request #841 from SAP-samples/bookshop-tests
Fix: adjust IDs and size of Genre objects for testing
2025-07-02 11:34:12 +02:00
Eric Peairs
f8252207a0 Fix: adjust IDs and size of Genre objects for testing
Changed ID values of Genre objects to UUIDs and decreased depth of the POSTed Genre object to match the maximum depth of DELETE
2025-06-24 14:51:25 +02:00
Daniel Hutzel
600afb704a Fiori Tree Views towards GA (#839)
* Fiori Tree Views towards GA

* Also automate addition of Aggregation.RecursiveHierarchy

* Cleanup models for Genres Tree View

* Implementing @hierarchy shortcut

* .

* Formatting

* Using verbose config
2025-06-05 15:39:50 +02:00
Johannes Vogel
6fa2aaee34 fiori: rm unused hierarchy elements (#838) 2025-05-15 15:43:21 +02:00
Daniel Hutzel
987611b009 cosmetics 2025-05-14 14:09:13 +02:00
Daniel Hutzel
ce1da7fce9 cleanup deps in nested tests' package.jsons 2025-05-08 10:28:48 +02:00
Daniel Hutzel
395587b1bf fix: update SAP UI5 resource URLs to use the latest domain 2025-05-07 10:29:17 +02:00
Johannes Vogel
bab7827000 chore(deps): allow newer cap-js versions (#835) 2025-04-29 14:48:22 +02:00
Daniel Hutzel
efc2f3632f Moved app/routes back into srv/server, as cds build ignores the former 2025-04-28 06:55:35 +02:00
Daniel Hutzel
61ceb4a63a Removed TreeView fake handlers for SQLite 2025-04-28 06:07:40 +02:00
Daniel Hutzel
226ab2539e Using specific list of npm workspaces 2025-04-24 14:38:11 +02:00
Daniel Hutzel
56a9796329 . 2025-04-24 05:33:59 +02:00
Johannes Vogt
ece1962052 Merge pull request #834 from SAP-samples/shared-db-deps
add shared-db dependencies
2025-04-23 10:47:41 +02:00
Johannes Vogt
f90c43150a add shared-db dependencies 2025-04-23 09:42:50 +02:00
101 changed files with 1281 additions and 1090 deletions

View File

@@ -1068,14 +1068,15 @@
}
},
"node_modules/form-data": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {

View File

@@ -1,11 +1,6 @@
{
"welcomeFile": "app/bookshop/index.html",
"routes": [
{
"source": "^/-/cds/.*",
"destination": "mtx-api",
"authenticationType": "none"
},
{
"source": "^/app/(.*)$",
"target": "$1",

View File

@@ -18,3 +18,6 @@ updates:
- dependency-name: "chai-as-promised"
# chai-as-promised 8 doesn't work atm w/ cds.test, TODO fix that in cds.test
versions: ["8.x"]
- dependency-name: "express"
# express 5 not supported atm
versions: ["5.x"]

View File

@@ -15,7 +15,7 @@ jobs:
strategy:
matrix:
node-version: [22.x, 20.x, 18.x]
node-version: [22.x, 20.x]
steps:
- uses: actions/checkout@v4

27
.vscode/launch.json vendored
View File

@@ -18,8 +18,8 @@
]
},
{
"name": "Fiori App",
"command": "npx cds watch fiori",
"name": "bookstore",
"command": "npx cds watch bookstore",
"type": "node-terminal",
"request": "launch",
"skipFiles": [
@@ -29,29 +29,6 @@
"**/cds/lib/req/cds-context.js",
"**/odata-v4/okra/**"
]
},
{
"name": "Debug Mocha Tests",
"type": "node",
"request": "attach",
"port": 9229,
"continueOnAttach": true,
"skipFiles": [
"<node_internals>/**",
"**/node_modules/**",
"**/cds/lib/lazy.js",
"**/cds/lib/req/cds-context.js",
"**/odata-v4/okra/**",
]
},
],
"inputs": [
{
"type": "pickString",
"id": "sample",
"description": "Which sample do you want to start?",
"options": [ "bookshop", "fiori", "reviews", "reviews" ],
"default": "bookshop"
}
]
}

View File

@@ -12,6 +12,5 @@
"**/cds/lib/req/cds-context.js",
"**/odata-v4/okra/**"
]
},
"jest.jestCommandLine": "npx jest"
}
}

View File

@@ -9,7 +9,7 @@
"index.cds"
],
"devDependencies": {
"@cap-js/sqlite": "*"
"@cap-js/sqlite": ">=1"
},
"dependencies": {
"@sap/cds": ">=7",

View File

@@ -1,5 +1,5 @@
const cds = require('@sap/cds')
const { GET, POST, expect } = cds.test(__dirname+'/../bookshop')
const { GET, POST, expect } = cds.test(__dirname+'/..')
cds.User.default = cds.User.Privileged // hard core monkey patch
describe('cap/samples - Custom Handlers', () => {

View File

@@ -1,38 +0,0 @@
#################################################
#
# Genres
#
GET http://localhost:4004/odata/v4/test/Genres?
###
GET http://localhost:4004/odata/v4/test/Genres?
&$filter=parent_ID eq null&$select=name
&$expand=children($select=name)
###
POST http://localhost:4004/odata/v4/test/Genres?
Content-Type: application/json
{ "ID":100, "name":"Some Sample Genres...", "children":[
{ "ID":101, "name":"Cat", "children":[
{ "ID":102, "name":"Kitty", "children":[
{ "ID":103, "name":"Kitty Cat", "children":[
{ "ID":104, "name":"Aristocat" } ]},
{ "ID":105, "name":"Kitty Bat" } ]},
{ "ID":106, "name":"Catwoman", "children":[
{ "ID":107, "name":"Catalina" } ]} ]},
{ "ID":108, "name":"Catweazle" }
]}
###
GET http://localhost:4004/odata/v4/test/Genres(100)?
# &$expand=children
# &$expand=children($expand=children($expand=children($expand=children)))
###
DELETE http://localhost:4004/odata/v4/test/Genres(103)
###
DELETE http://localhost:4004/odata/v4/test/Genres(100)
###

View File

@@ -1,5 +1,5 @@
const cds = require('@sap/cds')
const { expect } = cds.test.in(__dirname,'..')
const { expect } = cds.test.in(__dirname,'..','..')
describe('cap/samples - Hierarchical Data', ()=>{

View File

@@ -0,0 +1,37 @@
#################################################
#
# Genres
#
GET http://localhost:4004/odata/v4/test/Genres?
###
GET http://localhost:4004/odata/v4/test/Genres?
&$filter=parent_ID eq null&$select=name
&$expand=children($select=name)
###
POST http://localhost:4004/odata/v4/test/Genres?
Content-Type: application/json
{ "ID":"100aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Some Sample Genres...", "children":[
{ "ID":"101aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Cat", "children":[
{ "ID":"102aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Kitty", "children":[
{ "ID":"103aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Aristocat" },
{ "ID":"104aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Kitty Bat" } ]},
{ "ID":"105aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Catwoman", "children":[
{ "ID":"106aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Catalina" } ]} ]},
{ "ID":"107aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Catweazle" }
]}
###
GET http://localhost:4004/odata/v4/test/Genres(100aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa)?
&$expand=children
&$expand=children($expand=children($expand=children($expand=children)))
###
DELETE http://localhost:4004/odata/v4/test/Genres(103aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa)
###
DELETE http://localhost:4004/odata/v4/test/Genres(100aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa)
###

View File

@@ -1,4 +1,4 @@
using { sap.capire.bookshop as my } from '../db/schema';
using { sap.capire.bookshop as my } from '../../db/schema';
service TestService {
entity Genres as projection on my.Genres;
}

View File

@@ -1,5 +1,5 @@
{
"devDependencies": {
"@cap-js/sqlite": "^1"
"@cap-js/sqlite": "*"
}
}

View File

@@ -40,8 +40,7 @@ Authorization: Basic alice:
{
"ID": 112,
"name": "Shakespeeeeere",
"age": 22
"name": "Shakespeeeeere"
}
@@ -56,7 +55,7 @@ Authorization: Basic alice:
"title": "Poems : Pocket Poets",
"descr": "The Everyman's Library Pocket Poets hardcover series is popular for its compact size and reasonable price which does not compromise content. Poems: Bronte contains poems that demonstrate a sensibility elemental in its force with an imaginative discipline and flexibility of the highest order. Also included are an Editor's Note and an index of first lines.",
"author": { "ID": 101 },
"genre": { "ID": 12 },
"genre": { "ID": "12aaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" },
"stock": 5,
"price": "12.05",
"currency": { "code": "USD" }

View File

@@ -0,0 +1,126 @@
const cds = require('@sap/cds/lib')
const { GET, expect, axios } = cds.test(__dirname)
// Fetch API disallows GET|HEAD requests with body
if (axios.constructor.name === 'Naxios') it = it.skip
describe ('GET w/ query in body', () => {
it ('serves CQN query objects in body', async () => {
const {data:books} = await GET ('/hcql/admin', {
headers: { 'Content-Type': 'application/json' },
data: cds.ql `SELECT from Books`
})
expect(books).to.be.an('array').of.length(5)
})
it ('serves plain CQL strings in body', async () => {
const {data:books} = await GET ('/hcql/admin', {
headers: { 'Content-Type': 'text/plain' },
data: `SELECT from Books`
})
expect(books).to.be.an('array').of.length(5)
})
it ('serves complex and deep queries', async () => {
const {data:books} = await GET ('/hcql/admin', {
headers: { 'Content-Type': 'text/plain' },
data: `SELECT from Authors {
name,
books [order by title] {
title,
genre.name as genre
}
}`
})
expect(books).to.deep.equal([
{
name: "Emily Brontë",
books: [
{ title: "Wuthering Heights", genre: 'Drama' }
]
},
{
name: "Charlotte Brontë",
books: [
{ title: "Jane Eyre", genre: 'Drama' }
]
},
{
name: "Edgar Allen Poe",
books: [
{ title: "Eleonora", genre: 'Romance' },
{ title: "The Raven", genre: 'Mystery' },
]
},
{
name: "Richard Carpenter",
books: [
{ title: "Catweazle", genre: 'Fantasy' }
]
}
])
})
})
describe ('Sluggified variants', () => {
test ('GET /Books', async () => {
const {data:books} = await GET ('/hcql/admin/Books')
expect(books).to.be.an('array').of.length(5)
expect(books.length).to.eql(5) //.of.length(5)
})
test ('GET /Books/201', async () => {
const {data:book} = await GET ('/hcql/admin/Books/201')
expect(book).to.be.an('object')
expect(book).to.have.property ('title', "Wuthering Heights")
})
test ('GET /Books { title, author.name as author }' , async () => {
const {data:books} = await GET ('/hcql/admin/Books { title, author.name as author } order by ID')
expect(books).to.deep.equal ([
{ title: "Wuthering Heights", author: "Emily Brontë" },
{ title: "Jane Eyre", author: "Charlotte Brontë" },
{ title: "The Raven", author: "Edgar Allen Poe" },
{ title: "Eleonora", author: "Edgar Allen Poe" },
{ title: "Catweazle", author: "Richard Carpenter" }
])
})
test ('GET /Books/201 w/ CQL tail in URL' , async () => {
const {data:book} = await GET ('/hcql/admin/Books/201 { title, author.name as author } order by ID')
expect(book).to.deep.equal ({ title: "Wuthering Heights", author: "Emily Brontë" })
})
it ('GET /Books/201 w/ CQL fragment in body' , async () => {
const {data:book} = await GET ('/hcql/admin/Books/201', {
headers: { 'Content-Type': 'text/plain' },
data: `{ title, author.name as author }`
})
expect(book).to.deep.equal ({ title: "Wuthering Heights", author: "Emily Brontë" })
})
it ('GET /Books/201 w/ CQN fragment in body' , async () => {
const {data:book} = await GET ('/hcql/admin/Books/201', {
data: cds.ql `SELECT title, author.name as author` .SELECT
})
expect(book).to.deep.equal ({ title: "Wuthering Heights", author: "Emily Brontë" })
})
it ('GET /Books/201 w/ tail in URL plus CQL/CQN fragments in body' , async () => {
const {data:[b1]} = await GET ('/hcql/admin/Books where ID=201', {
data: cds.ql `SELECT title, author.name as author` .SELECT
})
expect(b1).to.deep.equal ({ title: "Wuthering Heights", author: "Emily Brontë" })
const {data:[b2]} = await GET ('/hcql/admin/Books where ID=201', {
headers: { 'Content-Type': 'text/plain' },
data: `{ title, author.name as author }`
})
expect(b2).to.deep.equal ({ title: "Wuthering Heights", author: "Emily Brontë" })
})
})

View File

@@ -0,0 +1,225 @@
@server = http://localhost:4004
GET {{server}}/odata/v4/admin/Authors?
&$select=ID,name
&$expand=books($select=ID,title)
&$count=true
###
#
# The basic variant expects a CQN object passed as an application/json body
# to a POST request. This is also the fastest one, as it doesn't need CQL parsing.
# Note: $count is returned in X-Total-Count response header
#
GET {{server}}/hcql/admin
Content-Type: application/json
# Accept-Language: de
{ "SELECT": {
"from": { "ref": [ "Authors" ] },
"columns": [
{ "ref": [ "name" ] },
{ "ref": [ "books" ], "expand": [
{ "ref": [ "ID" ] },
{ "ref": [ "title" ] }
]}
],
"count": true
}}
###
POST {{server}}/hcql/browse/submitOrder?book=201&quantity=2
Authorization: Basic alice:
###
POST {{server}}/hcql/browse/submitOrder
Authorization: Basic alice:
Content-Type: application/json
{
"book": 201,
"quantity": 2
}
###
GET {{server}}/hcql/browse/submitOrder?book=201&quantity=2
Authorization: Basic alice:
###
#
# Alternatively you can pass a CQL string as plain/text body
#
GET {{server}}/hcql/admin
Content-Type: text/plain
# X-Total-Count: true
SELECT from Authors { name, books { title }}
# SELECT from Books { title, currency }
###
#
# In addition we offer convenience slug routes...
# .e.g. /srv/entity routes
#
GET {{server}}/hcql/admin/Books
###
GET {{server}}/hcql/admin/Books/201
###
GET {{server}}/hcql/admin/Books { ID, title, author.name as author }
###
GET {{server}}/hcql/admin/Books order by stock desc
Content-Type: text/plain
{ title, stock }
###
GET {{server}}/hcql/admin/Books/201 { ID, title, author.name }
###
GET {{server}}/hcql/admin/Books/201 { ID, title, author{name} }
###
POST {{server}}/hcql/admin/Books?title=The Black Cat&author_ID=101
###
POST {{server}}/hcql/admin/Books?title=The Black Cat
Content-Type: application/json
{
"author_ID": 101
}
###
POST {{server}}/hcql/admin/Books
Content-Type: application/json
{
"title": "The Black Cat",
"author": { "ID": 101 }
}
###
PUT {{server}}/hcql/admin/Books/275?title=Catastrophe
###
PATCH {{server}}/hcql/admin/Books/275
Content-Type: application/json
{
"title": "Catastrophe"
}
###
GET {{server}}/hcql/admin/Authors { name, books { ID, title }}
###
GET {{server}}/hcql/admin/Books { ID, title, author.name as author } order by ID desc
###
// ------------------------------------
POST {{server}}/hcql/admin
Content-Type: application/json
{"SELECT": { "from": { "ref": ["Books"] }}}
###
POST {{server}}/hcql/admin
Content-Type: text/plain
SELECT from Authors {
name as author,
books {
title,
stock,
price,
currency { * }
}
}
where name like '%Bro%'
order by name asc
###
#
# Simple REST-style URLs as supported as well
#
GET {{server}}/hcql/admin/Books
###
GET {{server}}/hcql/admin/Books/201
###
#
# REST-style URLs can be combined with trailing CQL in the path, in plain
# text body, or with projections sent as application/json array
#
GET {{server}}/hcql/admin/Books order by stock desc
###
GET {{server}}/hcql/admin/Books { title as book, stock } order by stock desc
###
GET {{server}}/hcql/admin/Authors
Content-Type: text/plain
Accept-Language: fr
{
ID, name as author,
books {
title,
stock,
currency { * }
}
}
where name like '%Bro%'
order by name asc
###
GET {{server}}/hcql/admin/Books/201 { title, stock }
###
GET {{server}}/hcql/admin/Books order by stock desc
Content-Type: text/plain
{ title, stock }
###
#
# CQL adaptor also provides access to the underlying CSN schema
#
GET {{server}}/hcql/admin/$csn
###
#
# CQL adaptor also supports INSERTs, UPDATEs, DELETEs ...
#
POST {{server}}/hcql/admin
Content-Type: application/jsonin wonderland
{ "INSERT": {
"into": "Books",
"entries": [{
"title": "The Black Cat",
"author": { "ID": 150 }
}]
}}
###

View File

@@ -0,0 +1,26 @@
@server = http://localhost:4004
GET {{server}}/odata/v2/admin/Authors
Authorization: Basic alice:
###
GET {{server}}/odata/v2/admin/Authors?$select=ID,name&$expand=books($select=ID,title)
Authorization: Basic alice:
###
GET {{server}}/odata/v4/admin/Authors
Authorization: Basic alice:
###
GET {{server}}/odata/v4/admin/Authors?$select=ID,name&$expand=books($select=ID,title)
Authorization: Basic alice:
###
GET {{server}}/rest/admin/Authors
Authorization: Basic alice:
###
GET {{server}}/rest/admin/Authors?$select=ID,name&$expand=books($select=ID,title)
Authorization: Basic alice:
###

View File

@@ -0,0 +1,9 @@
@server = http://localhost:4004
GET {{server}}/rest/admin/Authors
Authorization: Basic alice:
###
GET {{server}}/rest/admin/Authors?$select=ID,name&$expand=books($select=ID,title)
Authorization: Basic alice:
###

View File

@@ -0,0 +1,4 @@
using { CatalogService, AdminService } from '@capire/bookstore';
annotate CatalogService with @hcql @odata @path:'browse' @requires:[];
annotate AdminService with @hcql @odata @path:'admin';

View File

@@ -62,24 +62,10 @@ annotate AdminService.Books with {
ValueListProperty: 'ID',
}
],
PresentationVariantQualifier: 'VH',
}
});
}
annotate AdminService.Genres with @UI: {
PresentationVariant #VH: {
$Type : 'UI.PresentationVariantType',
Visualizations : ['@UI.LineItem'],
RecursiveHierarchyQualifier: 'GenreHierarchy'
},
LineItem : [{
$Type: 'UI.DataField',
Value: name,
Label :'{i18n>Name}'
}],
};
// Hide ID because of the ValueHelp
annotate AdminService.Genres with {
ID @UI.Hidden;
@@ -124,4 +110,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; }

View File

@@ -4,7 +4,6 @@
using { sap.capire.bookshop as my } from '@capire/bookstore';
using { sap.common } from '@capire/common';
using { sap.common.Currencies } from '@sap/cds/common';
////////////////////////////////////////////////////////////////////////////
//
@@ -38,7 +37,7 @@ annotate my.Books with @(
author @ValueList.entity : 'Authors';
};
annotate Currencies with {
annotate common.Currencies with {
symbol @Common.Label : '{i18n>Currency}';
}
@@ -69,103 +68,6 @@ annotate my.Books with {
image @title: '{i18n>Image}';
}
////////////////////////////////////////////////////////////////////////////
//
// Computed Fields for Tree Tables
//
// DISCLAIMER: The below are an alpha version implementation and will change in final release !!!
//
aspect Hierarchy {
LimitedDescendantCount : Integer64 = null;
DistanceFromRoot : Integer64 = null;
DrillState : String = null;
Matched : Boolean = null;
MatchedDescendantCount : Integer64 = null;
LimitedRank : Integer64 = null;
}
annotate Hierarchy with @Capabilities.FilterRestrictions.NonFilterableProperties: [
'LimitedDescendantCount',
'DistanceFromRoot',
'DrillState',
'Matched',
'MatchedDescendantCount',
'LimitedRank'
];
annotate Hierarchy with @Capabilities.SortRestrictions.NonSortableProperties: [
'LimitedDescendantCount',
'DistanceFromRoot',
'DrillState',
'Matched',
'MatchedDescendantCount',
'LimitedRank'
];
extend my.Genres with Hierarchy;
////////////////////////////////////////////////////////////////////////////
//
// Genres Tree Table Annotations
//
// DISCLAIMER: The below are an alpha version implementation and will change in final release !!!
//
annotate my.Genres with @Aggregation.RecursiveHierarchy #GenreHierarchy: {
$Type : 'Aggregation.RecursiveHierarchyType',
NodeProperty : ID, // identifies a node
ParentNavigationProperty: parent // navigates to a node's parent
};
annotate my.Genres with @Hierarchy.RecursiveHierarchy #GenreHierarchy: {
$Type : 'Hierarchy.RecursiveHierarchyType',
LimitedDescendantCount: LimitedDescendantCount,
DistanceFromRoot : DistanceFromRoot,
DrillState : DrillState,
Matched : Matched,
MatchedDescendantCount: MatchedDescendantCount,
LimitedRank : LimitedRank
};
annotate my.Genres with @(
readonly,
cds.search: {name}
);
////////////////////////////////////////////////////////////////////////////
//
// Genres List
//
annotate my.Genres with @(
Common.SemanticKey : [name],
UI : {
SelectionFields : [name],
LineItem : [
{ Value : name, Label : '{i18n>Name}' },
],
}
);
////////////////////////////////////////////////////////////////////////////
//
// Genre Details
//
annotate my.Genres with @(UI : {
Identification : [{ Value: name}],
HeaderInfo : {
TypeName : '{i18n>Genre}',
TypeNamePlural : '{i18n>Genres}',
Title : { Value: name },
Description : { Value: ID }
}
});
////////////////////////////////////////////////////////////////////////////
//
// Genres Elements
//
annotate my.Genres with {
name @title: '{i18n>Genre}';
}
////////////////////////////////////////////////////////////////////////////
//
// Authors List

View File

@@ -0,0 +1,33 @@
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}';
}
// Lists
annotate Genres with @(
Common.SemanticKey : [name],
UI.SelectionFields : [name],
UI.LineItem : [
{ Value: name, Label: '{i18n>Name}' },
],
);
// Details
annotate Genres with @(UI : {
Identification : [{ Value: name }],
HeaderInfo : {
TypeName : '{i18n>Genre}',
TypeNamePlural : '{i18n>Genres}',
Title : { Value: name },
Description : { Value: ID }
}
});
// Tree Views
// annotate AdminService.Genres with @hierarchy; // upcomming simplification
using from './tree-view';
using from './value-help';

View File

@@ -0,0 +1,42 @@
using { AdminService } from '@capire/bookstore';
////////////////////////////////////////////////////////////////////////////
//
// Genres Tree View
//
// Tell Fiori about the structure of the hierarchy
annotate AdminService.Genres with @Aggregation.RecursiveHierarchy #GenresHierarchy : {
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.Genres with @(
// The columns expected by Fiori to be present in hierarchy entities
Hierarchy.RecursiveHierarchy #GenresHierarchy : {
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,
};

View File

@@ -0,0 +1,6 @@
// Value help with Tree View
using from '../admin-books/fiori-service';
annotate AdminService.Books:genre with @Common.ValueList.PresentationVariantQualifier: 'VH';
annotate AdminService.Genres with @UI.PresentationVariant #VH: {
RecursiveHierarchyQualifier : 'GenresHierarchy',
};

View File

@@ -51,7 +51,7 @@
"earlyRequests": true,
"groupProperties": {
"default": {
"submit": "Auto"
"submit": "Auto"
}
}
}
@@ -82,17 +82,17 @@
"Genres": {
"detail": {
"route": "GenresDetails"
}
}
}
},
"controlConfiguration": {
"@com.sap.vocabularies.UI.v1.LineItem": {
"tableSettings": {
"hierarchyQualifier": "GenreHierarchy",
"type": "TreeTable"
}
}
}
"@com.sap.vocabularies.UI.v1.LineItem": {
"tableSettings": {
"hierarchyQualifier": "GenresHierarchy",
"type": "TreeTable"
}
}
}
}
}
},
@@ -121,4 +121,4 @@
"registrationIds": [],
"archeType": "transactional"
}
}
}

View File

@@ -1,6 +0,0 @@
// Add routes to UIs from imported packages
module.exports = (app) => {
app.serve ('/bookshop') .from ('@capire/bookshop','app/vue')
app.serve ('/reviews') .from ('@capire/reviews','app/vue')
app.serve ('/orders') .from('@capire/orders','app/orders')
}

View File

@@ -5,6 +5,7 @@
using from './admin-authors/fiori-service';
using from './admin-books/fiori-service';
using from './browse/fiori-service';
using from './genres/fiori-service';
using from './common';
using from '@capire/bookstore/srv/mashup';

View File

@@ -1 +0,0 @@
require('./srv/server')

View File

@@ -7,12 +7,18 @@
"@capire/orders": "*",
"@capire/common": "*",
"@capire/data-viewer": "*",
"@cap-js/hana": ">=1",
"@sap-cloud-sdk/http-client": "^4",
"@sap-cloud-sdk/resilience": "^4",
"@sap/cds": ">=5",
"express": "^4.17.1",
"@cap-js/hana": "^1",
"@sap/cds-mtxs": "^2"
"express": "^4.17.1"
},
"devDependencies": {
"@cap-js/sqlite": ">=1"
},
"scripts": {
"start": "cds-serve",
"watch": "cds watch"
},
"cds": {
"requires": {
@@ -26,13 +32,20 @@
},
"messaging": true,
"db": true,
"multitenancy": true,
"auth": "xsuaa"
"db-ext": {
"[development]": {
"model": "db/sqlite"
},
"[production]": {
"model": "db/hana"
}
}
},
"log": { "service": true }
},
"scripts": {
"start": "cds-serve"
}
"sapux": [
"app/admin-authors",
"app/admin-books",
"app/browse"
]
}

2
bookstore/server.js Normal file
View File

@@ -0,0 +1,2 @@
require('./srv/mashup')
require('./srv/trees')

View File

@@ -1,10 +1,16 @@
const cds = require ('@sap/cds')
// Add routes to UIs from imported packages
if (!cds.env.production) cds.once ('bootstrap', require('../app/routes'))
if (!cds.env.production) cds.once ('bootstrap', (app) => {
app.serve ('/bookshop') .from ('@capire/bookshop','app/vue')
app.serve ('/reviews') .from ('@capire/reviews','app/vue')
app.serve ('/orders') .from('@capire/orders','app/orders')
})
// Mashing up bookshop services with required services...
cds.once ('served', async ()=>{ // called by server.js
cds.once ('served', async ()=>{
const CatalogService = await cds.connect.to ('CatalogService')
const ReviewsService = await cds.connect.to ('ReviewsService')

50
bookstore/srv/trees.js Normal file
View File

@@ -0,0 +1,50 @@
const cds = require('@sap/cds/lib')
// PoC for simplified Fiori Tree Views
cds.on('compile.for.runtime', csn => {
for (let each of cds.linked(csn).definitions) {
if (each.is_entity && each._service && each['@hierarchy']) _hierarchy (each)
}
})
const _hierarchy = entity => {
// Add annotations explaining the hierarchy structure to Fiori
const Qualifier = entity.name.slice (entity._service.name.length+1) + 'Hierarchy'
const parent = _parent4(entity)
entity[`@Aggregation.RecursiveHierarchy#${Qualifier}.ParentNavigationProperty`] ??= {'=': parent.name }
entity[`@Aggregation.RecursiveHierarchy#${Qualifier}.NodeProperty`] ??= {'=': parent.keys[0].ref[0] }
// Add expected hierarchy elements to the entity
const columns = entity.projection.columns ??= ['*']
const elements = entity.elements
for (let e of Hierarchy.elements) {
entity[`@Hierarchy.RecursiveHierarchy#${Qualifier}.${e.name}`] = {'=': e.name }
if (e.name in elements) continue
const { name, value, ...rest } = e
elements[e.name] = Object.defineProperty ({ __proto__:e, ...rest }, 'parent', { value: entity })
columns.push ({ ...value, as: name, cast: { type: e.type } })
}
// Disable filter and sort for hierarchy elements
entity['@Capabilities.FilterRestrictions.NonFilterableProperties'] =
entity['@Capabilities.SortRestrictions.NonSortableProperties'] =
Object.keys (Hierarchy.elements)
}
const _parent4 = entity => {
const parent = entity['@hierarchy.parent'] || entity['@hierarchy.via']
if (parent) return entity.elements [parent['=']||parent]
else for (let e of entity.elements) // use first recursive uplink association
if (e.is2one && e._target === entity) return e
}
const { Hierarchy } = cds.linked `aspect Hierarchy {
LimitedDescendantCount : Int16 = null;
DistanceFromRoot : Int16 = null;
DrillState : String = null;
LimitedRank : Int16 = null;
}`.definitions

13
common/currencies.cds Normal file
View File

@@ -0,0 +1,13 @@
using { sap } from '@sap/cds/common';
extend sap.common.Currencies with {
// Currencies.code = ISO 4217 alphabetic three-letter code
// with the first two letters being equal to ISO 3166 alphabetic country codes
// See also:
// [1] https://www.iso.org/iso-4217-currency-codes.html
// [2] https://www.currency-iso.org/en/home/tables/table-a1.html
// [3] https://www.ibm.com/support/knowledgecenter/en/SSZLC2_7.0.0/com.ibm.commerce.payments.developer.doc/refs/rpylerl2mst97.htm
numcode : Integer;
exponent : Integer; //> e.g. 2 --> 1 Dollar = 10^2 Cent
minor : String; //> e.g. 'Cent'
}

View File

@@ -1,45 +1,2 @@
using { sap } from '@sap/cds/common';
extend sap.common.Currencies with {
// Currencies.code = ISO 4217 alphabetic three-letter code
// with the first two letters being equal to ISO 3166 alphabetic country codes
// See also:
// [1] https://www.iso.org/iso-4217-currency-codes.html
// [2] https://www.currency-iso.org/en/home/tables/table-a1.html
// [3] https://www.ibm.com/support/knowledgecenter/en/SSZLC2_7.0.0/com.ibm.commerce.payments.developer.doc/refs/rpylerl2mst97.htm
numcode : Integer;
exponent : Integer; //> e.g. 2 --> 1 Dollar = 10^2 Cent
minor : String; //> e.g. 'Cent'
}
/**
* The Code Lists below are designed as optional extensions to
* the base schema. Switch them on by adding an Association to
* one of the code list entities in your models or by:
* annotate sap.common.Countries with @cds.persistence.skip:false;
*/
context sap.common.countries {
extend sap.common.Countries {
regions : Composition of many Regions on regions._parent = $self.code;
}
entity Regions : sap.common.CodeList {
key code : String(5); // ISO 3166-2 alpha5 codes, e.g. DE-BW
children : Composition of many Regions on children._parent = $self.code;
cities : Composition of many Cities on cities.region = $self;
_parent : String(11);
}
entity Cities : sap.common.CodeList {
key code : String(11);
region : Association to Regions;
districts : Composition of many Districts on districts.city = $self;
}
entity Districts : sap.common.CodeList {
key code : String(11);
city : Association to Cities;
}
}
using from './currencies';
using from './regions';

22
common/regions.cds Normal file
View File

@@ -0,0 +1,22 @@
using { sap.common } from '@sap/cds/common';
namespace sap.common.countries;
extend common.Countries {
regions : Composition of many Regions on regions._parent = $self.code;
}
entity Regions : common.CodeList {
key code : String(5); // ISO 3166-2 alpha5 codes, e.g. DE-BW
children : Composition of many Regions on children._parent = $self.code;
cities : Composition of many Cities on cities.region = $self;
_parent : String(11);
}
entity Cities : common.CodeList {
key code : String(11);
region : Association to Regions;
districts : Composition of many Districts on districts.city = $self;
}
entity Districts : common.CodeList {
key code : String(11);
city : Association to Cities;
}

1
db
View File

@@ -1 +0,0 @@
shared-db/db

View File

@@ -1,195 +0,0 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="357px" height="283px" viewBox="-0.5 -0.5 357 283" content="&lt;mxfile&gt;&lt;diagram id=&quot;QQJxv4aCTC7ZgE7HHOvM&quot; name=&quot;Page-1&quot;&gt;7VrZcqM4FP0av7q0L4+T9DIvU9VVeZhnFtlQwRYly7HTX98XgzBgOpNJG7eZGlKVwNECuudwdSSyoI+b41cXldlfNjXFgqD0uKCfFoQIIuF3BbzWACO6BtYuT2sInYGn/LupQRzQfZ6aXYPVkLe28HnZBxO73ZrE97DIOXvoV1vZIu0BZbQ2vceogKckKsxFtb/z1Gc1qsKwKvxPk6+zcGcsmvHFUfK8dna/be63IBQxXpdtotBRc9NdFqX20IHo5wV9dNb6+mxzfDRFFdd+zL78pLR9aGe2/j0NSN3gJSr2zbgXDCVRmTtTNSIi2pQL+rCNd9UfuC6g24fYwdnad5EAxNY+7zJbhgLoJT5XPg3Zv4YYw+jL6jQzx2htt1ClNC7fGG/cGf0WIAjOwyHLvXkqo6RqdgDhAZb5TQFXGE5X+dEELVXXu2fjkyri6FRYFI+2sO50c7paGZEkVSXv7LPplKRSxwi1JYF+0g6hG98m5C/GeXPsQE28vxoLD+9eoUpTSiSrm4QXQ9L6+nCWmW7kkXUUphosaoS9bns+8wsnDcXjdNNJ6Pa2an73fKvEjPMdK874zfimktyMb3Ztvp15yQ2k1rtnO+VGpWyMbUViKsRUbFOB+2xjfTO2+bXZTuxmA8TdPdkrXv1UuN36Dl4fYyIQp+NWImDhRbyBCMS1RWBdatwc3vjIqNVofheJMvFqKrKxEr+NbHlJ9pATs03/qOwwXCVFtNvlST/EvZBeBgiaN/GXp/LI+d71INRfTsdbgd3ZvUtML2FBp2vjew7FpMGd/yT4neDykeAGzJki8vlL39OPRby5wzebw/OeuSW4P3lzRPp91MNpmnWN9kVPYmD7+KCnOgoXPZ0k0A78XapQ81aFuHdVwKu75Iq2B+knAKrJslNKqfyYZIhmS4ZFewzXDQgvO6VC0Kn0pOetJzJzPTH+NtHX0hN7W7bX01PY4pmroNjMBcWHgppET3ygJzaZnIJlu5rl3e3Lssj/d73/wvXecp2LyUj+GFD4BJ2A4tD9M2hwys1oVtJC0miyRaoeEHjDbSk8sg85pwkgCLA7A4QsNI8pYOgp5CA7T+QpyGCqueIkMLLVOXdJibtSFAaqJVKcICw1ZIuw+dAuRzQoQSKGKFeSsY+aVIyXRGMmtSJIEBk+jrRrKw2yJpprwTAYmek86shm6qz0FL6Z3q1JxVpAClKnL8MaCc4HmUMuYaUDVhXWuUroD267EFClolhKLhHSlA1uwtmSUsGY4lphitRkarr6ruwqty7/T5ubCyczovl3f3Qjt3Q3974rO0gA/5hL6IjbEb/V3Ei9FFIpyBuKcKF0f5KozA3lEqYQLDimUvyCuaGQSSFzYMkoHtwFvI1gkGGwokwJWHBdKXvA5fkfQOrq5/+woZ9/AA==&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(0, 68, 85);">
<defs/>
<g>
<path d="M 199 202 L 249 202 L 269 242 L 249 282 L 199 282 L 179 242 Z" fill="#ffe6cc" stroke="#d79b00" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 242px; margin-left: 180px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
@capire/
<br/>
<b>
bookshop
</b>
</div>
</div>
</div>
</foreignObject>
<text x="224" y="246" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
<path d="M 199 101 L 249 101 L 269 141 L 249 181 L 199 181 L 179 141 Z" fill="#f8cecc" stroke="#b85450" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 141px; margin-left: 180px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
@capire/
<br/>
<b>
bookstore
</b>
</div>
</div>
</div>
</foreignObject>
<text x="224" y="145" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
<path d="M 286 48 L 336 48 L 356 88 L 336 128 L 286 128 L 266 88 Z" fill="#d5e8d4" stroke="#82b366" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 88px; margin-left: 267px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
@capire/
<br/>
<b>
reviews
</b>
</div>
</div>
</div>
</foreignObject>
<text x="311" y="92" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
<path d="M 286 153 L 336 153 L 356 193 L 336 233 L 286 233 L 266 193 Z" fill="#f5f5f5" stroke="#666666" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 193px; margin-left: 267px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
@capire/
<br/>
<b>
common
</b>
</div>
</div>
</div>
</foreignObject>
<text x="311" y="197" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
<path d="M 111 153 L 161 153 L 181 193 L 161 233 L 111 233 L 91 193 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 193px; margin-left: 92px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
@capire/
<br/>
<b>
orders
</b>
</div>
</div>
</div>
</foreignObject>
<text x="136" y="197" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
<path d="M 276.35 172.29 L 266.36 166.32" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 260.57 162.86 L 270.6 163.61 L 266.36 166.32 L 265.98 171.34 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 170.74 172.47 L 181.53 166.1" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 187.34 162.66 L 181.88 171.12 L 181.53 166.1 L 177.3 163.37 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 224 202 L 224 189.99" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 224 183.24 L 228.5 192.24 L 224 189.99 L 219.5 192.24 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 276.51 109.01 L 266.17 115.31" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 260.4 118.82 L 265.75 110.3 L 266.17 115.31 L 270.43 117.98 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 111 48 L 161 48 L 181 88 L 161 128 L 111 128 L 91 88 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 88px; margin-left: 92px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
@capire/
<br/>
<b>
suppliers
</b>
</div>
</div>
</div>
</foreignObject>
<text x="136" y="92" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
<path d="M 21 101 L 71 101 L 91 141 L 71 181 L 21 181 L 1 141 Z" fill="#e1d5e7" stroke="#9673a6" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 141px; margin-left: 2px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<b>
S/4
</b>
</div>
</div>
</div>
</foreignObject>
<text x="46" y="145" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
S/4
</text>
</switch>
</g>
<path d="M 80.76 120.53 L 93.49 113.03" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 99.31 109.61 L 93.84 118.05 L 93.49 113.03 L 89.27 110.3 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 80.91 161.17 L 93.31 168.33" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 99.15 171.71 L 89.11 171.1 L 93.31 168.33 L 93.61 163.31 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 170.59 108.83 L 181.72 115.53" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 187.5 119.02 L 177.47 118.23 L 181.72 115.53 L 182.11 110.52 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 199 1 L 249 1 L 269 41 L 249 81 L 199 81 L 179 41 Z" fill="#e1d5e7" stroke="#9673a6" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 41px; margin-left: 180px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
@capire/
<br/>
<b>
fiori
</b>
</div>
</div>
</div>
</foreignObject>
<text x="224" y="45" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
<path d="M 224 101 L 224 89.99" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 224 83.24 L 228.5 92.24 L 224 89.99 L 219.5 92.24 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
<a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
Text is not SVG - cannot display
</text>
</a>
</switch>
</svg>

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -1,212 +0,0 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="368px" height="282px" viewBox="-0.5 -0.5 368 282" content="&lt;mxfile&gt;&lt;diagram id=&quot;QQJxv4aCTC7ZgE7HHOvM&quot; name=&quot;Page-1&quot;&gt;7Zpbc9o4FIB/DY9hdL88JqRJH9ppd9mZndk3YwvwxCBXmIT01+9xLNvYMaEl4ZIUeLB1JOt2viMdXXp0MFvduiCdfrWRSXoERaseve4RgpnU8Mglj4VEIF4IJi6OChGqBcP4p/FfltJlHJmFlxWizNoki9OmMLTzuQmzhixwzj40k41tEjUEaTAxzwTDMEieS/+No2xaSBWRtfyziSfTsmQsfINnQZnYt2QxDSL7sCain3p04KzNirfZamCSvPOa/XKzIbaqmDPz7Fc+mJDb2+X19NuX/778vEB/LX+gO3vhc7kPkqVvcI+IBPK7GuVVzh59P4gfy7yeV2M7zy4WT1q6hAQYp6Dpqzoe3ib588rau8XUpmVuUK1RGVeV4F5VxGWa+o6tsiDQx2n+OjWrYGLnkCo1Lp6ZzLha+r0UgQquHqZxZoZpEOafPQDDIJtmswRCOK9MvDIllUU4SQY2se6pPDoeGxGGIF9kzt6ZtZhI6hFCVUzJDvENvAlmcZKbxMDO4hAaMQzmC3h8HfoEZZm4DPtGoqceaGu+VKNxmVmtiTwJt8ZCg90jJPGxhPtPvFlSLYrwQw259uBO1/hWXhZ4s5pUOdfkwYuH7zdAJBtBXKTB/FWgvHlGowblmXVmHelm2i7wQVbUZQ3kNzGJDQUc30xUaLrNZKQ443syE+iCMJ5P/oFRiF7z/dgN0fK4dkP3bzevmwn+NvexgVl4fxPB0Lj7ODQf3IYiblTEumxIkREVYh829Hp7oaxlL0wd117YSw5PoWrop5nNTWcbs4XkOsiCo9NhMPAhu+jQQtLgndBBGT8uHfzUR9NvLjLuPJj+mYMpFidmLqLDXFqaNfPoMl+GQyhMgsUiDpuKanZzLoEvfCcW41ngska4pTA+yP/7U8/CLl1ots8oUM+JybavcEzU2HB4ruw1ZfIOZZYyZ5Igi++b2xRdGvYlfLcxtKxmCesmTKzc0ijzKBruP1vfV2jnRNqjuGzlVHTNs5yekKsavjuF8kxhNXO9MwoJl32uaPUjokkSlv21WEp3RJRI3GdYVD/JmsUQ0V+LFYIelF915rfaiPxg/MqXwXorfsXLZrJnfvWZ32of5mPxyw7DLzsuv+VR0+mu+obLNE3i88LvvPDrncYuGt58bvhqkxlCjdjJ8hMYNe48yRChMqPxRn7aeGznyTey45z3t/kRvOkvIHxkfMjZZaiNaKvPUE5Q78NpaDu95WS/Z6e3rMWhnIaug7czwpsS8pMiGANaEikOs5DUVJJy66tEizIgTyKGKFeSsR29XqxUn+j8CpQiSBApabMUwsCMiOZaMEw4P7DT23UQ9ufxi36R39NatmFJYYhV+aat1kjw1vQuSR+WapxjhrASmuyKr4ABFkvJJUK6OmuoCtF9SgVjimuFKVKHpffkD+puYuvifd9++9BLtfF4TDbcrRMjwfeyVDvMpSF87Mt2+HxwV4/p293v03JeCBd9wmE8Fk+neKp1+IZ1n2kYjyV4FAIcmJ237FBfMsEZlVIphHXLd4ElABIaE8byKyak5ePvPPxDsL4RXSSv75XTT/8D&lt;/diagram&gt;&lt;/mxfile&gt;">
<defs/>
<g>
<path d="M 207 201 L 257 201 L 277 241 L 257 281 L 207 281 L 187 241 Z" fill="#ffe6cc" stroke="#d79b00" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 241px; margin-left: 188px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<b style="font-size: 11px;">
Bookshop
</b>
<br style="font-size: 11px;"/>
App
</div>
</div>
</div>
</foreignObject>
<text x="232" y="244" fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-size="11px" text-anchor="middle">
Bookshop...
</text>
</switch>
</g>
<path d="M 207 102 L 257 102 L 277 142 L 257 182 L 207 182 L 187 142 Z" fill="#f8cecc" stroke="#b85450" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 145px; margin-left: 188px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<span style="font-size: 11px;">
<span style="font-size: 11px;">
<b>
Bookstore
<br/>
</b>
</span>
App
<br style="font-size: 11px;"/>
</span>
</div>
</div>
</div>
</foreignObject>
<text x="232" y="148" fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-size="11px" text-anchor="middle">
Bookstore...
</text>
</switch>
</g>
<path d="M 297 53 L 347 53 L 367 93 L 347 133 L 297 133 L 277 93 Z" fill="#d5e8d4" stroke="#82b366" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 93px; margin-left: 278px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<span style="font-size: 11px;">
<b style="font-size: 11px;">
Reviews
</b>
<br style="font-size: 11px;"/>
Service
<br style="font-size: 11px;"/>
</span>
</div>
</div>
</div>
</foreignObject>
<text x="322" y="96" fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-size="11px" text-anchor="middle">
Reviews...
</text>
</switch>
</g>
<path d="M 297 150 L 347 150 L 367 190 L 347 230 L 297 230 L 277 190 Z" fill="#e1d5e7" stroke="#9673a6" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 190px; margin-left: 278px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<b>
Common
</b>
<br/>
Data
</div>
</div>
</div>
</foreignObject>
<text x="322" y="193" fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-size="11px" text-anchor="middle">
Common...
</text>
</switch>
</g>
<path d="M 117 150 L 167 150 L 187 190 L 167 230 L 117 230 L 97 190 Z" fill="#d5e8d4" stroke="#82b366" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 190px; margin-left: 98px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<span style="font-size: 11px;">
<b style="font-size: 11px;">
Orders
</b>
<br style="font-size: 11px;"/>
Service
<br style="font-size: 11px;"/>
</span>
</div>
</div>
</div>
</foreignObject>
<text x="142" y="193" fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-size="11px" text-anchor="middle">
Orders...
</text>
</switch>
</g>
<path d="M 286.47 171.05 L 273.81 164.3" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 268.51 161.47 L 277.45 161.71 L 273.81 164.3 L 273.69 168.77 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 177.53 171.05 L 190.19 164.3" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 195.49 161.47 L 190.31 168.77 L 190.19 164.3 L 186.55 161.71 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 232 201 L 232 189.12" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 232 183.12 L 236 191.12 L 232 189.12 L 228 191.12 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 286.63 112.26 L 273.62 119.34" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 268.35 122.21 L 273.47 114.87 L 273.62 119.34 L 277.29 121.9 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 117 53 L 167 53 L 187 93 L 167 133 L 117 133 L 97 93 Z" fill="#d5e8d4" stroke="#82b366" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 93px; margin-left: 98px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<span style="font-size: 11px;">
<b style="font-size: 11px;">
Suppliers
</b>
<br style="font-size: 11px;"/>
Service
<br style="font-size: 11px;"/>
</span>
</div>
</div>
</div>
</foreignObject>
<text x="142" y="96" fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-size="11px" text-anchor="middle">
Suppliers...
</text>
</switch>
</g>
<path d="M 21 106 L 71 106 L 91 146 L 71 186 L 21 186 L 1 146 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 146px; margin-left: 2px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
<span style="font-size: 11px;">
S/4
</span>
</div>
</div>
</div>
</foreignObject>
<text x="46" y="149" fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-size="11px" text-anchor="middle" font-weight="bold">
S/4
</text>
</switch>
</g>
<path d="M 81.27 126.53 L 100.5 115.91" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 105.76 113.01 L 100.69 120.38 L 100.5 115.91 L 96.82 113.37 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 82.61 162.78 L 98.92 170.25" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 104.37 172.75 L 95.43 173.06 L 98.92 170.25 L 98.77 165.79 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 177.37 112.26 L 190.38 119.34" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 195.65 122.21 L 186.71 121.9 L 190.38 119.34 L 190.53 114.87 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 207 1 L 257 1 L 277 41 L 257 81 L 207 81 L 187 41 Z" fill="#fff2cc" stroke="#d6b656" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 44px; margin-left: 188px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<span style="font-size: 11px;">
<b style="font-size: 11px;">
Fiori
</b>
<br style="font-size: 11px;"/>
App
<br style="font-size: 11px;"/>
</span>
</div>
</div>
</div>
</foreignObject>
<text x="232" y="47" fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-size="11px" text-anchor="middle">
Fiori...
</text>
</switch>
</g>
<path d="M 232 102 L 232 88.12" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 232 82.12 L 236 90.12 L 232 88.12 L 228 90.12 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all"/>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
<a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
Text is not SVG - cannot display
</text>
</a>
</switch>
</svg>

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -1 +0,0 @@
cds.requires.[hybrid].messaging.kind=file-based-messaging

View File

@@ -1,3 +0,0 @@
/*
All annotations needed for UI5 Tree Table View are located in '../common'
*/

View File

@@ -1 +0,0 @@
using from './db/common';

View File

@@ -1,43 +0,0 @@
{
"name": "@capire/fiori",
"version": "1.0.0",
"dependencies": {
"@capire/bookstore": "*",
"@sap/cds": ">=5",
"express": "^4.17.1"
},
"devDependencies": {
"@cap-js/sqlite": "^1"
},
"scripts": {
"start": "cds-serve",
"watch": "cds watch"
},
"cds": {
"requires": {
"ReviewsService": {
"kind": "odata",
"model": "@capire/reviews"
},
"OrdersService": {
"kind": "odata",
"model": "@capire/orders"
},
"messaging": true,
"db": true,
"db-ext": {
"[development]": {
"model": "db/sqlite"
},
"[production]": {
"model": "db/hana"
}
}
}
},
"sapux": [
"app/admin-authors",
"app/admin-books",
"app/browse"
]
}

View File

@@ -1,32 +0,0 @@
const cds = require('@sap/cds/lib')
if (cds.requires.db?.kind === 'sqlite') {
cds.on ('serving:AdminService', srv => srv.prepend(() => {
const {Genres} = srv.entities
// Register a simplistic handler for hierarchical queries
srv.on('READ', Genres, (req,next) => {
const q = req.query
// Expand query on a single row
if (q.SELECT.recurse?.where?.[0].ref[0] === 'Distance') {
q.SELECT.where[0] = 'parent_ID'
// Initial query
} else if (!q.SELECT.search && !is_count(q)) {
q.SELECT.where ??= [ 'parent_ID is null' ]
}
// Use scalar subselect for DrillState
q.SELECT.from.as = 'g'
q.SELECT.columns = q.SELECT.columns.map (c => {
if (c.ref == 'DrillState') return { xpr:[`
CASE WHEN ( SELECT count(1) from ${Genres} where parent_ID = g.ID ) > 0
THEN 'collapsed' ELSE 'leaf' END`
], as: 'DrillState' }
else return c
})
// Suppress error message: Feature "recurse" queries not supported.
delete q.SELECT.__proto__.recurse
delete q.SELECT.recurse
return next()
})
}))
}
const is_count = q => q.SELECT.columns?.length === 1 && q.SELECT.columns[0].func === 'count'

View File

@@ -9,7 +9,7 @@ build-parameters:
- builder: custom
commands:
- npm ci
- npx cds build --production
- npx cds build shared-db --for hana --production
- npx cds build orders --for nodejs --production --ws-pack
- npx cds build reviews --for nodejs --production
- npx cds build bookstore --for nodejs --production --ws-pack
@@ -78,6 +78,14 @@ modules:
- name: samples-auth
- name: samples-destination
- name: samples-db-deployer
type: hdb
path: shared-db/gen/db
parameters:
buildpack: nodejs_buildpack
requires:
- name: samples-db
- name: samples
type: approuter.nodejs
path: .deploy/app-router
@@ -85,8 +93,6 @@ modules:
keep-existing-routes: true
disk-quota: 256M
memory: 256M
properties:
TENANT_HOST_PATTERN: "^(.*)-${default-uri}"
requires:
- name: orders-api
group: destinations
@@ -106,17 +112,7 @@ modules:
name: bookstore-api # must be used in xs-app.json as well
url: ~{srv-url}
forwardAuthToken: true
- name: mtx-api
group: destinations
properties:
name: mtx-api # must be used in xs-app.json as well
url: ~{mtx-url}
- name: samples-auth
provides:
- name: app-api
properties:
app-protocol: ${protocol}
app-uri: ${default-uri}
- name: destination-content
type: com.sap.application.content
@@ -149,27 +145,6 @@ modules:
TokenServiceInstanceName: samples-auth
TokenServiceKeyName: xsuaa-service-key
- name: samples-mtx
type: nodejs
path: gen/mtx/sidecar
build-parameters:
builder: npm
parameters:
instances: 1
memory: 256M
disk-quota: 512M
provides:
- name: mtx-api
properties:
mtx-url: ${default-url}
requires:
- name: samples-db
- name: samples-registry
- name: samples-auth
- name: app-api
properties:
SUBSCRIPTION_URL: ~{app-protocol}://\${tenant_subdomain}-~{app-uri}
resources:
- name: samples-messaging
type: org.cloudfoundry.managed-service
@@ -181,51 +156,23 @@ resources:
emname: bookstore-${org}-${space}
namespace: cap/samples/${space}
- name: samples-db
type: org.cloudfoundry.managed-service
type: com.sap.xs.hdi-container
parameters:
service: service-manager
service-plan: container
service: hana
service-plan: hdi-shared
- name: samples-auth
type: org.cloudfoundry.managed-service
processed-after:
- samples-messaging
requires:
- name: app-api
parameters:
service: xsuaa
service-plan: application
path: ./xs-security.json
config:
xsappname: samples-${org}-${space}
tenant-mode: shared
oauth2-configuration:
redirect-uris:
- https://*-~{app-api/app-uri}/**
tenant-mode: dedicated
- name: samples-destination
type: org.cloudfoundry.managed-service
parameters:
service: destination
service-plan: lite
- name: samples-registry
type: org.cloudfoundry.managed-service
requires:
- name: mtx-api
parameters:
service: saas-registry
service-plan: application
config:
xsappname: samples-${org}-${space}
appName: samples-${org}-${space}
displayName: samples-shared-db
description: CAP Samples with shared-db and multitenancy
category: 'Samples shared-db'
appUrls:
getDependencies: ~{mtx-api/mtx-url}/-/cds/saas-provisioning/dependencies
onSubscription: ~{mtx-api/mtx-url}/-/cds/saas-provisioning/tenant/{tenantId}
onSubscriptionAsync: true
onUnSubscriptionAsync: true
onUpdateDependenciesAsync: true
callbackTimeoutMillis: 300000 # Increase if your deployments are taking longer than that

View File

@@ -1,19 +0,0 @@
{
"name": "samples-mtx",
"dependencies": {
"@cap-js/hana": "^1",
"@sap/cds": "^8",
"@sap/cds-mtxs": "^2",
"@sap/xssec": "^4",
"express": "^4"
},
"devDependencies": {
"@cap-js/sqlite": "^1"
},
"scripts": {
"start": "cds-serve"
},
"cds": {
"profile": "mtx-sidecar"
}
}

View File

@@ -23,8 +23,8 @@
};
</script>
<script id="sap-ushell-bootstrap" src="https://sapui5.hana.ondemand.com/test-resources/sap/ushell/bootstrap/sandbox.js"></script>
<script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
<script id="sap-ushell-bootstrap" src="https://ui5.sap.com/test-resources/sap/ushell/bootstrap/sandbox.js"></script>
<script id="sap-ui-bootstrap" src="https://ui5.sap.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
data-sap-ui-compatVersion="edge"
data-sap-ui-theme="sap_horizon"

View File

@@ -2,18 +2,15 @@
"name": "@capire/orders",
"version": "1.0.0",
"dependencies": {
"@cap-js/hana": "^1",
"@cap-js/hana": ">=1",
"@capire/common": "*",
"@sap/cds": ">=5",
"@sap/xssec": "^4",
"@sap/cds-mtxs": "^2"
"@sap/xssec": "^4"
},
"cds": {
"requires": {
"messaging": true,
"db": true,
"multitenancy": true,
"auth": "xsuaa"
"db": true
}
},
"scripts": {

309
package-lock.json generated
View File

@@ -9,8 +9,7 @@
"version": "3.0.0",
"license": "SEE LICENSE IN LICENSE",
"workspaces": [
"./*",
"./etc/*"
"*"
],
"devDependencies": {
"@cap-js/cds-test": "^0"
@@ -24,14 +23,14 @@
"express": "^4.17.1"
},
"devDependencies": {
"@cap-js/sqlite": "*"
"@cap-js/sqlite": ">=1"
}
},
"bookstore": {
"name": "@capire/bookstore",
"version": "1.0.0",
"dependencies": {
"@cap-js/hana": "^1",
"@cap-js/hana": ">=1",
"@capire/bookshop": "*",
"@capire/common": "*",
"@capire/data-viewer": "*",
@@ -41,6 +40,9 @@
"@sap-cloud-sdk/resilience": "^4",
"@sap/cds": ">=5",
"express": "^4.17.1"
},
"devDependencies": {
"@cap-js/sqlite": ">=1"
}
},
"common": {
@@ -50,14 +52,14 @@
"@sap/cds": "*"
}
},
"etc/data-viewer": {
"inspectr": {
"name": "@capire/data-viewer",
"version": "0.1.0",
"dependencies": {
"@sap/cds": ">=5.0.4"
}
},
"etc/loggers": {
"loggers": {
"name": "@capire/loggers",
"version": "1.0.0",
"dependencies": {
@@ -65,24 +67,12 @@
"express": "^4.17.1"
}
},
"fiori": {
"name": "@capire/fiori",
"version": "1.0.0",
"dependencies": {
"@capire/bookstore": "*",
"@sap/cds": ">=5",
"express": "^4.17.1"
},
"devDependencies": {
"@cap-js/sqlite": "^1"
}
},
"node_modules/@cap-js/cds-test": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@cap-js/cds-test/-/cds-test-0.3.0.tgz",
"integrity": "sha512-qt6Y7cYjhYlbVOeqMJ1wiuxmkbfYbgXvU7uqyasikJn2s5Vf/A6cawROJfSKxPTsmbnLi5nyrCSFCliUYG0rww==",
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@cap-js/cds-test/-/cds-test-0.4.0.tgz",
"integrity": "sha512-l8Ad/rV5qXIjU9qyA3twcKDYUnT1Ru1402BHhjnMjeYD9GeCmoj/0KrRGFbQIW63zAbs3QFya9X4GMGd0qYesA==",
"dev": true,
"license": "SEE LICENSE IN LICENSE",
"license": "Apache-2.0",
"dependencies": {
"axios": "^1",
"chai": "^4.4.1",
@@ -101,29 +91,29 @@
}
},
"node_modules/@cap-js/db-service": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/@cap-js/db-service/-/db-service-1.19.1.tgz",
"integrity": "sha512-3IpyDq0sw0bI2SYzC+A6IwriU1sNFNRBmHj20yi4TfKaw1FMZJmdVhK8EjG0r3odEJrPcOy+gTWu4u0P85ISAg==",
"license": "SEE LICENSE",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@cap-js/db-service/-/db-service-2.2.0.tgz",
"integrity": "sha512-C5n8Qy8MwOGWjpXS44CskaEZt8YKrEEs4AtJyBSfJ6+aKMu/ynqpXh0Up4Ql0XX2Frq2PwNU8Ohai/04wxd46g==",
"license": "Apache-2.0",
"dependencies": {
"generic-pool": "^3.9.0"
},
"peerDependencies": {
"@sap/cds": ">=7.9"
"@sap/cds": ">=9"
}
},
"node_modules/@cap-js/hana": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@cap-js/hana/-/hana-1.8.1.tgz",
"integrity": "sha512-Fz0yU+ZuwJO0ZECwHk94QNkqOO0PDC1IcMlPyytdniQbmU6OfZyiT6yJuCgNj5NJSqZar4tQTYOk4It2EwZyng==",
"license": "SEE LICENSE",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@cap-js/hana/-/hana-2.1.1.tgz",
"integrity": "sha512-4N/ByOd1N++7IEVwoSKyIqEXEzuAJE1qhpWhr3JM4LPoeCpvlv+Eki/YLIvCB06O7/PO8d2569Emjml/TwaJhQ==",
"license": "Apache-2.0",
"dependencies": {
"@cap-js/db-service": "^1.19.0",
"@cap-js/db-service": "^2.1.1",
"hdb": "^0.19.5"
},
"peerDependencies": {
"@sap/cds": ">=8.2",
"@sap/hana-client": "2"
"@sap/cds": ">=9",
"@sap/hana-client": "^2"
},
"peerDependenciesMeta": {
"@sap/hana-client": {
@@ -132,17 +122,17 @@
}
},
"node_modules/@cap-js/sqlite": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@cap-js/sqlite/-/sqlite-1.10.0.tgz",
"integrity": "sha512-4LfBbQy/Omt7GgImwD5iIKnUsmuMIozL/XLMQjMCWryfe/RXMJBhpBW2qvZIg+tYL7ifgMrXXcbDUyKGzG+q/g==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@cap-js/sqlite/-/sqlite-2.0.2.tgz",
"integrity": "sha512-oNg2f56sfELshyp0eSmYYwG1lt4Zmc135sLIzS8iykHdRVxxJpTrPj0jx0Y4Hc6sfC9u25LRXVu/ZKqjm9Yu+Q==",
"dev": true,
"license": "SEE LICENSE",
"license": "Apache-2.0",
"dependencies": {
"@cap-js/db-service": "^1.19.0",
"better-sqlite3": "^11.0.0"
"@cap-js/db-service": "^2",
"better-sqlite3": "^12.0.0"
},
"peerDependencies": {
"@sap/cds": ">=7.6"
"@sap/cds": ">=9"
}
},
"node_modules/@capire/bookshop": {
@@ -158,15 +148,11 @@
"link": true
},
"node_modules/@capire/data-viewer": {
"resolved": "etc/data-viewer",
"link": true
},
"node_modules/@capire/fiori": {
"resolved": "fiori",
"resolved": "inspectr",
"link": true
},
"node_modules/@capire/loggers": {
"resolved": "etc/loggers",
"resolved": "loggers",
"link": true
},
"node_modules/@capire/orders": {
@@ -202,13 +188,16 @@
}
},
"node_modules/@eslint/js": {
"version": "9.24.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.24.0.tgz",
"integrity": "sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==",
"version": "9.31.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz",
"integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==",
"license": "MIT",
"peer": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://eslint.org/donate"
}
},
"node_modules/@sap-cloud-sdk/connectivity": {
@@ -265,22 +254,21 @@
}
},
"node_modules/@sap/cds": {
"version": "8.9.1",
"resolved": "https://registry.npmjs.org/@sap/cds/-/cds-8.9.1.tgz",
"integrity": "sha512-+KoY7Bw1Gc3vwK4X3CFCV+IAQO4QT0HRsaW/qgETeOGqjzbuf6KvUqlkDuPE5msdXwfz/EFDB9Vx9jTyTw581Q==",
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/@sap/cds/-/cds-9.1.0.tgz",
"integrity": "sha512-i5bAVbFzi1uN11O4U6SdPKzYDDxc+YDSWMiqt1ryxT0WYrrehJPg5pJQjy4AH1EgRIqa3eqK2RfmHS6SgkBOyg==",
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"@sap/cds-compiler": ">=5.1",
"@sap/cds-fiori": "^1",
"@sap/cds-foss": "^5.0.0"
"@sap/cds-compiler": "^6",
"@sap/cds-fiori": "^2",
"js-yaml": "^4.1.0"
},
"bin": {
"cds-deploy": "lib/dbs/cds-deploy.js",
"cds-serve": "bin/serve.js",
"cds-test": "bin/test.js"
"cds-serve": "bin/serve.js"
},
"engines": {
"node": ">=18"
"node": ">=20"
},
"peerDependencies": {
"@eslint/js": "^9",
@@ -297,51 +285,33 @@
}
},
"node_modules/@sap/cds-compiler": {
"version": "5.9.2",
"resolved": "https://registry.npmjs.org/@sap/cds-compiler/-/cds-compiler-5.9.2.tgz",
"integrity": "sha512-YpRUD3L0Ylg7KNoDqdCmsH1n6vt22Uvyvtc7Maj0wPl7haqeDOax2ouOAtqgJaYJfu83pcyx04sWLK6oH+Lh0w==",
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@sap/cds-compiler/-/cds-compiler-6.1.0.tgz",
"integrity": "sha512-s71fsxDZKqHn2xvoqoNst54K/BkBzCpiU+8xc0t3nMDXmsLzSC3VfygZGwGAZD8fkxUnXh8oL2XLHWKWcvcdNg==",
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"antlr4": "4.9.3"
},
"bin": {
"cdsc": "bin/cdsc.js",
"cdshi": "bin/cdshi.js",
"cdsse": "bin/cdsse.js"
},
"engines": {
"node": ">=18"
"node": ">=20"
}
},
"node_modules/@sap/cds-fiori": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@sap/cds-fiori/-/cds-fiori-1.4.1.tgz",
"integrity": "sha512-laoK+xfJRcJy+zWzUdgqOOy5V6lpUi9I3CN8yeGmMIktQ1ZsXc52814WvoWt4TWchY1/+rNYuWDl9Q8ttj4Y4w==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@sap/cds-fiori/-/cds-fiori-2.0.1.tgz",
"integrity": "sha512-KZVLWXndydgqdlao8OL1gtgd/XMgBdiKBmmgwGpBL1y4S21FOXglnWh6d3bnSZL/qwR3z50D+0PoGghjhayF0Q==",
"license": "SEE LICENSE IN LICENSE",
"peerDependencies": {
"@sap/cds": ">=7.6",
"@sap/cds": ">=8",
"express": ">=4"
}
},
"node_modules/@sap/cds-foss": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@sap/cds-foss/-/cds-foss-5.0.1.tgz",
"integrity": "sha512-q6h7LkEx6w9LswCIQzJJ2mnoyeGS8jrmBXN4I4+aECRL60mkLskoqGetot+2tX2xXGxCYJuo5v1dtSafwBqTRQ==",
"license": "See LICENSE in LICENSE",
"dependencies": {
"big.js": "^6.1.1",
"generic-pool": "^3.8.2",
"xmlbuilder": "^15.1.1",
"yaml": "^2.2.2"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@sap/xsenv": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/@sap/xsenv/-/xsenv-5.5.0.tgz",
"integrity": "sha512-+FIpnXjDrgtJaN6AxjDRIc5ONd4Yt5UarCqqzRiZjvJaknnkT+b6/ho/va/rg8UdiCAVxn8c4vMVhgjXGc/gmQ==",
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/@sap/xsenv/-/xsenv-5.6.1.tgz",
"integrity": "sha512-4pDpsYLNJsLUBWtTSG+TJ8ul5iY0dWDyJgTy2H/WZGZww9CSPLP/39x+syDDTjkggsmZAlo9t7y9TiXMmtAunw==",
"license": "SEE LICENSE IN LICENSE file",
"dependencies": {
"debug": "4.4.0",
@@ -376,9 +346,9 @@
"license": "MIT"
},
"node_modules/@sap/xssec": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@sap/xssec/-/xssec-4.6.0.tgz",
"integrity": "sha512-0VYDqFymsQnpztTBUmdJaUVgHK/wIOC1KR6BmcmRJLQ3HMqGpGju1zkeY/D7SCwuQ8djYp0GEDhJ60F4aN1H/g==",
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/@sap/xssec/-/xssec-4.9.0.tgz",
"integrity": "sha512-x2f1AvS9KDs3djtDsRgH4Md3Ze5vc2NZHAlpCf+oRokWaQCmMNmS57DE6Zm80IVCCzo1mr8VtSrjWMPTshfUpw==",
"license": "SAP DEVELOPER LICENSE AGREEMENT",
"dependencies": {
"debug": "^4.3.4",
@@ -386,20 +356,12 @@
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/express": ">=4"
},
"peerDependenciesMeta": {
"@types/express": {
"optional": true
}
}
},
"node_modules/@sap/xssec/node_modules/debug": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -453,14 +415,11 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/antlr4": {
"version": "4.9.3",
"resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.9.3.tgz",
"integrity": "sha512-qNy2odgsa0skmNMCuxzXhM4M8J1YDaPv3TI+vCdnOAanu0N982wBrSqziDKRDctEZLZy9VffqIZXc0UGjjSP/g==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=14"
}
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"license": "Python-2.0"
},
"node_modules/array-flatten": {
"version": "1.1.1",
@@ -509,9 +468,9 @@
"license": "MIT"
},
"node_modules/axios": {
"version": "1.8.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
"integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
@@ -541,28 +500,18 @@
"license": "MIT"
},
"node_modules/better-sqlite3": {
"version": "11.9.1",
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.9.1.tgz",
"integrity": "sha512-Ba0KR+Fzxh2jDRhdg6TSH0SJGzb8C0aBY4hR8w8madIdIzzC6Y1+kx5qR6eS1Z+Gy20h6ZU28aeyg0z1VIrShQ==",
"version": "12.2.0",
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.2.0.tgz",
"integrity": "sha512-eGbYq2CT+tos1fBwLQ/tkBt9J5M3JEHjku4hbvQUePCckkvVf14xWj+1m7dGoK81M/fOjFT7yM9UMeKT/+vFLQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"bindings": "^1.5.0",
"prebuild-install": "^7.1.1"
}
},
"node_modules/big.js": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz",
"integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==",
"license": "MIT",
"engines": {
"node": "*"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/bigjs"
"engines": {
"node": "20.x || 22.x || 23.x || 24.x"
}
},
"node_modules/bindings": {
@@ -716,6 +665,7 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/chai-subset/-/chai-subset-1.6.0.tgz",
"integrity": "sha512-K3d+KmqdS5XKW5DWPd5sgNffL3uxdDe+6GdnJh3AYPhwnBGRY5urfvfcbRtWIvvpz+KxkL9FeBB6MZewLUNwug==",
"deprecated": "functionality of this lib is built-in to chai now. see more details here: https://github.com/debitoor/chai-subset/pull/85",
"dev": true,
"license": "MIT",
"engines": {
@@ -961,9 +911,9 @@
}
},
"node_modules/detect-libc": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
"dev": true,
"license": "Apache-2.0",
"engines": {
@@ -1015,9 +965,9 @@
}
},
"node_modules/end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1207,14 +1157,15 @@
}
},
"node_modules/form-data": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
@@ -1479,6 +1430,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/jsonwebtoken": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
@@ -1508,12 +1471,12 @@
"license": "MIT"
},
"node_modules/jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
"integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
"license": "MIT",
"dependencies": {
"buffer-equal-constant-time": "1.0.1",
"buffer-equal-constant-time": "^1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
@@ -1740,9 +1703,9 @@
}
},
"node_modules/node-abi": {
"version": "3.74.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz",
"integrity": "sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==",
"version": "3.75.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.75.0.tgz",
"integrity": "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1808,12 +1771,12 @@
}
},
"node_modules/opossum": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/opossum/-/opossum-8.4.0.tgz",
"integrity": "sha512-YYamqKu48bZCSTJKSWLLO4SSk8tKN2Gg2z1sJZVzHJYVObMO/xQpIzAh6re9HCMHRdB1dJvBjJH18DW7xYOicg==",
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/opossum/-/opossum-8.5.0.tgz",
"integrity": "sha512-LZNvs+p9/ZbG4oN6unnjh4hTxkB0dyHKI2p7azVt8w+//GKDpfHss6WR7KebbpzGEssYwtSd8Mvwxqcmxg10NA==",
"license": "Apache-2.0",
"engines": {
"node": "^22 || ^21 || ^20 || ^18 || ^16"
"node": "^24 || ^22 || ^21 || ^20 || ^18 || ^16"
}
},
"node_modules/parseurl": {
@@ -1888,9 +1851,9 @@
"license": "MIT"
},
"node_modules/pump": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
"integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2012,9 +1975,9 @@
"license": "MIT"
},
"node_modules/semver": {
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -2261,9 +2224,9 @@
}
},
"node_modules/tar-fs": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz",
"integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz",
"integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2446,32 +2409,11 @@
"dev": true,
"license": "ISC"
},
"node_modules/xmlbuilder": {
"version": "15.1.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
"integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
"license": "MIT",
"engines": {
"node": ">=8.0"
}
},
"node_modules/yaml": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
"integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14"
}
},
"orders": {
"name": "@capire/orders",
"version": "1.0.0",
"dependencies": {
"@cap-js/hana": "^1",
"@cap-js/hana": ">=1",
"@capire/common": "*",
"@sap/cds": ">=5",
"@sap/xssec": "^4"
@@ -2481,7 +2423,7 @@
"name": "@capire/reviews",
"version": "1.0.0",
"dependencies": {
"@cap-js/hana": "^1",
"@cap-js/hana": ">=1",
"@sap/cds": ">=5",
"@sap/xssec": "^4.2.7",
"express": "^4.17.1"
@@ -2489,7 +2431,12 @@
},
"shared-db": {
"name": "@capire/shared-db",
"version": "3.0.0"
"version": "3.0.0",
"dependencies": {
"@capire/bookstore": "*",
"@capire/orders": "*",
"@capire/reviews": "*"
}
}
}
}

View File

@@ -5,8 +5,7 @@
"repository": "https://github.com/sap-samples/cloud-cap-samples.git",
"author": "daniel.hutzel@sap.com",
"workspaces": [
"./*",
"./etc/*"
"*"
],
"devDependencies": {
"@cap-js/cds-test": "^0"
@@ -15,11 +14,10 @@
"start": "cds watch bookshop --open http://localhost:4004",
"bookstore": "cds watch bookstore",
"bookshop": "cds watch bookshop",
"fiori": "cds watch fiori",
"orders": "cds watch orders",
"reviews": "cds watch reviews",
"lint": "npx eslint",
"test": "chest test",
"test": "chest",
"jest": "npx jest",
"mocha": "npx mocha",
"node:test": "node --test",
@@ -33,15 +31,5 @@
"timeout": 6666
},
"license": "SEE LICENSE IN LICENSE",
"private": true,
"dependencies": {
"@sap/cds-mtxs": "^2"
},
"cds": {
"profile": "with-mtx-sidecar",
"requires": {
"multitenancy": true,
"auth": "xsuaa"
}
}
}
"private": true
}

View File

@@ -2,14 +2,14 @@
# Welcome to cap/samples
Find here a collection of samples for the [SAP Cloud Application Programming Model](https://cap.cloud.sap) organized in a simplistic [monorepo setup](samples.md#all-in-one-monorepo).
Find here a collection of samples for the [SAP Cloud Application Programming Model](https://cap.cloud.sap) organized in a simplistic [monorepo setup](readme/samples.md#all-in-one-monorepo).
![](https://github.com/SAP-samples/cloud-cap-samples/workflows/CI/badge.svg)
## Get Started
Assumed you did your [initial setup of CAP Node.js](https://cap.cloud.sap/docs/get-started/#setup), simply copy & paste these lines to a terminal for a jumpstart:
```sh
git clone -q https://github.com/sap-samples/cloud-cap-samples cap/samples
cd cap/samples
@@ -21,7 +21,7 @@ npm start
After download and setup this starts the bookshop server and opens a browser window on _http://localhost:4004_ looking like that:
<p align="center">
<img width=480 src="etc/index-html.png" alt="bookshop showing up in browser" />
<img width=480 src="readme/index-html.png" alt="bookshop showing up in browser" />
</p>
Click on the *[/vue](http:/localhost:4004/vue)* link at the top to display the bookshop app (when asked to log in, type `alice` as user and leave the password field blank).
@@ -35,14 +35,11 @@ After the jumpstart, have a look into the enclosed sub folders/projects, which a
- [orders](orders) - a generic reuse service
- [common](common) - a reuse content package
- [bookstore](bookstore) - a composite app of the above
- [fiori](fiori) - Fiori elements UIs for the bookstore
- [etc/*](etc) - Plugins adding cross-cutting concerns
- [test](test) - Tests for all the above
> _see also [samples.md](samples.md)_
> _see also [samples.md](readme/samples.md)_
<p align="center">
<img width=480 src="etc/samples.drawio.svg">
<img width=480 src="readme/samples.drawio.svg">
</p>
## Get Help

View File

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

215
readme/dark.drawio.svg Normal file
View File

@@ -0,0 +1,215 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" style="background: #045; background-color: light-dark(#045, #000000);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="357px" height="236px" viewBox="-0.5 -0.5 357 236" content="&lt;mxfile&gt;&lt;diagram id=&quot;QQJxv4aCTC7ZgE7HHOvM&quot; name=&quot;Page-1&quot;&gt;7VnLjqM4FP2abCO/H8upmn5sWmqpFrPmcRNQkRgZp5Karx8TMAFCl3pKIROkIYvYxy98z/H1tVnR593pm43K7IdJoVgRlJ5W9M8VIRhj7f9q5L1BuEYNsLV52kA94CX/G9qWAT3kKVQt1kDOmMLl5RBMzH4PiRtgkbXmOKy2MUU6AMpoC4PXqIGXJCrgqtpfeeqyBlVEXvDvkG+zMDIW7YTjKHndWnPYt+OtCEWMN2W7KHTUDlplUWqOPYh+WdFna4xrUrvTMxS1YYc2+/qL0u6lLezd7zQgTYO3qDi0814xlERlbqFuRES0K1f0aR9X9Z/PF77bp9j61Nb1kQDExrxWmSlDge8lvlQ+T9m9Bxv72Zd1MoNTtDV7X6UEm+/Agb2gPwPkjfN0zHIHL2WU1M2OXnkey9yu8Dnsk5v8BEFLdb56BZfUFkfnwqJ4NoWx58HpZgMiSepKzppX6JWkUscIdSWBftJNoW/f1uRvYB2celBr729g/Mvbd1+lLSWSNU3ahcEkbfLHi8zCWsl6ClMtFrXC3nY9X/j1iZbiabrpLHQ7Uzd/eL5VAtN8x4ozfje+qSR345vdmm8Lbzl41/rwbKccVMqm2FYkpkLMxTYVeMh22AfvwDa/NduJ2e08cQ9P9obXvxo3e9fDm2dKBOL83EsELCzEO4hA3FoExqZgl7DiI1CbSf8uEgXxZi6ysRL/GdnymuwxJ7BP/6jDYZ9Liqiq8mRo4oFJrw3km7f2l+fyyLpBfmTqr+fnI8NW5mATGDgs3+kW3CBCgTRE578wfs+4fMK4AbNQRC5/G8b0UxZvR/hpcv++F24JHm7eHJFhH8102mb9QPuqJzEK+/iop8YKVz2dJdBN/LdUoZatCvHoqvBLd80V7R4ydABUk3WvlFL5OckQzdYMi+4ZnxsQXvdKhaBz6UkvW09k4Xpi/GOib6Un9rFsb6encMWzVEGxhQuKjwU1i574SE9sNjmFkO1mIW91KMsi/z/q/RdR7z3PuZhM+I8RhS++E6849PgMAk45THolLSSNZjuk6hGBd7yWwhP3kEvaAIIA+ztA8ELL2ALGMYUceeeZYgoy2mpuuAlMXHUuXVLioRSFPdUSKU4Qltp7i3D50B1HtFeCRAxRriRjnw1SMV4TjZnUiiBBZPg40p2ttJc10VwLhn0gM1+MOnGZuig9hW+mDxukYi28C1L1hZnWSHA+8hxy7U86PlT151wl9CevXYhXpaJYSi4R0pSNBuFsTalgTHGtMEXqRmry2csn3Kb65SM5/fIP&lt;/diagram&gt;&lt;/mxfile&gt;">
<defs/>
<rect fill="#045" width="100%" height="100%" x="0" y="0" style="fill: light-dark(rgb(0, 68, 85), rgb(0, 0, 0));"/>
<g>
<g>
<path d="M 199 155 L 249 155 L 269 195 L 249 235 L 199 235 L 179 195 Z" fill="#ffe6cc" stroke="#d79b00" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(255, 230, 204), rgb(54, 33, 10)); stroke: light-dark(rgb(215, 155, 0), rgb(153, 101, 0));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 195px; margin-left: 180px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 12px; font-family: &quot;Helvetica&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
@capire/
<br/>
<b>
bookshop
</b>
</div>
</div>
</div>
</foreignObject>
<text x="224" y="199" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
</g>
<g>
<path d="M 199 54 L 249 54 L 269 94 L 249 134 L 199 134 L 179 94 Z" fill="#f8cecc" stroke="#b85450" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(248, 206, 204), rgb(81, 45, 43)); stroke: light-dark(rgb(184, 84, 80), rgb(215, 129, 126));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 94px; margin-left: 180px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 12px; font-family: &quot;Helvetica&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
@capire/
<br/>
<b>
bookstore
</b>
</div>
</div>
</div>
</foreignObject>
<text x="224" y="98" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
</g>
<g>
<path d="M 286 1 L 336 1 L 356 41 L 336 81 L 286 81 L 266 41 Z" fill="#d5e8d4" stroke="#82b366" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(213, 232, 212), rgb(31, 47, 30)); stroke: light-dark(rgb(130, 179, 102), rgb(68, 110, 44));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 41px; margin-left: 267px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 12px; font-family: &quot;Helvetica&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
@capire/
<br/>
<b>
reviews
</b>
</div>
</div>
</div>
</foreignObject>
<text x="311" y="45" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
</g>
<g>
<path d="M 286 106 L 336 106 L 356 146 L 336 186 L 286 186 L 266 146 Z" fill="#f5f5f5" stroke="#666666" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(245, 245, 245), rgb(26, 26, 26)); stroke: light-dark(rgb(102, 102, 102), rgb(149, 149, 149));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 146px; margin-left: 267px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #333333; ">
<div style="display: inline-block; font-size: 12px; font-family: &quot;Helvetica&quot;; color: light-dark(#333333, #c1c1c1); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
@capire/
<br/>
<b>
common
</b>
</div>
</div>
</div>
</foreignObject>
<text x="311" y="150" fill="#333333" font-family="&quot;Helvetica&quot;" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
</g>
<g>
<path d="M 111 106 L 161 106 L 181 146 L 161 186 L 111 186 L 91 146 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(218, 232, 252), rgb(29, 41, 59)); stroke: light-dark(rgb(108, 142, 191), rgb(92, 121, 163));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 146px; margin-left: 92px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 12px; font-family: &quot;Helvetica&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
@capire/
<br/>
<b>
orders
</b>
</div>
</div>
</div>
</foreignObject>
<text x="136" y="150" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
</g>
<g>
<path d="M 276.35 125.29 L 266.36 119.32" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
<path d="M 260.57 115.86 L 270.6 116.61 L 266.36 119.32 L 265.98 124.34 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(255, 255, 255), rgb(18, 18, 18)); stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
</g>
<g>
<path d="M 170.74 125.47 L 181.53 119.1" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
<path d="M 187.34 115.66 L 181.88 124.12 L 181.53 119.1 L 177.3 116.37 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(255, 255, 255), rgb(18, 18, 18)); stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
</g>
<g>
<path d="M 224 155 L 224 142.99" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
<path d="M 224 136.24 L 228.5 145.24 L 224 142.99 L 219.5 145.24 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(255, 255, 255), rgb(18, 18, 18)); stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
</g>
<g>
<path d="M 276.51 62.01 L 266.17 68.31" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
<path d="M 260.4 71.82 L 265.75 63.3 L 266.17 68.31 L 270.43 70.98 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(255, 255, 255), rgb(18, 18, 18)); stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
</g>
<g>
<path d="M 111 1 L 161 1 L 181 41 L 161 81 L 111 81 L 91 41 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(218, 232, 252), rgb(29, 41, 59)); stroke: light-dark(rgb(108, 142, 191), rgb(92, 121, 163));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 41px; margin-left: 92px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 12px; font-family: &quot;Helvetica&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
@capire/
<br/>
<b>
suppliers
</b>
</div>
</div>
</div>
</foreignObject>
<text x="136" y="45" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12px" text-anchor="middle">
@capire/...
</text>
</switch>
</g>
</g>
<g>
<path d="M 21 54 L 71 54 L 91 94 L 71 134 L 21 134 L 1 94 Z" fill="#e1d5e7" stroke="#9673a6" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(225, 213, 231), rgb(57, 47, 63)); stroke: light-dark(rgb(150, 115, 166), rgb(149, 119, 163));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 94px; margin-left: 2px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 12px; font-family: &quot;Helvetica&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
<b>
S/4
</b>
</div>
</div>
</div>
</foreignObject>
<text x="46" y="98" fill="light-dark(#000000, #ffffff)" font-family="&quot;Helvetica&quot;" font-size="12px" text-anchor="middle">
S/4
</text>
</switch>
</g>
</g>
<g>
<path d="M 80.76 73.53 L 93.49 66.03" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
<path d="M 99.31 62.61 L 93.84 71.05 L 93.49 66.03 L 89.27 63.3 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(255, 255, 255), rgb(18, 18, 18)); stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
</g>
<g>
<path d="M 80.91 114.17 L 93.31 121.33" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
<path d="M 99.15 124.71 L 89.11 124.1 L 93.31 121.33 L 93.61 116.31 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(255, 255, 255), rgb(18, 18, 18)); stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
</g>
<g>
<path d="M 170.59 61.83 L 181.72 68.53" fill="none" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
<path d="M 187.5 72.02 L 177.47 71.23 L 181.72 68.53 L 182.11 63.52 Z" fill="#ffffff" stroke="#ffffff" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(255, 255, 255), rgb(18, 18, 18)); stroke: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));"/>
</g>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
<a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank">
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
Text is not SVG - cannot display
</text>
</a>
</switch>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 273 KiB

After

Width:  |  Height:  |  Size: 273 KiB

228
readme/samples.drawio.svg Normal file
View File

@@ -0,0 +1,228 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="368px" height="230px" viewBox="-0.5 -0.5 368 230" content="&lt;mxfile&gt;&lt;diagram id=&quot;QQJxv4aCTC7ZgE7HHOvM&quot; name=&quot;Page-1&quot;&gt;7ZpLc9o6GIZ/Dcsw1l1aBtKmi3Z64cycmbMTtsCeGOTKJpD++iPHkrEdE9okBJICC6xXsm7f8+nKAI0Xm2sjs/iLjlQ6gEG0GaCrAYQAAGF/SuWuUogIKmFukqiSGsIk+aXcm15dJZHKnVZJhdZpkWRtMdTLpQqLliaN0et2splOo5aQybl6IExCmT5U/02iIq5UDtlW/6SSeexLBtQ1eCF9YteSPJaRXjck9GGAxkbronpabMYqLTuv3S8fd8TWFTNqWfzOC3N4fb26ir9+/u/zr4vg++pncKMvXC63Ml25Bg8gTW1+o2lZ5eLO9QP9uSrrOZrpZXGR31vp0iYAILOWHm3j7dO8/B1pfZPHOvO52WpNfVxdgnlWEZdZ5jq2zgLaPs7Kx1ht5FwvbapMmWShCmW26jcvWROM1nFSqEkmw/K1tWXYanGxSG0IlJVJNspTWYXTdKxTbe7LQ7OZomFo9bww+kY1YiImpkFQx3h2oGvgR7lI0tIlxnqRhLYRE7nM7c+XiUvgywQ+7BoZ3PdA1/LejMoUatOQHAnXStsGmzubxMVC4l5xbokErcLrLeTeU+MG39xp0rnVvM55S559cPD9AYhwJ4h5JpfPAuXFM5q2KC+0UU2k22n7wLdaVZcGyC/iEjsKOL6b8FD1u8mUE0wO5Ca2C8JkOf/HjkLoihzGb6Bgx/UbdHi/ed5M8EPdJsrOwoebCCbK3Caheuc+FBHFI9znQxxOEaWH8KHn+wvCHX/B/Lj+gh9b8FSmtv200KXr7GO2Uq5kIY9OhwKWD9ZHh6AMyTdCB8LkuHSQUx9Nv5pImfNg+ncOpoCemLvQHnfpWFYto8tyG25DYSrzPAnbhmp3c6nYN1wnVuOZNEUr3DEYGZffw5kn1ysTqv0ziq3nXBX7dzgqah04PDR2w5ikx5heMyqVRXLbPqbos7Ar4ZtObMu2LAHRhgn7Iw2fR9Vw91rzXKGbE+yO4qyTU9U1D3K6R65u+NMpZGcK65nrjVEICRsSjuoPpG2SABs2YhF6IqKQgSEGtP4w3C4G0mEjllL0qvzyM7/1QeQ745c9DtZL8Usfd5MD8yvO/NbnMO+LX/w6/OLj8uuvmk531zdZZVmanDd+543f4DRO0cDue8Nnu8zE1gifLD9S8VnvTQYNuZrOdvLTxWM/T66RPfe8f8wPJe31QgCOjA88Lxm2TrR3zeAnqLexaOguev1kf+BFr6/Fay0a+i7ezgjvSkhOimBg0WIBJ3YWYgIx6I++PFoIW/JYgANEOMP4iatewPkQCoCZ4DCgkDHULgVi60ZQEEExgIS88qK37yLs7+M3+E1+T2vbBhiyQywvD22FCCjpTO8MDu1WjRCAA8CpgE/Fl9oBFjBGWBCI+q6hLkQMEaIYcyI4QAF/IXptcPuXuCr59o+F6MP/&lt;/diagram&gt;&lt;/mxfile&gt;">
<defs/>
<g>
<g>
<path d="M 207 149 L 257 149 L 277 189 L 257 229 L 207 229 L 187 189 Z" fill="#ffe6cc" stroke="#d79b00" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(255, 230, 204), rgb(54, 33, 10)); stroke: light-dark(rgb(215, 155, 0), rgb(153, 101, 0));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 189px; margin-left: 188px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
<b style="font-size: 11px;">
Bookshop
</b>
<br style="font-size: 11px;"/>
App
</div>
</div>
</div>
</foreignObject>
<text x="232" y="192" fill="light-dark(#000000, #ffffff)" font-family="&quot;Comic Sans MS&quot;" font-size="11px" text-anchor="middle">
Bookshop...
</text>
</switch>
</g>
</g>
<g>
<path d="M 207 50 L 257 50 L 277 90 L 257 130 L 207 130 L 187 90 Z" fill="#f8cecc" stroke="#b85450" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(248, 206, 204), rgb(81, 45, 43)); stroke: light-dark(rgb(184, 84, 80), rgb(215, 129, 126));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 93px; margin-left: 188px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
<span style="font-size: 11px;">
<span style="font-size: 11px;">
<b>
Bookstore
<br/>
</b>
</span>
App
<br style="font-size: 11px;"/>
</span>
</div>
</div>
</div>
</foreignObject>
<text x="232" y="96" fill="light-dark(#000000, #ffffff)" font-family="&quot;Comic Sans MS&quot;" font-size="11px" text-anchor="middle">
Bookstore...
</text>
</switch>
</g>
</g>
<g>
<path d="M 297 1 L 347 1 L 367 41 L 347 81 L 297 81 L 277 41 Z" fill="#d5e8d4" stroke="#82b366" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(213, 232, 212), rgb(31, 47, 30)); stroke: light-dark(rgb(130, 179, 102), rgb(68, 110, 44));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 41px; margin-left: 278px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
<span style="font-size: 11px;">
<b style="font-size: 11px;">
Reviews
</b>
<br style="font-size: 11px;"/>
Service
<br style="font-size: 11px;"/>
</span>
</div>
</div>
</div>
</foreignObject>
<text x="322" y="44" fill="light-dark(#000000, #ffffff)" font-family="&quot;Comic Sans MS&quot;" font-size="11px" text-anchor="middle">
Reviews...
</text>
</switch>
</g>
</g>
<g>
<path d="M 297 98 L 347 98 L 367 138 L 347 178 L 297 178 L 277 138 Z" fill="#e1d5e7" stroke="#9673a6" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(225, 213, 231), rgb(57, 47, 63)); stroke: light-dark(rgb(150, 115, 166), rgb(149, 119, 163));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 138px; margin-left: 278px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
<b>
Common
</b>
<br/>
Data
</div>
</div>
</div>
</foreignObject>
<text x="322" y="141" fill="light-dark(#000000, #ffffff)" font-family="&quot;Comic Sans MS&quot;" font-size="11px" text-anchor="middle">
Common...
</text>
</switch>
</g>
</g>
<g>
<path d="M 117 98 L 167 98 L 187 138 L 167 178 L 117 178 L 97 138 Z" fill="#d5e8d4" stroke="#82b366" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(213, 232, 212), rgb(31, 47, 30)); stroke: light-dark(rgb(130, 179, 102), rgb(68, 110, 44));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 138px; margin-left: 98px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
<span style="font-size: 11px;">
<b style="font-size: 11px;">
Orders
</b>
<br style="font-size: 11px;"/>
Service
<br style="font-size: 11px;"/>
</span>
</div>
</div>
</div>
</foreignObject>
<text x="142" y="141" fill="light-dark(#000000, #ffffff)" font-family="&quot;Comic Sans MS&quot;" font-size="11px" text-anchor="middle">
Orders...
</text>
</switch>
</g>
</g>
<g>
<path d="M 286.47 119.05 L 273.81 112.3" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
<path d="M 268.51 109.47 L 277.45 109.71 L 273.81 112.3 L 273.69 116.77 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(92, 92, 92), rgb(158, 158, 158)); stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
</g>
<g>
<path d="M 177.53 119.05 L 190.19 112.3" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
<path d="M 195.49 109.47 L 190.31 116.77 L 190.19 112.3 L 186.55 109.71 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(92, 92, 92), rgb(158, 158, 158)); stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
</g>
<g>
<path d="M 232 149 L 232 137.12" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
<path d="M 232 131.12 L 236 139.12 L 232 137.12 L 228 139.12 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(92, 92, 92), rgb(158, 158, 158)); stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
</g>
<g>
<path d="M 286.63 60.26 L 273.62 67.34" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
<path d="M 268.35 70.21 L 273.47 62.87 L 273.62 67.34 L 277.29 69.9 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(92, 92, 92), rgb(158, 158, 158)); stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
</g>
<g>
<path d="M 117 1 L 167 1 L 187 41 L 167 81 L 117 81 L 97 41 Z" fill="#d5e8d4" stroke="#82b366" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(213, 232, 212), rgb(31, 47, 30)); stroke: light-dark(rgb(130, 179, 102), rgb(68, 110, 44));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 41px; margin-left: 98px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
<span style="font-size: 11px;">
<b style="font-size: 11px;">
Suppliers
</b>
<br style="font-size: 11px;"/>
Service
<br style="font-size: 11px;"/>
</span>
</div>
</div>
</div>
</foreignObject>
<text x="142" y="44" fill="light-dark(#000000, #ffffff)" font-family="&quot;Comic Sans MS&quot;" font-size="11px" text-anchor="middle">
Suppliers...
</text>
</switch>
</g>
</g>
<g>
<path d="M 21 54 L 71 54 L 91 94 L 71 134 L 21 134 L 1 94 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-width="2" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(218, 232, 252), rgb(29, 41, 59)); stroke: light-dark(rgb(108, 142, 191), rgb(92, 121, 163));"/>
</g>
<g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 94px; margin-left: 2px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; ">
<div style="display: inline-block; font-size: 11px; font-family: &quot;Comic Sans MS&quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">
<span style="font-size: 11px;">
S/4
</span>
</div>
</div>
</div>
</foreignObject>
<text x="46" y="97" fill="light-dark(#000000, #ffffff)" font-family="&quot;Comic Sans MS&quot;" font-size="11px" text-anchor="middle" font-weight="bold">
S/4
</text>
</switch>
</g>
</g>
<g>
<path d="M 81.27 74.53 L 100.5 63.91" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
<path d="M 105.76 61.01 L 100.69 68.38 L 100.5 63.91 L 96.82 61.37 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(92, 92, 92), rgb(158, 158, 158)); stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
</g>
<g>
<path d="M 82.61 110.78 L 98.92 118.25" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
<path d="M 104.37 120.75 L 95.43 121.06 L 98.92 118.25 L 98.77 113.79 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(92, 92, 92), rgb(158, 158, 158)); stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
</g>
<g>
<path d="M 177.37 60.26 L 190.38 67.34" fill="none" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="stroke" style="stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
<path d="M 195.65 70.21 L 186.71 69.9 L 190.38 67.34 L 190.53 62.87 Z" fill="#5c5c5c" stroke="#5c5c5c" stroke-miterlimit="10" pointer-events="all" style="fill: light-dark(rgb(92, 92, 92), rgb(158, 158, 158)); stroke: light-dark(rgb(92, 92, 92), rgb(158, 158, 158));"/>
</g>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
<a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank">
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
Text is not SVG - cannot display
</text>
</a>
</switch>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -3,10 +3,10 @@
The following list gives an overview of the samples provided in subdirectories.
Each sub directory essentially is an individual npm package arranged in an [all-in-one monorepo](#all-in-one-monorepo) umbrella setup.
![](etc/samples.drawio.svg)
![](samples.drawio.svg)
## [@capire/bookshop](bookshop)
## [@capire/bookshop](../bookshop)
- [Getting Started](https://cap.cloud.sap/docs/get-started/in-a-nutshell) with CAP, briefly introducing:
- [Project Setup](https://cap.cloud.sap/docs/get-started/) and [Layouts](https://cap.cloud.sap/docs/get-started/projects)
@@ -17,24 +17,24 @@ Each sub directory essentially is an individual npm package arranged in an [all-
- [Using Databases](https://cap.cloud.sap/docs/guides/databases)
## [@capire/common](common)
## [@capire/common](../common)
- Showcases how to extend [@sap/cds/common](https://cap.cloud.sap/docs/cds/common) thereby covering:
- Building [extension packages](https://cap.cloud.sap/docs/guides/domain-models#aspects-extensibility)
- Providing [reuse packages](https://cap.cloud.sap/docs/get-started/projects#sharing-and-reusing-content)
- [Verticalization](https://cap.cloud.sap/docs/cds/common#adapting-to-your-needs)
- Using [Aspects](https://cap.cloud.sap/docs/cds/cdl#aspects)
- Used in the [fiori app sample](#fiori)
- Used in the [bookstore sample](#capire-bookstore)
## [@capire/orders](orders)
## [@capire/orders](../orders)
- A standalone orders management service, demonstrating:
- Using [Compositions](https://cap.cloud.sap/docs/cds/cdl#compositions) in [Domain Models](https://cap.cloud.sap/docs/guides/domain-models), along with
- [Serving deeply nested documents](https://cap.cloud.sap/docs/guides/generic-providers#serving-structured-data)
## [@capire/reviews](reviews)
## [@capire/reviews](../reviews)
- Shows how to implement a modular service to manage product reviews, including:
- Consuming other services synchronously and asynchronously
@@ -47,22 +47,18 @@ Each sub directory essentially is an individual npm package arranged in an [all-
- As well as managed data, input validations, and authorization
## [@capire/bookstore](bookstore)
## [@capire/bookstore](../bookstore)
- A [composite app, reusing and combining](https://cap.cloud.sap/docs/guides/extensibility/composition) these packages:
- [@capire/bookshop](bookshop)
- [@capire/reviews](reviews)
- [@capire/orders](orders)
- [@capire/common](common)
- [@capire/data-viewer](etc/data-viewer)
- [The Vue.js app](bookshop/app/vue) imported from `bookshop` is served as well
- [The Vue.js app](reviews/app/vue) imported from `reviews` is served as well
- [The Vue.js app](etc/data-viewer/app/data) imported from `data-viewer` is served as well
- [The Fiori app](orders/app) imported from `orders` is served as well
## [@capire/fiori](fiori)
- [@capire/bookshop](../bookshop)
- [@capire/reviews](../reviews)
- [@capire/orders](../orders)
- [@capire/common](../common)
- [@capire/data-viewer](data-viewer)
- [The Vue.js app](../bookshop/app/vue) imported from `bookshop` is served as well
- [The Vue.js app](../reviews/app/vue) imported from `reviews` is served as well
- [The Vue.js app](data-viewer/app/data) imported from `data-viewer` is served as well
- [The Fiori app](../orders/app) imported from `orders` is served as well
- Adds an SAP Fiori elements application to bookstore, thereby introducing:
- OData Annotations in `.cds` files
- Support for Fiori Draft
@@ -75,4 +71,4 @@ See the [Serving Fiori UIs](https://cap.cloud.sap/docs/advanced/fiori) documenta
# All-in-one Monorepo
Each sample sub directory essentially is a standard npm package, some with standard npm dependencies to other samples. The root folder's [package.json](package.json) has local links to the sub folders, such that an `npm install` populates a local `node_modules` folder and acts like a local npm registry to the individual sample packages.
Each sample sub directory essentially is a standard npm package, some with standard npm dependencies to other samples. The root folder's [package.json](../package.json) has local links to the sub folders, such that an `npm install` populates a local `node_modules` folder and acts like a local npm registry to the individual sample packages.

View File

@@ -7,18 +7,15 @@
"index.cds"
],
"dependencies": {
"@cap-js/hana": "^1",
"@cap-js/hana": ">=1",
"@sap/cds": ">=5",
"@sap/xssec": "^4.2.7",
"express": "^4.17.1",
"@sap/cds-mtxs": "^2"
"express": "^4.17.1"
},
"cds": {
"requires": {
"messaging": true,
"db": true,
"multitenancy": true,
"auth": "xsuaa"
"db": true
}
},
"scripts": {

View File

@@ -3,7 +3,7 @@ module.exports = cds.service.impl (function(){
// Get the CSN definition for Reviews from the db schema for sub-sequent queries
// ( Note: we explicitly specify the namespace to support embedded reuse )
const { Reviews, Likes } = this.entities ('sap.capire.reviews')
const { Reviews, Likes } = this.entities
this.before (['CREATE','UPDATE'], 'Reviews', req => {
if (!req.data.rating) req.data.rating = Math.round(Math.random()*4)+1

View File

@@ -2,6 +2,11 @@
"name": "@capire/shared-db",
"version": "3.0.0",
"description": "CAP Sample CDS model deployment for shared-db scenario",
"dependencies": {
"@capire/bookstore": "*",
"@capire/orders": "*",
"@capire/reviews": "*"
},
"cds": {
"sql": {
"native_hana_associations": false

Some files were not shown because too many files have changed in this diff Show More