Compare commits
21 Commits
audit-log-
...
cg-deploy-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f8a78fe8a | ||
|
|
7f9474244b | ||
|
|
cad615a662 | ||
|
|
7101c58920 | ||
|
|
07dc1e88b3 | ||
|
|
6f8d74dc9a | ||
|
|
ec57c5ea48 | ||
|
|
c040a47279 | ||
|
|
30bfd70c49 | ||
|
|
6fb9581cf1 | ||
|
|
e87d6cdfc5 | ||
|
|
29ea2bc2da | ||
|
|
12574271ac | ||
|
|
17b5cc1ad2 | ||
|
|
26ca7f54ad | ||
|
|
573e78253d | ||
|
|
a7511ed677 | ||
|
|
f1289b436b | ||
|
|
984ea2133b | ||
|
|
179d301acb | ||
|
|
bbf20b1ca3 |
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
version: 2
|
||||||
|
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: /
|
||||||
|
versioning-strategy: increase-if-necessary
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
3752
bookshop/app/package-lock.json
generated
Normal file
3752
bookshop/app/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
12
bookshop/app/package.json
Normal file
12
bookshop/app/package.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "approuter",
|
||||||
|
"dependencies": {
|
||||||
|
"@sap/approuter": "^10"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "node node_modules/@sap/approuter/approuter.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,14 +3,15 @@ const $ = sel => document.querySelector(sel)
|
|||||||
const GET = (url) => axios.get('/browse'+url)
|
const GET = (url) => axios.get('/browse'+url)
|
||||||
const POST = (cmd,data) => axios.post('/browse'+cmd,data)
|
const POST = (cmd,data) => axios.post('/browse'+cmd,data)
|
||||||
|
|
||||||
const books = new Vue ({
|
const books = Vue.createApp ({
|
||||||
|
|
||||||
el:'#app',
|
data() {
|
||||||
|
return {
|
||||||
data: {
|
|
||||||
list: [],
|
list: [],
|
||||||
book: undefined,
|
book: undefined,
|
||||||
order: { quantity:1, succeeded:'', failed:'' }
|
order: { quantity:1, succeeded:'', failed:'' },
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@@ -37,12 +38,21 @@ const books = new Vue ({
|
|||||||
book.stock = res.data.stock
|
book.stock = res.data.stock
|
||||||
books.order = { quantity, succeeded: `Successfully ordered ${quantity} item(s).` }
|
books.order = { quantity, succeeded: `Successfully ordered ${quantity} item(s).` }
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
books.order = { quantity, failed: e.response.data.error.message }
|
books.order = { quantity, failed: e.response.data.error ? e.response.data.error.message : e.response.data }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
}).mount("#app")
|
||||||
|
|
||||||
// initially fill list of books
|
// initially fill list of books
|
||||||
books.fetch()
|
books.fetch()
|
||||||
|
|
||||||
|
// show user info on request
|
||||||
|
document.addEventListener('keydown', async (event) => {
|
||||||
|
if (event.key === 'u') {
|
||||||
|
try {
|
||||||
|
books.user = (await axios.get('/user/User')).data
|
||||||
|
} catch (err) { }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
@@ -5,19 +5,26 @@
|
|||||||
<title> Capire Books </title>
|
<title> Capire Books </title>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/primitive-ui/dist/css/main.css">
|
<link rel="stylesheet" href="https://unpkg.com/primitive-ui/dist/css/main.css">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
|
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
|
||||||
<style>
|
<style>
|
||||||
.hovering tr:hover td { color:cyan; background: #123; cursor: pointer; }
|
.hovering tr:hover td { color:cyan; background: #123; cursor: pointer; }
|
||||||
.rating-stars { color:teal }
|
.rating-stars { color:teal }
|
||||||
.succeeded { color:teal }
|
.succeeded { color:teal }
|
||||||
.failed { color:red }
|
.failed { color:red }
|
||||||
|
.user {text-align: end; color: grey;}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="small-container", style="margin-top: 70px;">
|
<body class="small-container", style="margin-top: 70px;">
|
||||||
<div id='app'>
|
<div id='app'>
|
||||||
|
|
||||||
<h1> {{ document.title }} </h1>
|
<div v-if="user.ID && user.ID !== 'anonymous'" class="user">
|
||||||
|
<div>User: {{ user.ID }}</div>
|
||||||
|
<div>Locale: {{ user.locale }}</div>
|
||||||
|
<div>Tenant: {{ user.tenant }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1> Capire Books </h1>
|
||||||
|
|
||||||
<input type="text" placeholder="Search..." @input="search">
|
<input type="text" placeholder="Search..." @input="search">
|
||||||
|
|
||||||
|
|||||||
19
bookshop/app/xs-app.json
Normal file
19
bookshop/app/xs-app.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"authenticationMethod": "route",
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"source": "^/app/(.*)$",
|
||||||
|
"target": "$1",
|
||||||
|
"localDir": ".",
|
||||||
|
"authenticationType": "xsuaa",
|
||||||
|
"cacheControl": "no-cache, no-store, must-revalidate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "^/(.*)$",
|
||||||
|
"target": "$1",
|
||||||
|
"destination": "srv-api",
|
||||||
|
"authenticationType": "xsuaa",
|
||||||
|
"csrfProtection": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
136
bookshop/db/src/.hdiconfig
Normal file
136
bookshop/db/src/.hdiconfig
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
{
|
||||||
|
"file_suffixes": {
|
||||||
|
"csv": {
|
||||||
|
"plugin_name": "com.sap.hana.di.tabledata.source"
|
||||||
|
},
|
||||||
|
"hdbafllangprocedure": {
|
||||||
|
"plugin_name": "com.sap.hana.di.afllangprocedure"
|
||||||
|
},
|
||||||
|
"hdbanalyticprivilege": {
|
||||||
|
"plugin_name": "com.sap.hana.di.analyticprivilege"
|
||||||
|
},
|
||||||
|
"hdbcalculationview": {
|
||||||
|
"plugin_name": "com.sap.hana.di.calculationview"
|
||||||
|
},
|
||||||
|
"hdbcollection": {
|
||||||
|
"plugin_name": "com.sap.hana.di.collection"
|
||||||
|
},
|
||||||
|
"hdbconstraint": {
|
||||||
|
"plugin_name": "com.sap.hana.di.constraint"
|
||||||
|
},
|
||||||
|
"hdbdropcreatetable": {
|
||||||
|
"plugin_name": "com.sap.hana.di.dropcreatetable"
|
||||||
|
},
|
||||||
|
"hdbflowgraph": {
|
||||||
|
"plugin_name": "com.sap.hana.di.flowgraph"
|
||||||
|
},
|
||||||
|
"hdbfunction": {
|
||||||
|
"plugin_name": "com.sap.hana.di.function"
|
||||||
|
},
|
||||||
|
"hdbgraphworkspace": {
|
||||||
|
"plugin_name": "com.sap.hana.di.graphworkspace"
|
||||||
|
},
|
||||||
|
"hdbhadoopmrjob": {
|
||||||
|
"plugin_name": "com.sap.hana.di.virtualfunctionpackage.hadoop"
|
||||||
|
},
|
||||||
|
"hdbindex": {
|
||||||
|
"plugin_name": "com.sap.hana.di.index"
|
||||||
|
},
|
||||||
|
"hdblibrary": {
|
||||||
|
"plugin_name": "com.sap.hana.di.library"
|
||||||
|
},
|
||||||
|
"hdbmigrationtable": {
|
||||||
|
"plugin_name": "com.sap.hana.di.table.migration"
|
||||||
|
},
|
||||||
|
"hdbprocedure": {
|
||||||
|
"plugin_name": "com.sap.hana.di.procedure"
|
||||||
|
},
|
||||||
|
"hdbprojectionview": {
|
||||||
|
"plugin_name": "com.sap.hana.di.projectionview"
|
||||||
|
},
|
||||||
|
"hdbprojectionviewconfig": {
|
||||||
|
"plugin_name": "com.sap.hana.di.projectionview.config"
|
||||||
|
},
|
||||||
|
"hdbreptask": {
|
||||||
|
"plugin_name": "com.sap.hana.di.reptask"
|
||||||
|
},
|
||||||
|
"hdbresultcache": {
|
||||||
|
"plugin_name": "com.sap.hana.di.resultcache"
|
||||||
|
},
|
||||||
|
"hdbrole": {
|
||||||
|
"plugin_name": "com.sap.hana.di.role"
|
||||||
|
},
|
||||||
|
"hdbroleconfig": {
|
||||||
|
"plugin_name": "com.sap.hana.di.role.config"
|
||||||
|
},
|
||||||
|
"hdbsearchruleset": {
|
||||||
|
"plugin_name": "com.sap.hana.di.searchruleset"
|
||||||
|
},
|
||||||
|
"hdbsequence": {
|
||||||
|
"plugin_name": "com.sap.hana.di.sequence"
|
||||||
|
},
|
||||||
|
"hdbstatistics": {
|
||||||
|
"plugin_name": "com.sap.hana.di.statistics"
|
||||||
|
},
|
||||||
|
"hdbstructuredprivilege": {
|
||||||
|
"plugin_name": "com.sap.hana.di.structuredprivilege"
|
||||||
|
},
|
||||||
|
"hdbsynonym": {
|
||||||
|
"plugin_name": "com.sap.hana.di.synonym"
|
||||||
|
},
|
||||||
|
"hdbsynonymconfig": {
|
||||||
|
"plugin_name": "com.sap.hana.di.synonym.config"
|
||||||
|
},
|
||||||
|
"hdbsystemversioning": {
|
||||||
|
"plugin_name": "com.sap.hana.di.systemversioning"
|
||||||
|
},
|
||||||
|
"hdbtable": {
|
||||||
|
"plugin_name": "com.sap.hana.di.table"
|
||||||
|
},
|
||||||
|
"hdbtabledata": {
|
||||||
|
"plugin_name": "com.sap.hana.di.tabledata"
|
||||||
|
},
|
||||||
|
"hdbtabletype": {
|
||||||
|
"plugin_name": "com.sap.hana.di.tabletype"
|
||||||
|
},
|
||||||
|
"hdbtrigger": {
|
||||||
|
"plugin_name": "com.sap.hana.di.trigger"
|
||||||
|
},
|
||||||
|
"hdbview": {
|
||||||
|
"plugin_name": "com.sap.hana.di.view"
|
||||||
|
},
|
||||||
|
"hdbvirtualfunction": {
|
||||||
|
"plugin_name": "com.sap.hana.di.virtualfunction"
|
||||||
|
},
|
||||||
|
"hdbvirtualfunctionconfig": {
|
||||||
|
"plugin_name": "com.sap.hana.di.virtualfunction.config"
|
||||||
|
},
|
||||||
|
"hdbvirtualpackagehadoop": {
|
||||||
|
"plugin_name": "com.sap.hana.di.virtualpackage.hadoop"
|
||||||
|
},
|
||||||
|
"hdbvirtualpackagesparksql": {
|
||||||
|
"plugin_name": "com.sap.hana.di.virtualpackage.sparksql"
|
||||||
|
},
|
||||||
|
"hdbvirtualprocedure": {
|
||||||
|
"plugin_name": "com.sap.hana.di.virtualprocedure"
|
||||||
|
},
|
||||||
|
"hdbvirtualprocedureconfig": {
|
||||||
|
"plugin_name": "com.sap.hana.di.virtualprocedure.config"
|
||||||
|
},
|
||||||
|
"hdbvirtualtable": {
|
||||||
|
"plugin_name": "com.sap.hana.di.virtualtable"
|
||||||
|
},
|
||||||
|
"hdbvirtualtableconfig": {
|
||||||
|
"plugin_name": "com.sap.hana.di.virtualtable.config"
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"plugin_name": "com.sap.hana.di.tabledata.properties"
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"plugin_name": "com.sap.hana.di.tabledata.properties"
|
||||||
|
},
|
||||||
|
"txt": {
|
||||||
|
"plugin_name": "com.sap.hana.di.copyonly"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
bookshop/db/undeploy.json
Normal file
5
bookshop/db/undeploy.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
"src/gen/**/*.hdbview",
|
||||||
|
"src/gen/**/*.hdbindex",
|
||||||
|
"src/gen/**/*.hdbconstraint"
|
||||||
|
]
|
||||||
98
bookshop/mta.yaml
Normal file
98
bookshop/mta.yaml
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
---
|
||||||
|
_schema-version: '3.1'
|
||||||
|
ID: capire.bookshop
|
||||||
|
version: 1.0.0
|
||||||
|
description: "A simple self-contained bookshop service."
|
||||||
|
parameters:
|
||||||
|
enable-parallel-deployments: true
|
||||||
|
build-parameters:
|
||||||
|
before-all:
|
||||||
|
- builder: custom
|
||||||
|
commands:
|
||||||
|
- npx -p @sap/cds-dk cds build --production
|
||||||
|
|
||||||
|
modules:
|
||||||
|
- name: bookshop-srv
|
||||||
|
type: nodejs
|
||||||
|
path: gen/srv
|
||||||
|
parameters:
|
||||||
|
buildpack: nodejs_buildpack
|
||||||
|
build-parameters:
|
||||||
|
builder: npm-ci
|
||||||
|
provides:
|
||||||
|
- name: srv-api # required by consumers of CAP services (e.g. approuter)
|
||||||
|
properties:
|
||||||
|
srv-url: ${default-url}
|
||||||
|
- name: mtx-api # potentially required by approuter
|
||||||
|
properties:
|
||||||
|
mtx-url: ${default-url}
|
||||||
|
requires:
|
||||||
|
- name: bookshop-auth
|
||||||
|
- name: bookshop-db
|
||||||
|
- name: bookshop-registry
|
||||||
|
properties:
|
||||||
|
SUBSCRIPTION_URL: ${protocol}://\${tenant_subdomain}-${default-uri}
|
||||||
|
SUBSCRIPTION_URL_REPLACEMENT_RULES: [ [ '-srv', '' ] ]
|
||||||
|
|
||||||
|
- name: bookshop
|
||||||
|
type: approuter.nodejs
|
||||||
|
path: app/ # from cds.env.folders. Consider also cds.env.build.target -> gen/app
|
||||||
|
parameters:
|
||||||
|
keep-existing-routes: true
|
||||||
|
disk-quota: 256M
|
||||||
|
memory: 256M
|
||||||
|
requires:
|
||||||
|
- name: srv-api
|
||||||
|
group: destinations
|
||||||
|
properties:
|
||||||
|
name: srv-api # must be used in xs-app.json as well
|
||||||
|
url: ~{srv-url}
|
||||||
|
forwardAuthToken: true
|
||||||
|
- name: bookshop-auth
|
||||||
|
- name: mtx-api
|
||||||
|
group: destinations
|
||||||
|
properties:
|
||||||
|
name: mtx-api # must be used in xs-app.json as well
|
||||||
|
url: ~{mtx-url}
|
||||||
|
properties:
|
||||||
|
TENANT_HOST_PATTERN: "^(.*)-${default-uri}"
|
||||||
|
|
||||||
|
resources:
|
||||||
|
|
||||||
|
- name: bookshop-auth
|
||||||
|
type: org.cloudfoundry.managed-service
|
||||||
|
parameters:
|
||||||
|
service: xsuaa
|
||||||
|
service-plan: application
|
||||||
|
path: ./xs-security.json
|
||||||
|
config:
|
||||||
|
xsappname: bookshop-${org}-${space}
|
||||||
|
tenant-mode: shared
|
||||||
|
|
||||||
|
- name: bookshop-db
|
||||||
|
type: org.cloudfoundry.managed-service
|
||||||
|
parameters:
|
||||||
|
service: service-manager
|
||||||
|
service-plan: container
|
||||||
|
properties:
|
||||||
|
hdi-service-name: ${service-name}
|
||||||
|
|
||||||
|
- name: bookshop-registry
|
||||||
|
type: org.cloudfoundry.managed-service
|
||||||
|
requires:
|
||||||
|
- name: mtx-api
|
||||||
|
parameters:
|
||||||
|
service: saas-registry
|
||||||
|
service-plan: application
|
||||||
|
config:
|
||||||
|
xsappname: bookshop-${org}-${space}
|
||||||
|
appName: bookshop-${org}-${space}
|
||||||
|
displayName: bookshop
|
||||||
|
description: A simple CAP project.
|
||||||
|
category: 'Category'
|
||||||
|
appUrls:
|
||||||
|
getDependencies: ~{mtx-api/mtx-url}/mtx/v1/provisioning/dependencies
|
||||||
|
onSubscription: ~{mtx-api/mtx-url}/mtx/v1/provisioning/tenant/{tenantId}
|
||||||
|
onSubscriptionAsync: false
|
||||||
|
onUnSubscriptionAsync: false
|
||||||
|
callbackTimeoutMillis: 300000
|
||||||
4025
bookshop/package-lock.json
generated
Normal file
4025
bookshop/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,9 +2,19 @@
|
|||||||
"name": "@capire/bookshop",
|
"name": "@capire/bookshop",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "A simple self-contained bookshop service.",
|
"description": "A simple self-contained bookshop service.",
|
||||||
|
"files": [
|
||||||
|
"app",
|
||||||
|
"srv",
|
||||||
|
"db",
|
||||||
|
"index.cds",
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sap/cds": "^5.0.4",
|
"@sap/cds": "^5",
|
||||||
|
"@sap/cds-mtx": "^2",
|
||||||
|
"@sap/xssec": "^3",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
|
"hdb": "^0.19.0",
|
||||||
"passport": "0.4.1"
|
"passport": "0.4.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -16,7 +26,24 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"db": {
|
"db": {
|
||||||
"kind": "sql"
|
"kind": "sql"
|
||||||
|
},
|
||||||
|
"[production]": {
|
||||||
|
"db": {
|
||||||
|
"kind": "hana-mt"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"kind": "xsuaa"
|
||||||
|
},
|
||||||
|
"multitenancy": true,
|
||||||
|
"approuter": {
|
||||||
|
"kind": "cloudfoundry"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"mtx": {
|
||||||
|
"element-prefix": "Z_",
|
||||||
|
"namespace-blocklist": [],
|
||||||
|
"extension-allowlist": []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
bookshop/srv/user-service.cds
Normal file
11
bookshop/srv/user-service.cds
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
@requires : 'authenticated-user'
|
||||||
|
service UserService {
|
||||||
|
|
||||||
|
@odata.singleton
|
||||||
|
entity User {
|
||||||
|
ID : String;
|
||||||
|
locale : String;
|
||||||
|
tenant : String;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
11
bookshop/srv/user-service.js
Normal file
11
bookshop/srv/user-service.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
const cds = require('@sap/cds');
|
||||||
|
|
||||||
|
module.exports = cds.service.impl((srv) => {
|
||||||
|
srv.on('READ', 'User', ({ user }) => {
|
||||||
|
return {
|
||||||
|
ID: user.id,
|
||||||
|
locale: user.locale,
|
||||||
|
tenant: user.tenant,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
70
bookshop/xs-security.json
Normal file
70
bookshop/xs-security.json
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"scopes": [
|
||||||
|
{
|
||||||
|
"name": "$XSAPPNAME.admin",
|
||||||
|
"description": "admin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "$XSAPPNAME.MtxDiagnose",
|
||||||
|
"description": "Diagnose MTX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "$XSAPPNAME.mtcallback",
|
||||||
|
"description": "Subscribe to applications",
|
||||||
|
"grant-as-authority-to-apps": [
|
||||||
|
"$XSAPPNAME(application,sap-provisioning,tenant-onboarding)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "$XSAPPNAME.mtdeployment",
|
||||||
|
"description": "Deploy applications"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "$XSAPPNAME.ExtendCDS",
|
||||||
|
"description": "Extend CDS applications"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "$XSAPPNAME.ExtendCDSdelete",
|
||||||
|
"description": "Extend CDS applications with undeployments"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"attributes": [],
|
||||||
|
"role-templates": [
|
||||||
|
{
|
||||||
|
"name": "admin",
|
||||||
|
"description": "generated",
|
||||||
|
"scope-references": [
|
||||||
|
"$XSAPPNAME.admin"
|
||||||
|
],
|
||||||
|
"attribute-references": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MultitenancyAdministrator",
|
||||||
|
"description": "Administrate multitenant applications",
|
||||||
|
"scope-references": [
|
||||||
|
"$XSAPPNAME.MtxDiagnose",
|
||||||
|
"$XSAPPNAME.mtdeployment",
|
||||||
|
"$XSAPPNAME.mtcallback"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ExtensionDeveloper",
|
||||||
|
"description": "Extend application",
|
||||||
|
"scope-references": [
|
||||||
|
"$XSAPPNAME.ExtendCDS"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ExtensionDeveloperUndeploy",
|
||||||
|
"description": "Undeploy extension",
|
||||||
|
"scope-references": [
|
||||||
|
"$XSAPPNAME.ExtendCDSdelete"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"authorities": [
|
||||||
|
"$XSAPPNAME.MtxDiagnose",
|
||||||
|
"$XSAPPNAME.mtdeployment",
|
||||||
|
"$XSAPPNAME.mtcallback"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
<script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
|
<script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
|
||||||
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
|
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
|
||||||
data-sap-ui-compatVersion="edge"
|
data-sap-ui-compatVersion="edge"
|
||||||
data-sap-ui-theme="sap_fiori_3"
|
data-sap-ui-theme="sap_horizon"
|
||||||
data-sap-ui-frameOptions="allow"
|
data-sap-ui-frameOptions="allow"
|
||||||
></script>
|
></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
|
<script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
|
||||||
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
|
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
|
||||||
data-sap-ui-compatVersion="edge"
|
data-sap-ui-compatVersion="edge"
|
||||||
data-sap-ui-theme="sap_fiori_3"
|
data-sap-ui-theme="sap_horizon"
|
||||||
data-sap-ui-frameOptions="allow"
|
data-sap-ui-frameOptions="allow"
|
||||||
></script>
|
></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
2238
package-lock.json
generated
2238
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@
|
|||||||
"chai": "^4.3.4",
|
"chai": "^4.3.4",
|
||||||
"chai-as-promised": "^7.1.1",
|
"chai-as-promised": "^7.1.1",
|
||||||
"chai-subset": "^1.6.0",
|
"chai-subset": "^1.6.0",
|
||||||
|
"semver": "^7",
|
||||||
"sqlite3": "npm:@mendix/sqlite3@^5"
|
"sqlite3": "npm:@mendix/sqlite3@^5"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ const GET = (url) => axios.get('/reviews'+url)
|
|||||||
const PUT = (cmd,data) => axios.patch('/reviews'+cmd,data)
|
const PUT = (cmd,data) => axios.patch('/reviews'+cmd,data)
|
||||||
const POST = (cmd,data) => axios.post('/reviews'+cmd,data)
|
const POST = (cmd,data) => axios.post('/reviews'+cmd,data)
|
||||||
|
|
||||||
const reviews = new Vue ({
|
const reviews = Vue.createApp ({
|
||||||
|
|
||||||
el:'#app',
|
data() {
|
||||||
|
return {
|
||||||
data: {
|
|
||||||
list: [],
|
list: [],
|
||||||
review: undefined,
|
review: undefined,
|
||||||
message: {},
|
message: {},
|
||||||
@@ -19,6 +18,7 @@ const reviews = new Vue ({
|
|||||||
2 : '★★',
|
2 : '★★',
|
||||||
1 : '★',
|
1 : '★',
|
||||||
}).reverse()
|
}).reverse()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@@ -66,7 +66,7 @@ const reviews = new Vue ({
|
|||||||
datetime: (d) => d && new Date(d).toLocaleString(),
|
datetime: (d) => d && new Date(d).toLocaleString(),
|
||||||
},
|
},
|
||||||
|
|
||||||
})
|
}).mount("#app")
|
||||||
|
|
||||||
// initially fill list of my reviews
|
// initially fill list of my reviews
|
||||||
reviews.fetch()
|
reviews.fetch()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<title> Capire Reviews </title>
|
<title> Capire Reviews </title>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/primitive-ui/dist/css/main.css">
|
<link rel="stylesheet" href="https://unpkg.com/primitive-ui/dist/css/main.css">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
|
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
|
||||||
<style>
|
<style>
|
||||||
.hovering tr:hover td { color:cyan; background: #123; cursor: pointer; }
|
.hovering tr:hover td { color:cyan; background: #123; cursor: pointer; }
|
||||||
.rating-stars { color:teal }
|
.rating-stars { color:teal }
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
<body class="small-container", style="margin-top: 70px;">
|
<body class="small-container", style="margin-top: 70px;">
|
||||||
<div id='app'>
|
<div id='app'>
|
||||||
|
|
||||||
<h1> {{ document.title }} </h1>
|
<h1> Capire Reviews </h1>
|
||||||
|
|
||||||
<input type="text" placeholder="Search..." @input="search">
|
<input type="text" placeholder="Search..." @input="search">
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,27 @@ describe('Consuming Services locally', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}).where(`name like`, 'E%')
|
}).where(`name like`, 'E%')
|
||||||
|
if (require('semver').gte(cds.version, '5.9.0')) {
|
||||||
|
expect(authors).to.containSubset([
|
||||||
|
{
|
||||||
|
name: 'Emily Brontë',
|
||||||
|
books: [
|
||||||
|
{
|
||||||
|
title: 'Wuthering Heights',
|
||||||
|
currency: { name: 'British Pound', symbol: '£' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Edgar Allen Poe',
|
||||||
|
books: [
|
||||||
|
{ title: 'The Raven', currency: { name: 'US Dollar', symbol: '$' } },
|
||||||
|
{ title: 'Eleonora', currency: { name: 'US Dollar', symbol: '$' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
return
|
||||||
|
}
|
||||||
expect(authors).to.containSubset([
|
expect(authors).to.containSubset([
|
||||||
{
|
{
|
||||||
name: 'Emily Brontë',
|
name: 'Emily Brontë',
|
||||||
|
|||||||
@@ -35,6 +35,21 @@ describe('Hierarchical Data', ()=>{
|
|||||||
))
|
))
|
||||||
|
|
||||||
it ('supports nested reads', async()=>{
|
it ('supports nested reads', async()=>{
|
||||||
|
if (require('semver').gte(cds.version, '5.9.0')) {
|
||||||
|
expect (await
|
||||||
|
SELECT.one.from (Cats, c=>{
|
||||||
|
c.ID, c.name.as('parent'), c.children (c=>{
|
||||||
|
c.name.as('child')
|
||||||
|
})
|
||||||
|
}) .where ({name:'Cat'})
|
||||||
|
) .to.eql (
|
||||||
|
{ ID:101, parent:'Cat', children:[
|
||||||
|
{ child:'Kitty' },
|
||||||
|
{ child:'Catwoman' },
|
||||||
|
]}
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
expect (await
|
expect (await
|
||||||
SELECT.one.from (Cats, c=>{
|
SELECT.one.from (Cats, c=>{
|
||||||
c.ID, c.name.as('parent'), c.children (c=>{
|
c.ID, c.name.as('parent'), c.children (c=>{
|
||||||
@@ -50,6 +65,25 @@ describe('Hierarchical Data', ()=>{
|
|||||||
})
|
})
|
||||||
|
|
||||||
it ('supports deeply nested reads', async()=>{
|
it ('supports deeply nested reads', async()=>{
|
||||||
|
if (require('semver').gte(cds.version, '5.9.0')) {
|
||||||
|
expect (await SELECT.one.from (Cats, c=>{
|
||||||
|
c.ID, c.name, c.children (
|
||||||
|
c => { c.name },
|
||||||
|
{levels:3}
|
||||||
|
)
|
||||||
|
}) .where ({name:'Cat'})
|
||||||
|
) .to.eql (
|
||||||
|
{ ID:101, name:'Cat', children:[
|
||||||
|
{ name:'Kitty', children:[
|
||||||
|
{ name:'Kitty Cat', children:[
|
||||||
|
{ name:'Aristocat' }, ]}, // level 3
|
||||||
|
{ name:'Kitty Bat', children:[] }, ]},
|
||||||
|
{ name:'Catwoman', children:[
|
||||||
|
{ name:'Catalina', children:[] } ]},
|
||||||
|
]}
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
expect (await SELECT.one.from (Cats, c=>{
|
expect (await SELECT.one.from (Cats, c=>{
|
||||||
c.ID, c.name, c.children (
|
c.ID, c.name, c.children (
|
||||||
c => { c.name },
|
c => { c.name },
|
||||||
|
|||||||
Reference in New Issue
Block a user