Merge branch 'main' into addCustomRules
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
"globals": {
|
"globals": {
|
||||||
"SELECT": true,
|
"SELECT": true,
|
||||||
"INSERT": true,
|
"INSERT": true,
|
||||||
|
"UPSERT": true,
|
||||||
"UPDATE": true,
|
"UPDATE": true,
|
||||||
"DELETE": true,
|
"DELETE": true,
|
||||||
"CREATE": true,
|
"CREATE": true,
|
||||||
|
|||||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: This channel is CLOSED.
|
||||||
|
about: Use SAP community instead
|
||||||
|
url: https://answers.sap.com/tags/9f13aee1-834c-4105-8e43-ee442775e5ce
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
name: This channel is CLOSED.
|
|
||||||
about: Use our community at https://answers.sap.com/tags/9f13aee1-834c-4105-8e43-ee442775e5ce
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Please use our community on https://answers.sap.com/tags/9f13aee1-834c-4105-8e43-ee442775e5ce
|
|
||||||
@@ -12,7 +12,11 @@ using { sap.capire.bookshop.Books } from '@capire/bookshop';
|
|||||||
using { ReviewsService.Reviews } from '@capire/reviews';
|
using { ReviewsService.Reviews } from '@capire/reviews';
|
||||||
extend Books with {
|
extend Books with {
|
||||||
reviews : Composition of many Reviews on reviews.subject = $self.ID;
|
reviews : Composition of many Reviews on reviews.subject = $self.ID;
|
||||||
|
|
||||||
|
@Common.Label : '{i18n>Rating}'
|
||||||
rating : Decimal;
|
rating : Decimal;
|
||||||
|
|
||||||
|
@Common.Label : '{i18n>NumberOfReviews}'
|
||||||
numberOfReviews : Integer;
|
numberOfReviews : Integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,16 +6,33 @@ Author = Author
|
|||||||
AuthorID = Author ID
|
AuthorID = Author ID
|
||||||
Stock = Stock
|
Stock = Stock
|
||||||
Name = Name
|
Name = Name
|
||||||
|
Description = Description
|
||||||
|
Image = Image
|
||||||
AuthorName = Author's Name
|
AuthorName = Author's Name
|
||||||
DateOfBirth = Date of Birth
|
DateOfBirth = Date of Birth
|
||||||
DateOfDeath = Date of Death
|
DateOfDeath = Date of Death
|
||||||
PlaceOfBirth = Place of Birth
|
PlaceOfBirth = Place of Birth
|
||||||
PlaceOfDeath = Place of Death
|
PlaceOfDeath = Place of Death
|
||||||
Age = Age
|
Age = Age
|
||||||
|
Lifetime = Lifetime
|
||||||
Authors = Authors
|
Authors = Authors
|
||||||
|
|
||||||
Order = Order
|
Order = Order
|
||||||
Orders = Orders
|
Orders = Orders
|
||||||
|
OrderNo = Order Number
|
||||||
|
OrderItems = Order Items
|
||||||
|
Customer = Customer
|
||||||
|
Product = Product
|
||||||
|
ProductID = Product ID
|
||||||
|
ProductTitle = Product Title
|
||||||
|
UnitPrice = Unit Price
|
||||||
|
Quantity = Quantity
|
||||||
|
|
||||||
Price = Price
|
Price = Price
|
||||||
|
Currency = Currency
|
||||||
|
Date = Date
|
||||||
|
Rating = Rating
|
||||||
|
NumberOfReviews = Number of Reviews
|
||||||
|
|
||||||
Genre = Genre
|
Genre = Genre
|
||||||
Genres = Genres
|
Genres = Genres
|
||||||
|
|||||||
@@ -43,5 +43,10 @@ extend sap.capire.bookshop.Authors with {
|
|||||||
virtual lifetime : String;
|
virtual lifetime : String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
annotate AdminService.Authors with {
|
||||||
|
age @Common.Label : '{i18n>Age}';
|
||||||
|
lifetime @Common.Label : '{i18n>Lifetime}'
|
||||||
|
}
|
||||||
|
|
||||||
// Workaround for Fiori popup for asking user to enter a new UUID on Create
|
// Workaround for Fiori popup for asking user to enter a new UUID on Create
|
||||||
annotate AdminService.Authors with { ID @Core.Computed; }
|
annotate AdminService.Authors with { ID @Core.Computed; }
|
||||||
|
|||||||
@@ -62,6 +62,11 @@ annotate AdminService.Books.texts with @(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
annotate AdminService.Books.texts with {
|
||||||
|
ID @UI.Hidden;
|
||||||
|
ID_texts @UI.Hidden;
|
||||||
|
};
|
||||||
|
|
||||||
// Add Value Help for Locales
|
// Add Value Help for Locales
|
||||||
annotate AdminService.Books.texts {
|
annotate AdminService.Books.texts {
|
||||||
locale @(
|
locale @(
|
||||||
|
|||||||
@@ -52,9 +52,6 @@ annotate CatalogService.Books with @(UI : {
|
|||||||
},
|
},
|
||||||
{Value : genre.name},
|
{Value : genre.name},
|
||||||
{Value : price},
|
{Value : price},
|
||||||
{
|
{Value : currency.symbol},
|
||||||
Value : currency.symbol,
|
|
||||||
Label : ' '
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
}, );
|
}, );
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
using { sap.capire.bookshop as my } from '@capire/bookstore';
|
using { sap.capire.bookshop as my } from '@capire/bookstore';
|
||||||
using { sap.common } from '@capire/common';
|
using { sap.common } from '@capire/common';
|
||||||
|
using { sap.common.Currencies } from '@sap/cds/common';
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -25,7 +26,7 @@ annotate my.Books with @(
|
|||||||
{ Value: genre.name },
|
{ Value: genre.name },
|
||||||
{ Value: stock },
|
{ Value: stock },
|
||||||
{ Value: price },
|
{ Value: price },
|
||||||
{ Value: currency.symbol, Label: ' ' },
|
{ Value: currency.symbol },
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
@@ -37,6 +38,10 @@ annotate my.Books with @(
|
|||||||
author @ValueList.entity : 'Authors';
|
author @ValueList.entity : 'Authors';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
annotate Currencies with {
|
||||||
|
symbol @Common.Label : '{i18n>Currency}';
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Books Details
|
// Books Details
|
||||||
@@ -60,7 +65,8 @@ annotate my.Books with {
|
|||||||
author @title: '{i18n>Author}' @Common: { Text: author.name, TextArrangement: #TextOnly };
|
author @title: '{i18n>Author}' @Common: { Text: author.name, TextArrangement: #TextOnly };
|
||||||
price @title: '{i18n>Price}' @Measures.ISOCurrency : currency_code;
|
price @title: '{i18n>Price}' @Measures.ISOCurrency : currency_code;
|
||||||
stock @title: '{i18n>Stock}';
|
stock @title: '{i18n>Stock}';
|
||||||
descr @UI.MultiLineText;
|
descr @title: '{i18n>Description}' @UI.MultiLineText;
|
||||||
|
image @title: '{i18n>Image}';
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -81,6 +87,10 @@ annotate my.Genres with @(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
annotate my.Genres with {
|
||||||
|
ID @Common.Text : name @Common.TextArrangement : #TextOnly;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Genre Details
|
// Genre Details
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
module.exports = class say {
|
module.exports = class say {
|
||||||
hello(req) { return `Hello ${req.data.to}!` }
|
hello(req) {
|
||||||
|
let {to} = req.data
|
||||||
|
if (to === 'me') to = require('os').userInfo().username
|
||||||
|
return `Hello ${to}!`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
76
loggers/app/loggers.html
Normal file
76
loggers/app/loggers.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title> cds.log </title>
|
||||||
|
<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/vue@3/dist/vue.global.prod.js"></script>
|
||||||
|
<style>
|
||||||
|
select { border-color: transparent; padding: 4px 12px; margin: 0px; }
|
||||||
|
button { padding: 2px 11px; margin: 0px 4px; font: 90% italic; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="small-container" , style="margin-top: 70px;">
|
||||||
|
<div id='app'>
|
||||||
|
<h1> Log Levels </h1>
|
||||||
|
<input type="text" placeholder="Search by ID or Log Level..." @input="fetch">
|
||||||
|
<table id='loggers'>
|
||||||
|
<thead>
|
||||||
|
<th> Module ID </th>
|
||||||
|
<th> Log Level </th>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="each in list">
|
||||||
|
<td>{{ each.id }}</td>
|
||||||
|
<td><select v-bind:id="each.id" v-model="each.level" @change="set">
|
||||||
|
<option>SILENT</option>
|
||||||
|
<option>ERROR</option>
|
||||||
|
<option>WARN</option>
|
||||||
|
<option>INFO</option>
|
||||||
|
<option>DEBUG</option>
|
||||||
|
<option>TRACE</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h4>Log Format:</h4>
|
||||||
|
[ <button class="round-button" :class={'muted-button':!format.timestamp} @click="toggle_format" id="timestamp">Timestamp </button>
|
||||||
|
| <button class="round-button" :class={'muted-button':!format.level} @click="toggle_format" id="level">Log Level </button>
|
||||||
|
| <button class="round-button" :class={'muted-button':!format.tenant} @click="toggle_format" id="tenant">Tenant </button>
|
||||||
|
| <button class="round-button" :class={'muted-button':!format.reqid} @click="toggle_format" id="reqid">Request ID </button>
|
||||||
|
| <button class="round-button" :class={'muted-button':!format.id} @click="toggle_format" id="module">Logger ID </button>
|
||||||
|
] - <i>log message ...</i>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
axios.defaults.headers['Content-Type'] = 'application/json'
|
||||||
|
axios.defaults.baseURL = '/log'
|
||||||
|
const loggers = Vue.createApp({ el: '#app',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
format: { timestamp:false, level:false, tenant:false, reqid:false, id:true, },
|
||||||
|
list: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetch (eve) {
|
||||||
|
this.list = (await axios.get (`/Loggers${
|
||||||
|
eve && eve.target.value ? `?$search=${eve.target.value}` : ''
|
||||||
|
}`)).data
|
||||||
|
},
|
||||||
|
async set (eve) {
|
||||||
|
const { id, value:level } = eve.target
|
||||||
|
await axios.put (`/Logger/${id}`, {id,level})
|
||||||
|
},
|
||||||
|
async toggle_format (eve) {
|
||||||
|
this.format[eve.target.id] = !this.format[eve.target.id]
|
||||||
|
await axios.post (`/format`, this.format)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).mount('#app')
|
||||||
|
loggers.fetch() // initially fill list of loggers
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
||||||
22
loggers/package.json
Normal file
22
loggers/package.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "@capire/loggers",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Simple sample on how to dynamically set cds.log levels and formats.",
|
||||||
|
"files": [
|
||||||
|
"app",
|
||||||
|
"srv"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@sap/cds": ">=5.9",
|
||||||
|
"express": "^4.17.1"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "cds run",
|
||||||
|
"watch": "cds watch"
|
||||||
|
},
|
||||||
|
"cds": {
|
||||||
|
"requires": {
|
||||||
|
"db": "sql"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
loggers/readme.md
Normal file
11
loggers/readme.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Dynamically Set `cds.log` Levels and Formats
|
||||||
|
|
||||||
|
### Run
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cds watch
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test
|
||||||
|
|
||||||
|
Either using the UI through http://localhost:4004/loggers.html, or try the requests in `test/requests.http`
|
||||||
3
loggers/srv/dummy.cds
Normal file
3
loggers/srv/dummy.cds
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
service Sue {
|
||||||
|
entity Dummy { key ID: UUID; title: String; }
|
||||||
|
}
|
||||||
20
loggers/srv/loggers.cds
Normal file
20
loggers/srv/loggers.cds
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@rest service LogService {
|
||||||
|
|
||||||
|
@readonly entity Loggers : Logger {};
|
||||||
|
entity Logger {
|
||||||
|
key id : String;
|
||||||
|
level : String;
|
||||||
|
}
|
||||||
|
|
||||||
|
action format (
|
||||||
|
timestamp : Boolean,
|
||||||
|
level : Boolean,
|
||||||
|
tenant : Boolean,
|
||||||
|
reqid : Boolean,
|
||||||
|
id : Boolean,
|
||||||
|
);
|
||||||
|
|
||||||
|
action debug (logger : String) returns Logger;
|
||||||
|
action reset (logger : String) returns Logger;
|
||||||
|
|
||||||
|
}
|
||||||
56
loggers/srv/loggers.js
Normal file
56
loggers/srv/loggers.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
const cds = require ('@sap/cds/lib')
|
||||||
|
const LOG = cds.log('cds.log')
|
||||||
|
|
||||||
|
module.exports = class LogService extends cds.Service {
|
||||||
|
init(){
|
||||||
|
|
||||||
|
this.on('GET','Loggers', (req)=>{
|
||||||
|
let loggers = Object.values(cds.log.loggers).map (_logger)
|
||||||
|
let {$search} = req._.req.query
|
||||||
|
if ($search) {
|
||||||
|
const re = RegExp($search,'i')
|
||||||
|
loggers = loggers.filter (l => re.test(l.id) || re.test(l.level))
|
||||||
|
}
|
||||||
|
return loggers.sort ((a,b) => a.id < b.id ? -1 : 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.on('PUT','Logger', (req)=>{
|
||||||
|
const {id} = req.params[0] || req.data
|
||||||
|
if (!id) return req.reject('No logger id specified in request')
|
||||||
|
return _logger (cds.log (id, req.data))
|
||||||
|
})
|
||||||
|
|
||||||
|
this.on('debug', (req)=>{
|
||||||
|
const {logger:id} = req.params[0] || req.data
|
||||||
|
if (!id) return req.reject('No logger id specified in request')
|
||||||
|
return _logger (cds.log (id, {level:'debug'}))
|
||||||
|
})
|
||||||
|
|
||||||
|
this.on('reset', (req)=>{
|
||||||
|
const {logger:id} = req.params[0] || req.data
|
||||||
|
if (!id) return req.reject('No logger id specified in request')
|
||||||
|
return _logger (cds.log (id, {level:'info'}))
|
||||||
|
})
|
||||||
|
|
||||||
|
this.on('format', (req)=>{
|
||||||
|
const $ = req.data; LOG.info('format:',$)
|
||||||
|
// Set format for new loggers constructed subsequently
|
||||||
|
cds.log.format = (id, level, ...args) => {
|
||||||
|
const fmt = []
|
||||||
|
if ($.timestamp) fmt.push ('|', (new Date).toISOString())
|
||||||
|
if ($.level) fmt.push ('|', _levels[level].padEnd(5))
|
||||||
|
if ($.tenant) fmt.push ('|', cds.context && cds.context.tenant)
|
||||||
|
if ($.reqid) fmt.push ('|', cds.context && cds.context.id)
|
||||||
|
if ($.id) fmt.push ('|', id)
|
||||||
|
fmt[0] = '[', fmt.push ('] -', ...args)
|
||||||
|
return fmt
|
||||||
|
}
|
||||||
|
// Apply this format to all existing loggers
|
||||||
|
Object.values(cds.log.loggers).forEach (l => l.setFormat (cds.log.format))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const _logger = ({id,level}) => ({id, level:_levels[level] })
|
||||||
|
const _levels = [ 'SILENT', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE' ]
|
||||||
18
loggers/test/requests.http
Normal file
18
loggers/test/requests.http
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
http://localhost:4004/loggers.html
|
||||||
|
@body: = Content-Type: application/json\n\n
|
||||||
|
|
||||||
|
###
|
||||||
|
GET http://localhost:4004/log/Loggers
|
||||||
|
|
||||||
|
###
|
||||||
|
PUT http://localhost:4004/log/Logger/sqlite
|
||||||
|
{{body:}} { "level": "debug" }
|
||||||
|
|
||||||
|
###
|
||||||
|
POST http://localhost:4004/log/debug(logger='sqlite')
|
||||||
|
|
||||||
|
###
|
||||||
|
POST http://localhost:4004/log/reset(logger='sqlite')
|
||||||
|
|
||||||
|
### Dummy request to see sqlite debug output
|
||||||
|
GET http://localhost:4004/sue/Dummy
|
||||||
@@ -40,7 +40,7 @@ module.exports = srv => {
|
|||||||
req.reject(404, 'Media not found for the ID')
|
req.reject(404, 'Media not found for the ID')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const decodedMedia = new Buffer(
|
const decodedMedia = Buffer.from(
|
||||||
mediaObj.media.split(';base64,').pop(),
|
mediaObj.media.split(';base64,').pop(),
|
||||||
'base64'
|
'base64'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,22 +18,22 @@ annotate OrdersService.Orders with @(
|
|||||||
UI: {
|
UI: {
|
||||||
SelectionFields: [ createdBy ],
|
SelectionFields: [ createdBy ],
|
||||||
LineItem: [
|
LineItem: [
|
||||||
{Value: OrderNo, Label:'OrderNo'},
|
{Value: OrderNo, Label:'{i18n>OrderNo}'},
|
||||||
{Value: buyer, Label:'Customer'},
|
{Value: buyer, Label:'{i18n>Customer}'},
|
||||||
{Value: currency.symbol, Label:'Currency'},
|
{Value: currency.symbol, Label:'{i18n>Currency}'},
|
||||||
{Value: createdAt, Label:'Date'},
|
{Value: createdAt, Label:'{i18n>Date}'},
|
||||||
],
|
],
|
||||||
HeaderInfo: {
|
HeaderInfo: {
|
||||||
TypeName: 'Order', TypeNamePlural: 'Orders',
|
TypeName: '{i18n>Order}', TypeNamePlural: '{i18n>Orders}',
|
||||||
Title: {
|
Title: {
|
||||||
Label: 'Order number ', //A label is possible but it is not considered on the ObjectPage yet
|
Label: '{i18n>OrderNo}', //A label is possible but it is not considered on the ObjectPage yet
|
||||||
Value: OrderNo
|
Value: OrderNo
|
||||||
},
|
},
|
||||||
Description: {Value: createdBy}
|
Description: {Value: createdBy}
|
||||||
},
|
},
|
||||||
Identification: [ //Is the main field group
|
Identification: [ //Is the main field group
|
||||||
{Value: createdBy, Label:'Customer'},
|
{Value: createdBy, Label:'{i18n>Customer}'},
|
||||||
{Value: createdAt, Label:'Date'},
|
{Value: createdAt, Label:'{i18n>Date}'},
|
||||||
{Value: OrderNo },
|
{Value: OrderNo },
|
||||||
],
|
],
|
||||||
HeaderFacets: [
|
HeaderFacets: [
|
||||||
@@ -46,7 +46,7 @@ annotate OrdersService.Orders with @(
|
|||||||
],
|
],
|
||||||
FieldGroup#Details: {
|
FieldGroup#Details: {
|
||||||
Data: [
|
Data: [
|
||||||
{Value: currency.code, Label:'Currency'}
|
{Value: currency.code, Label:'{i18n>Currency}'}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
FieldGroup#Created: {
|
FieldGroup#Created: {
|
||||||
@@ -65,6 +65,7 @@ annotate OrdersService.Orders with @(
|
|||||||
) {
|
) {
|
||||||
createdAt @UI.HiddenFilter:false;
|
createdAt @UI.HiddenFilter:false;
|
||||||
createdBy @UI.HiddenFilter:false;
|
createdBy @UI.HiddenFilter:false;
|
||||||
|
ID @UI.Hidden;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -72,15 +73,15 @@ annotate OrdersService.Orders with @(
|
|||||||
annotate OrdersService.Orders.Items with @(
|
annotate OrdersService.Orders.Items with @(
|
||||||
UI: {
|
UI: {
|
||||||
LineItem: [
|
LineItem: [
|
||||||
{Value: product_ID, Label:'Product ID'},
|
{Value: product_ID, Label:'{i18n>ProductID}'},
|
||||||
{Value: title, Label:'Product Title'},
|
{Value: title, Label:'{i18n>ProductTitle}'},
|
||||||
{Value: price, Label:'Unit Price'},
|
{Value: price, Label:'{i18n>UnitPrice}'},
|
||||||
{Value: quantity, Label:'Quantity'},
|
{Value: quantity, Label:'{i18n>Quantity}'},
|
||||||
],
|
],
|
||||||
Identification: [ //Is the main field group
|
Identification: [ //Is the main field group
|
||||||
{Value: quantity, Label:'Quantity'},
|
{Value: quantity, Label:'{i18n>Quantity}'},
|
||||||
{Value: title, Label:'Product'},
|
{Value: title, Label:'{i18n>Product}'},
|
||||||
{Value: price, Label:'Unit Price'},
|
{Value: price, Label:'{i18n>UnitPrice}'},
|
||||||
],
|
],
|
||||||
Facets: [
|
Facets: [
|
||||||
{$Type: 'UI.ReferenceFacet', Label: '{i18n>OrderItems}', Target: '@UI.Identification'},
|
{$Type: 'UI.ReferenceFacet', Label: '{i18n>OrderItems}', Target: '@UI.Identification'},
|
||||||
@@ -90,4 +91,7 @@ annotate OrdersService.Orders.Items with @(
|
|||||||
quantity @(
|
quantity @(
|
||||||
Common.FieldControl: #Mandatory
|
Common.FieldControl: #Mandatory
|
||||||
);
|
);
|
||||||
|
ID @UI.Hidden;
|
||||||
|
up_ @UI.Hidden;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
44
package-lock.json
generated
44
package-lock.json
generated
@@ -431,9 +431,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sap/cds": {
|
"node_modules/@sap/cds": {
|
||||||
"version": "6.2.2",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@sap/cds/-/cds-6.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@sap/cds/-/cds-6.3.1.tgz",
|
||||||
"integrity": "sha512-l1ps/Ofp+0k/ngSrCHBFNUXQew6n9A4OJhrm3CroxIEq8wQeXB5LBq53YQQYoCj807eQlXbVbzg6hRCm+BgDaQ==",
|
"integrity": "sha512-EywUoV16yfYMMEgpY5M4NdNrdjw7dPcIK5c+pAVjio+16PDa7l2x81AhO/JNWD7g7j/POsNUc2ry+LtRxUuceQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sap/cds-compiler": "^3.2.0",
|
"@sap/cds-compiler": "^3.2.0",
|
||||||
"@sap/cds-foss": "^4"
|
"@sap/cds-foss": "^4"
|
||||||
@@ -442,7 +442,7 @@
|
|||||||
"cds": "bin/cds.js"
|
"cds": "bin/cds.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.15.0"
|
"node": ">=14.18.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sap/cds-compiler": {
|
"node_modules/@sap/cds-compiler": {
|
||||||
@@ -962,14 +962,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chai": {
|
"node_modules/chai": {
|
||||||
"version": "4.3.6",
|
"version": "4.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
|
||||||
"integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==",
|
"integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"assertion-error": "^1.1.0",
|
"assertion-error": "^1.1.0",
|
||||||
"check-error": "^1.0.2",
|
"check-error": "^1.0.2",
|
||||||
"deep-eql": "^3.0.1",
|
"deep-eql": "^4.1.2",
|
||||||
"get-func-name": "^2.0.0",
|
"get-func-name": "^2.0.0",
|
||||||
"loupe": "^2.3.1",
|
"loupe": "^2.3.1",
|
||||||
"pathval": "^1.1.1",
|
"pathval": "^1.1.1",
|
||||||
@@ -1165,15 +1165,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/deep-eql": {
|
"node_modules/deep-eql": {
|
||||||
"version": "3.0.1",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.2.tgz",
|
||||||
"integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
|
"integrity": "sha512-gT18+YW4CcW/DBNTwAmqTtkJh7f9qqScu2qFVlx7kCoeY9tlBu9cUcr7+I+Z/noG8INehS3xQgLpTtd/QUTn4w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"type-detect": "^4.0.0"
|
"type-detect": "^4.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.12"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/deep-is": {
|
"node_modules/deep-is": {
|
||||||
@@ -4191,9 +4191,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sap/cds": {
|
"@sap/cds": {
|
||||||
"version": "6.2.2",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@sap/cds/-/cds-6.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@sap/cds/-/cds-6.3.1.tgz",
|
||||||
"integrity": "sha512-l1ps/Ofp+0k/ngSrCHBFNUXQew6n9A4OJhrm3CroxIEq8wQeXB5LBq53YQQYoCj807eQlXbVbzg6hRCm+BgDaQ==",
|
"integrity": "sha512-EywUoV16yfYMMEgpY5M4NdNrdjw7dPcIK5c+pAVjio+16PDa7l2x81AhO/JNWD7g7j/POsNUc2ry+LtRxUuceQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sap/cds-compiler": "^3.2.0",
|
"@sap/cds-compiler": "^3.2.0",
|
||||||
"@sap/cds-foss": "^4"
|
"@sap/cds-foss": "^4"
|
||||||
@@ -4612,14 +4612,14 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"chai": {
|
"chai": {
|
||||||
"version": "4.3.6",
|
"version": "4.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
|
||||||
"integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==",
|
"integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"assertion-error": "^1.1.0",
|
"assertion-error": "^1.1.0",
|
||||||
"check-error": "^1.0.2",
|
"check-error": "^1.0.2",
|
||||||
"deep-eql": "^3.0.1",
|
"deep-eql": "^4.1.2",
|
||||||
"get-func-name": "^2.0.0",
|
"get-func-name": "^2.0.0",
|
||||||
"loupe": "^2.3.1",
|
"loupe": "^2.3.1",
|
||||||
"pathval": "^1.1.1",
|
"pathval": "^1.1.1",
|
||||||
@@ -4762,9 +4762,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"deep-eql": {
|
"deep-eql": {
|
||||||
"version": "3.0.1",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.2.tgz",
|
||||||
"integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
|
"integrity": "sha512-gT18+YW4CcW/DBNTwAmqTtkJh7f9qqScu2qFVlx7kCoeY9tlBu9cUcr7+I+Z/noG8INehS3xQgLpTtd/QUTn4w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"type-detect": "^4.0.0"
|
"type-detect": "^4.0.0"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"./hello",
|
"./hello",
|
||||||
"./media",
|
"./media",
|
||||||
"./orders",
|
"./orders",
|
||||||
|
"./loggers",
|
||||||
"./reviews"
|
"./reviews"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -128,11 +128,11 @@ describe('cap/samples - Bookshop APIs', () => {
|
|||||||
it('serves user info', async () => {
|
it('serves user info', async () => {
|
||||||
{
|
{
|
||||||
const { data } = await GET (`/user/me`)
|
const { data } = await GET (`/user/me`)
|
||||||
expect(data).to.containSubset({ id: 'alice', locale:'en', tenant: null })
|
expect(data).to.containSubset({ id: 'alice', locale:'en' })
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const { data } = await GET (`/user/me`, {auth: { username: 'joe' }})
|
const { data } = await GET (`/user/me`, {auth: { username: 'joe' }})
|
||||||
expect(data).to.containSubset({ id: 'joe', locale:'en', tenant: null })
|
expect(data).to.containSubset({ id: 'joe', locale:'en' })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user