GithubHelp home page GithubHelp logo

cap-js / change-tracking Goto Github PK

View Code? Open in Web Editor NEW
12.0 10.0 5.0 3.85 MB

CDS plugin providing out-of-the box support for automatic capturing, storing, and viewing of the change records of modeled entities.

Home Page: https://cap.cloud.sap/docs

License: Apache License 2.0

CAP CDS 11.71% JavaScript 88.29%
cap cds change-tracking nodejs sap-btp sap-cap

change-tracking's Introduction

Change Tracking Plugin for SAP Cloud Application Programming Model (CAP)

REUSE status

The @cap-js/change-tracking package is a CDS plugin providing out-of-the box support for automatic capturing, storing, and viewing of the change records of modeled entities as simple as that:

  1. Install the plugin: npm add @cap-js/change-tracking
  2. Add @changelog annotations to your CDS models
  3. Et voilà:

change-history-loading

Table of Contents

Preliminaries

In this guide, we use the Incidents Management reference sample app as the base to add change tracking to. Clone the repository and apply the step-by-step instructions:

git clone https://github.com/cap-js/incidents-app
cd incidents-app
npm i

Alternatively, you can clone the incidents app including the prepared enhancements for change-tracking:

git clone https://github.com/cap-js/calesi --recursive
cd calesi
npm i
cds w samples/change-tracking

Setup

To enable change tracking, simply add this self-configuring plugin package to your project:

npm add @cap-js/change-tracking

Annotations

Warning

Please be aware that sensitive or personal data should not be change tracked, since viewing the log allows users to circumvent audit-logging.

All we need to do is to identify what should be change-tracked by annotating respective entities and elements in our model with the @changelog annotation. Following the best practice of separation of concerns, we do so in a separate file srv/change-tracking.cds:

using { ProcessorService } from './processor-service';

annotate ProcessorService.Incidents {
  customer @changelog: [customer.name];
  title    @changelog;
  status   @changelog;
}

annotate ProcessorService.Conversations with @changelog: [author, timestamp] {
  message  @changelog @Common.Label: 'Message';
}

The minimal annotation we require for change tracking is @changelog on elements, as for the elements title and status in the sample snippet above.

Additional identifiers or labels can be added to obtain more human-readable change records as described below.

Human-readable Types and Fields

By default the implementation looks up Object Type names or Field namesfrom respective @title or @Common.Label annotations, and applies i18n lookups. If no such annotations are given, the technical names of the respective CDS definitions are displayed.

For example, without the @title annotation, changes to conversation entries would show up with the technical entity name:

change-history-type

With an annotation, and possible i18n translations like so:

annotate Conversations with @title: 'Conversations';

We get a human-readable display for Object Type:

change-history-type-hr

Human-readable IDs

The changelog annotations for Object ID are defined at entity level.

These are already human-readable by default, unless the @changelog definition cannot be uniquely mapped such as types enum or Association.

For example, having a @changelog annotation without any additional identifiers, changes to conversation entries would show up as simple entity IDs:

annotate ProcessorService.Conversations {

change-history-id

However, this is not advisable as we cannot easily distinguish between changes. It is more appropriate to annotate as follows:

annotate ProcessorService.Conversations with @changelog: [author, timestamp] {

change-history-id-hr

Expanding the changelog annotation by additional identifiers [author, timestamp], we can now better identify the message change events by their respective author and timestamp.

Human-readable Values

The changelog annotations for New Value and Old Value are defined at element level.

They are already human-readable by default, unless the @changelog definition cannot be uniquely mapped such as types enum or Association.

For example, having a @changelog annotation without any additional identifiers, changes to incident customer would show up as UUIDs:

customer @changelog;

change-history-value

Hence, here it is essential to add a unique identifier to obtain human-readable value columns:

customer @changelog: [customer.name];

change-history-value-hr

Test-drive locally

With the steps above, we have successfully set up change tracking for our reference application. Let's see that in action.

  1. Start the server:
cds watch
  1. Make a change on your change-tracked elements. This change will automatically be persisted in the database table (sap.changelog.ChangeLog) and made available in a pre-defined view, namely the Change History view for your convenience.

Change History View

Important

To ensure proper lazy loading of the Change History table, please use SAPUI5 version 1.120.0 or higher.
If you wish to disable this feature, please see the customization section on how to disable lazy loading.

change-history

If you have a Fiori Element application, the CDS plugin automatically provides and generates a view sap.changelog.ChangeView, the facet of which is automatically added to the Fiori Object Page of your change-tracked entities/elements. In the UI, this corresponds to the Change History table which serves to help you to view and search the stored change records of your modeled entities.

Customizations

Altered table view

The Change History view can be easily adapted and configured to your own needs by simply changing or extending it. For example, let's assume we only want to show the first 5 columns in equal spacing, we would extend srv/change-tracking.cds as follows:

using from '@cap-js/change-tracking';

annotate sap.changelog.ChangeView with @(
  UI.LineItem : [
    { Value: modification, @HTML5.CssDefaults: { width:'20%' }},
    { Value: createdAt,    @HTML5.CssDefaults: { width:'20%' }},
    { Value: createdBy,    @HTML5.CssDefaults: { width:'20%' }},
    { Value: entity,       @HTML5.CssDefaults: { width:'20%' }},
    { Value: objectID,     @HTML5.CssDefaults: { width:'20%' }}
  ]
);

In the UI, the Change History table now contains 5 equally-spaced columns with the desired properties:

change-history-custom

For more information and examples on adding Fiori Annotations, see Adding SAP Fiori Annotations.

Disable lazy loading

To disable the lazy loading feature of the Change History table, you can add the following annotation to your srv/change-tracking.cds:

using from '@cap-js/change-tracking';

annotate sap.changelog.aspect @(UI.Facets: [{
  $Type : 'UI.ReferenceFacet',
  ID    : 'ChangeHistoryFacet',
  Label : '{i18n>ChangeHistory}',
  Target: 'changes/@UI.PresentationVariant',
  ![@UI.PartOfPreview]
}]);

The system now uses the SAPUI5 default setting ![@UI.PartOfPreview]: true, such that the table will always shown when navigating to that respective Object page.

Disable UI Facet generation

If you do not want the UI facet added to a specific UI, you can annotate the service entity with @changelog.disable_facet. This will disable the automatic addition of the UI faced to this specific entity, but also all views or further projections up the chain.

Disable Association to Changes Generation

For some scenarios, e.g. when doing UNION and the @changelog annotion is still propageted, the automatic addition of the association to changes does not make sense. You can use @changelog.disable_assocfor this to be disabled on entity level.

Important

This will also supress the addition of the UI facet, since the change-view is not available as target entity anymore.

Modelling Samples

This chapter describes more modelling cases for further reference, from simple to complex, including but not limited to the followings.

Specify Object ID

Use cases for Object ID annotation

Use Case 1: Annotate single field/multiple fields of associated table(s) as the Object ID

Modelling in db/schema.cds

entity Incidents : cuid, managed {
  ...
  customer       : Association to Customers;
  title          : String @title: 'Title';
  urgency        : Association to Urgency default 'M';
  status         : Association to Status default 'N';
  ...
}

Add the following @changelog annotations in srv/change-tracking.cds

annotate ProcessorService.Incidents with @changelog: [customer.name, urgency.code, status.criticality] {
  title    @changelog;
}

AssociationID

Use Case 2: Annotate single field/multiple fields of project customized types as the Object ID

Modelling in db/schema.cds

entity Incidents : cuid, managed {
  ...
  customer       : Association to Customers;
  title          : String @title: 'Title';
  ...
}

entity Customers : cuid, managed {
  ...
  email          : EMailAddress;  // customized type
  phone          : PhoneNumber;   // customized type
  ...
}

Add the following @changelog annotations in srv/change-tracking.cds

annotate ProcessorService.Incidents with @changelog: [customer.email, customer.phone] {
  title    @changelog;
}

CustomTypeID

Use Case 3: Annotate chained associated entities from the current entity as the Object ID

Modelling in db/schema.cds

entity Incidents : cuid, managed {
  ...
  customer       : Association to Customers;
  ...
}

entity Customers : cuid, managed {
  ...
  addresses : Association to Addresses;
  ...
}

Add the following @changelog annotations in srv/change-tracking.cds

annotate ProcessorService.Incidents with @changelog: [customer.addresses.city, customer.addresses.postCode] {
  title    @changelog;
}

ChainedAssociationID

Change-tracking supports annotating chained associated entities from the current entity as object ID of current entity in case the entity in consumer applications is a pure relation table. However, the usage of chained associated entities is not recommended due to performance cost.

Tracing Changes

Use cases for tracing changes

Use Case 1: Trace the changes of child nodes from the current entity and display the meaningful data from child nodes (composition relation)

Modelling in db/schema.cds

entity Incidents : managed, cuid {
  ...
  title          : String @title: 'Title';
  conversation   : Composition of many Conversation;
  ...
}

aspect Conversation: managed, cuid {
    ...
    message   : String;
}

Add the following @changelog annotations in srv/change-tracking.cds

annotate ProcessorService.Incidents with @changelog: [title] {
  conversation @changelog: [conversation.message];
}

CompositionChange

Use Case 2: Trace the changes of associated entities from the current entity and display the meaningful data from associated entities (association relation)

Modelling in db/schema.cds

entity Incidents : cuid, managed {
  ...
  customer       : Association to Customers;
  title          : String @title: 'Title';
  ...
}

entity Customers : cuid, managed {
  ...
  email          : EMailAddress;
  ...
}

Add the following @changelog annotations in srv/change-tracking.cds

annotate ProcessorService.Incidents with @changelog: [title] {
  customer @changelog: [customer.email];
}

AssociationChange

Use Case 3: Trace the changes of fields defined by project customized types and display the meaningful data

Modelling in db/schema.cds

type StatusType : Association to Status;

entity Incidents : cuid, managed {
  ...
  title          : String @title: 'Title';
  status         : StatusType default 'N';
  ...
}

Add the following @changelog annotations in srv/change-tracking.cds

annotate ProcessorService.Incidents with @changelog: [title] {
  status   @changelog: [status.code];
}

CustomTypeChange

Use Case 4: Trace the changes of chained associated entities from the current entity and display the meaningful data from associated entities (association relation)

Modelling in db/schema.cds

entity Incidents : cuid, managed {
  ...
  title          : String @title: 'Title';
  customer       : Association to Customers;
  ...
}

entity Customers : cuid, managed {
  ...
  addresses : Association to Addresses;
  ...
}

Add the following @changelog annotations in srv/change-tracking.cds

annotate ProcessorService.Incidents with @changelog: [title] {
  customer @changelog: [customer.addresses.city, customer.addresses.streetAddress];
}

ChainedAssociationChange

Change-tracking supports analyzing chained associated entities from the current entity in case the entity in consumer applications is a pure relation table. However, the usage of chained associated entities is not recommended due to performance cost.

Use Case 5: Trace the changes of union entity and display the meaningful data

Payable.cds:

entity Payables : cuid {
    displayId    : String;
    @changelog
    name         : String;
    cryptoAmount : Decimal;
    fiatAmount   : Decimal;
};

Payment.cds:

entity Payments : cuid {
    displayId : String; //readable ID
    @changelog
    name      : String;
};

Union entity in BusinessTransaction.cds:

entity BusinessTransactions          as(
    select from payments.Payments{
        key ID,
            displayId,
            name,
            changes  : Association to many ChangeView
                on changes.objectID = ID AND changes.entity = 'payments.Payments'
    }
)
union all
(
    select from payables.Payables {
        key ID,
            displayId,
            name,
            changes  : Association to many ChangeView
               on changes.objectID = ID AND changes.entity = 'payables.Payables'
    }
);

UnionChange.png

Don'ts

Don'ts

Use Case 1: Don't trace changes for field(s) with Association to many

entity Customers : cuid, managed {
  ...
  incidents : Association to many Incidents on incidents.customer = $self;
}

The reason is that: the relationship: Association to many is only for modelling purpose and there is no concrete field in database table. In the above sample, there is no column for incidents in the table Customers, but there is a navigation property of incidents in Customers OData entity metadata.

Use Case 2: Don't trace changes for field(s) with Unmanaged Association

entity AggregatedBusinessTransactionData @(cds.autoexpose) : cuid {
    FootprintInventory: Association to one FootprintInventories
                        on  FootprintInventory.month                      = month
                        and FootprintInventory.year                       = year
                        and FootprintInventory.FootprintInventoryScope.ID = FootprintInventoryScope.ID;
    ...
}

The reason is that: When deploying to relational databases, Associations are mapped to foreign keys. Yet, when mapped to non-relational databases they're just references. More details could be found in Prefer Managed Associations. In the above sample, there is no column for FootprintInventory in the table AggregatedBusinessTransactionData, but there is a navigation property FootprintInventoryof in OData entity metadata.

Use Case 3: Don't trace changes for CUD on DB entity

this.on("UpdateActivationStatus", async (req) =>
    // PaymentAgreementsOutgoingDb is the DB entity
    await UPDATE.entity(PaymentAgreementsOutgoingDb)
        .where({ ID: paymentAgreement.ID })
        .set({ ActivationStatus_code: ActivationCodes.ACTIVE });
);

The reason is that: Application level services are by design the only place where business logic is enforced. This by extension means, that it also is the only point where e.g. change-tracking would be enabled. The underlying method used to do change tracking is req.diff which is responsible to read the necessary before-image from the database, and this method is not available on DB level.

Contributing

This project is open to feature requests/suggestions, bug reports etc. via GitHub issues. Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, as well as additional contribution information, see our Contribution Guidelines.

Code of Conduct

We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone. By participating in this project, you agree to abide by its Code of Conduct at all times.

Licensing

Copyright 2023 SAP SE or an SAP affiliate company and contributors. Please see our LICENSE for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available via the REUSE tool.

change-tracking's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

change-tracking's Issues

Changelog for Entities containing associations as key

Hello Team,

currently we are facing an issue using the change log on entities which have associations as keys defined.
Some cases are even more complex, but real world scenarios.

We have one entity called MatrixCertificates which connects the keys of devisions with document types and adds a property called 'relevant'. Divisions are stored within the same project. Document types are not, they are part of a different micro-service in a different cap project according to our designed micro service architecture.

Please find below CDS model:

@cds.persistence.journal
entity Divisions : CodeList {
  key division : String(20);
}

@readonly
entity DocumentTypes as projection on Doc.DocumentTypes;

entity MatrixCertificates {
  @assert.integrity: false key division     : Association to one Divisions;
  @assert.integrity: false key documentType : Association to one DocumentTypes;
                               relevant     : String(1) enum {
                                 a;
                                 b;
                                 c;
                               }
}

We would like to use change-log annotations like this:

@changelog
@cds.persistence.journal
entity Divisions : CodeList {
  key division : String(20);
}

@readonly
entity DocumentTypes as projection on Doc.DocumentTypes;

@changelog
entity MatrixCertificates {
  @assert.integrity: false key division     : Association to one Divisions @changelog;
  @assert.integrity: false key documentType : Association to one DocumentTypes @changelog;
                               relevant     : String(1) enum {
                                 a;
                                 b;
                                 c;
                               };
}

Issue is, that at startup of the service following error occurs:
image

Are you aware about this behaviour? Is it foreseen to be fixed?

Thanks and best regards
Sandro

In the unmanaged case, unmanipulated data also generates a changelog.

Hi,

Here's the situation in incidents-app:

Model:
image

Annotation:

annotate ProcessorService.Incidents with @changelog: [title] {
  conversation @changelog: [conversation.message];
}

As we know, conversation is a inline composition of child entity, This is an unmanaged case. If we want to enable managed for inline composition of child entity, It can be set up as shown below:
image

Above is the background information, then the problem is in the following figure, when we go to an incident page, we will find that there is already a current conversation, so we create a new conversation:
image

And click 'Save' button, you can see that the change history generates two changelogs, but we see that there is an additional changelog generated, which we don't need because we haven't done anything with the original conversation:
image

When we enable aspect managed, generate changelog normally:
image

The reason is:

In req.diff(), the data is logged regardless of whether that data has been manipulated or not, so for the managed case, change-tracking will have a place for logic to filter out data that hasn't been manipulated, because for change-tracking, if it hasn't been manipulated, it shouldn't be logged:

https://github.com/cap-js/change-tracking/blob/main/lib/change-log.js#L189

  // Since req.diff() will record the managed data, change history will filter those logs only be changed managed data
  const managedAttrs = ["modifiedAt", "modifiedBy"]
  if (curChange.modification === "update") {
    const rowOldAttrs = Object.keys(childNodeChange._old)
    const diffAttrs = rowOldAttrs.filter((attr) => managedAttrs.indexOf(attr) === -1)
    if (!diffAttrs.length) {
      return
    }
  }

But for the unmanaged case, the unmanipulated data has no _op in req.diff(), so by the time we get to the logic above, the value of curChange.modification is undefined, so it skips the filtering and is added directly to the changelog, so here's the solution:
image

If you have time, please take a look at this scenario.

Best Regards,
Wenjun

Performance Issues with draftActivate

We encountered severe performance issues when activating a draft with sub entities, because of change-tracking plugin.

If a composite object with multiple sub entity instances is activated, each instance is read one by one from the database. See https://github.com/cap-js/change-tracking/blob/main/lib/entity-helper.js#L34
This leads to drastic performance issues in case there are a lot of sub entity instances. We encountered this, because a customer created 1000 sub entity instances and it took around a minute to activate the composite. Without having change-tracking plugin enabled it takes a fraction of a second.

I expect that db requests are reduced as much as possible and instances of one entity are read all together instead of a single instance basis.

@cap-js/change-tracking: change logs are not captured

Changing "@sap/cds": "6.5.0" to "@sap/cds": "7.5.2".
Before the cds upgrade we used @sap/cap-change-history.
With cds > 7 we thrive for @cap-js/change-tracking instead.

I was able to configure and run everything written for the incidents-app here . However, when applying the exact same steps within our project, I do not see Change History facet automatically added to the Fiori Object Page of my annotated entity. Thus, no changeLog is captured at all.

In the following pictures you will see proper entity level annotations and missing facet over the respective object page:
image

image

Object ID is filled as Object Type

Hi colleagues,

We declared changelog with object ID:

@title : '{i18n>BusinessPartner}'
@changelog.objectID: [
displayId,
name
]
entity BusinessPartners : cuid, managed, SourceReferences, Usage {
@title : '{i18n>ID}'
@changelog
displayId : String; //readable ID

@changelog
name                                 : String;

@mandatory  @changelog: [BusinessPartnerRoleCodes.name]
Role                                 : Association to one BusinessPartnerRoleCodes;

@title    : '{i18n>ContactPerson}'
@changelog
contactPersonFormattedName           : String;

@title    : '{i18n>Email}'
@changelog
contactPersonEmail                   : String;

@title    : '{i18n>Phone}'
@changelog
contactPersonTelephoneNumber         : String;
OutgoingPaymentAgreements            : Composition of many PaymentAgreementsOutgoing
                                           on OutgoingPaymentAgreements.Parent = $self;
IncomingPaymentAgreements            : Composition of many PaymentAgreementsIncoming
                                           on IncomingPaymentAgreements.Parent = $self;

//    Changes                              : Association to many ChangeView
//on Changes.entityKey = ID;

@changelog: [Countries.name]
@title    : '{i18n>Country}' Country : Association to one Countries;

}

With the old plugin change-history Object ID in the ChangeView was shown as defined (for example "BP_1, BP_1_name").

Now, with the new plugin, it is shown with the sane content as the column Object Type.

Is the definition of Object ID wrong?

Kind regards,
Elena Gurevitch

Change History

"Update" change logs are not created in the main test system

Hi colleagues,

We are working on the project https://github.tools.sap/erp4sme/crypto-for-business.

Some time ago we have discussed missing possibility to add changelog changes for an entity that is being processed not from a service (for example, UI service) but is inserted or updated directly on DB.

Meanwhile this issue was solved: we created Wrapper-Services for the involved entities and this solved even the second issue where a view was defined as a union of three different entities and we were not sure how to define change tracking for this.

It looks like (srv\payment\wrapper\wrapper-service.cds):

service PaymentWrapperService @(requires: 'system-user') {
entity Payments as projection on db.payments.Payments;
entity Payables as projection on db.payables.Payables;
entity PaymentOrders as projection on db.paymentOrders.PaymentOrders;
entity Receivables as projection on db.receivables.Receivables;
entity BusinessTransactions as projection on db.businessTransactions.BusinessTransactions;
}

BusinessTransactions is the mentioned view which is a union of Payments, Receivables and Payables.

Now all our DB operations relevant for change-tracking are defined via this service, for example

UPDATE.entity(WrapperService.Entity.Payments).where({ ID: paymentToUpdate.ID }).with(paymentToUpdate);

This works; the changes for all involved entities are written back and shown in the app “business Transactions” based on an UI service defined on the entityBusinessTransactions.

However there is one strange thing.

For creating the entities change logs are written both if you test locally or in the main test system https://c4b-main02-subscriber-1.c4b-main02.dev01.eu.canary.clusters.cs.services.sap/.
However these entities can be also updated. This is happening not from UI but from an Event Handler reacting on some events. For example if a Transfer Order which was created for a Payment becomes completed then the corresponding Payment gets status “Completed” as well. The event is thrown during a job run. Updating the Payment is fulfilled via WrapperService in lib\payment\payments\DbPaymentRepository.ts.

Now if I am testing this event processing locally then I see that the changes with modification = “update” are inserted into CHANGELOG and CHANGES. Unfortunately I cannot execute the mentioned job (it is running only in MAIN system). But I tested this from a unit test firing the same event and the update changes were created.

When the job is running in MAIN and payments are updated with the new status “Completed” it is however not reflected in CHANGELOG and CHANGES.

Do you have any idea what can be the difference? We supposed that this was due to the job execution. But we have other events which are creating new instances of Payment – and this works; the “create” changes are created.

What in MAIN environment could inhibit creating “update” change logs?

Kind regards,
Elena Gurevich

Save fails on HANA when tracking is enabled for Boolean fields

Hi,

I get the following exception when I enabled change tracking for a Boolean field when using HANA db.

[cds] - Error: Cannot set parameter at row: 1. Argument must be a string
    at next (/home/user/projects/testApp/node_modules/hdb/lib/protocol/ExecuteTask.js:175:19)
    at ExecuteTask.getParameters (/home/user/projects/testApp/node_modules/hdb/lib/protocol/ExecuteTask.js:189:3)
    at ExecuteTask.sendExecute (/home/user/projects/testApp/node_modules/hdb/lib/protocol/ExecuteTask.js:196:8)
    at execute (/home/user/projects/testApp/node_modules/hdb/lib/protocol/ExecuteTask.js:73:10)
    at ExecuteTask.run (/home/user/projects/testApp/node_modules/hdb/lib/protocol/ExecuteTask.js:115:3)
    at run (/home/user/projects/testApp/node_modules/hdb/lib/util/Queue.js:97:12)
    at next (/home/user/projects/testApp/node_modules/hdb/lib/util/Queue.js:86:7)
    at done (/home/user/projects/testApp/node_modules/hdb/lib/protocol/ExecuteTask.js:53:5)
    at finalize (/home/user/projects/testApp/node_modules/hdb/lib/protocol/ExecuteTask.js:58:14)
    at execute (/home/user/projects/testApp/node_modules/hdb/lib/protocol/ExecuteTask.js:71:14) {
  query: 'INSERT INTO sap_changelog_Changes ( serviceEntityPath, entity, serviceEntity, attribute, valueChangedFrom, valueChangedTo, valueDataType, modification, keys, entityID, parentEntityID, parentKey, changeLog_ID, ID ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )',
  values: [
    [
      'my.Books(301)',
      'my.Books',
      'CatalogService.Books',
      'yesOrNo',
      '',
      true,
      'cds.Boolean',
      'update',
      'ID=301',
      '',
      '',
      '',
      '4eff86ee-c60f-4031-a64d-ef45db9f9aac',
      '08d9d030-46cb-433e-ac44-1ad660762bfc'
    ]
  ],
  numericSeverity: 4,
  id: '1989256',
  level: 'ERROR',
  timestamp: 1700054785696
}

Potential solution:
Please refer here. Values of to and from are not ensured to be string. This is fine for sqlite. But Hana is not so forgiving.

Regards,
Dinu

Change logs not captured on composition level

As continuation of #64

On the calesi/incidents-app, with the following code changes:

image

I am able to achieve the following:
image

In other words, the end user is aware that changes are made for the composition "Conversation".

When I try to achieve the same thing within our project:
image

It is not the case. You cannot see any change made on the composition.
If i directly annotate the entity the composition points to, e.g.
image

And run the project as described here https://github.tools.sap/cap/issues/issues/15214

When I navigate to
image

And modify the customerTenantAssignment through the value help:

image

I get a log that tenant_id is logged
image

But this information is scarce and I do not see from which composition the change is coming from.
How can I overcome that?

CDS Compilation fails on mbt build when change-tracking is included

More details of the initial problem are to be found here: cap-issue-15399.

However, I was able to isolate the problem a bit further in the following branch: chore-change-tracking/working-cds-build.

Steps to reproduce:
git clone https://github.tools.sap/customer-data-hub/cockpit.git
git fetch
git checkout chore-change-tracking/working-cds-build
npm i -g typescript ts-node
npm i -g @sap/cds-dk
npm i
npm i --prefix approuter

mbt build

As a result npm run build phase passes successfully when no change-tracking is involved:
image

With slightest change, e.g. including change tracking within package.json and uncommenting the contents of db/ext-changes.cds:
image

image

CDS compilation fails. Complete log is to be found here: failing_logs.txt

Change tracking will capture the wrong objectID in some special cases.

Hello,

When I was debugging change tracking, I found that in the following modeling and annotation, certain special cases resulted in capturing the wrong objectID:
image
image

Because in modeling, Buildings entity has a name field, and the ObjectID annotation also needs to capture the name field of the final entity from goods.goods.goods.name. In fact, the two name fields represent different content.

When we set the value 'test buildings' to the name of the Buildings entity in our app, and Goods is empty, the ObjectID we expect is only: 'test buildings', because all the other values are empty. But in this case, because Buildings have a field called name, and path: 'goods.goods.goods.name' ends up with a field called name, the ObjectID will be: 'test buildings, test buildings'. You can see that we now have the wrong ObjectID.
image
image

And here's the problem:
https://github.com/cap-js/change-tracking/blob/main/lib/entity-helper.js#L99

This is my solution:
image

If you have time, please take a look at this scenario.

Best Regards,
Wenjun

How to handle the visibility of Change History Section?

Hi Team, Can we handle the visibility of the Change History Section based on the user role?
I tried the Show Page Map feature of SAP Fiori Element, but the section is not visible (I guess because the section is created at the runtime). Is there any other way?

Please suggest.

Questions about Object ID definition

Hi colleagues,
There was a discussion whether direct DB operations (not via services) should be also considered in the change tracking. Finally a decision was made that a service was necessary. We created such dummy-services like for example

service PaymentWrapperService @(requires: 'system-user') {
entity Payments as projection on db.payments.Payments;
entity Payables as projection on db.payables.Payables;
entity PaymentOrders as projection on db.paymentOrders.PaymentOrders;
entity Receivables as projection on db.receivables.Receivables;
entity BusinessTransactions as projection on db.businessTransactions.BusinessTransactions;
}

And all INSERT/UPDATE operations are now fulfilled via this service like:

INSERT([paymentToInsert]).into(PaymentWrapperService.Entity.Payments)

This works. Moreover, entity BusinessTransactions is a view defined as union of 3 other entities: Payments, Payables and Receivables. But on the UI based on BusinessTransactions the change history of Payment or other entities is shown – this is if course very good.
However some things do not work as expected.
All three entities Payments, Payables and Receivables in the view BusinessTransactions have a field displayId.
For Payables and Receivables it was possible to define Changelog as
@changelog: [displayId]

However for Payments it is not possible (then npm run build would bring an error saying that dependencies exist). It is only possible to define it as
@changelog.ObjectID: [displayId]

But then EntityID on the Changes DB table remains empty and “Payment” is shown as Object ID . I tried
@changelog.entityID: [displayId]

But it does not make any difference. Even in the DB table SAP_CHANGELOG_CHANGES Entity ID is empty.

I suppose that this is happening because the entity Payments has associations to other entities (Payments and PaymentOrders) having changelogs with the same entityID “displayId”:
Type : Association to one codelists.PaymentTypeCodes;
Direction : Association to one PaymentDirectionCodes;
displayId : String; //readable ID
Company : Association to one Companies;
BusinessPartner : Association to one BusinessPartners;
PaymentOrder : Association to one PaymentOrders;
Wallet : Association to one wallets.Wallets;
Transaction : Association to one wallets.Transactions;
cryptoAmount : Decimal;
CryptoAmountCurrency : Association to one Cryptocurrencies;

@changelog
fiatAmount               : Decimal; //Call reuse service to round due to allowed number of digits wherever necessary
FiatAmountCurrency       : Association to one FiatCurrencies;

@changelog
paymentExecutionDateTime : DateTime; //TimeStamp is not used here because we do not need 0,1 microsecond precision (sec precision is enough)

@title    : '{i18n>Status}'
@changelog: [LifecycleStatus.code]
LifecycleStatus          : Association to one codelists.PaymentLifecycleStatusCodes;

Fee                      : Association to one Payments;

Am I right? Does not it work when one entity is associated with another one with the same changelog Entity ID? How should we define ObjectID in this case?

One more question: if we are showing an amount in the change log, how can we add currency to it? Is it possible? I mean not just showing “5.5” but “5.5 USD”.

I am attaching an example from UI.

ChangeLog

Thank you and kind regards,
Elena Gurevitch

How to hide change history?

Hi colleagues,

we have two object pages in the same UI service annotation (app\payment\businessTransactions\annotations.cds) : one is used to show an existng business transaction. another to create or edit a draft business transaction. These are even different apps but they are built on the same UI service.

Non-draft

Draft

We would like to show Change History only for the non-draft view.

I saw that we could use

annotate sap.changelog.aspect @(UI.Facets: [{
$Type : 'UI.ReferenceFacet',
ID : 'ChangeHistoryFacet',
Label : '{i18n>ChangeHistory}',
Target: 'changes/@UI.PresentationVariant',
![@UI.PartOfPreview],
}]);

to make the change history to be shown at once.

Can we somehow use it to define visibility? I saw that UI.Hidden could be also defined here. But how can I provide the condition whether we are dealing with a draft? "IsActiveEntity" path is not valid .

I even tried to describe 'ChangeHistoryFacet' together with appplication facets - there "IsActiveEntity" path is known - but it did not have any affect.

Is there any possibility?

Kind regards,
Elena

Is it possible to change formatting of the changed fields?

Hello colleagues,

We defined changelog for decimal fields, for example

@changelog
cryptoAmount : Decimal;

If the values are very small they are shown like

Cryptocurrency Amount 4e-1

Is it possible to provide some formatting to be used (are there any exits to format the values) ? For example here we would prefer 0.4 because it is more user-friendly.

But I guess it is not possible.

And to combine an amount and a currency is also not possible, am I right?

I think the only way would be to have an additional string field where amount is formatted as desired but this is not good.

Kind regards,
Elena Gurevitch

How to disable Change History for some UI service annotation

Hi colleagues,

This question is similar to my previous ticket #75 but nevertheless another one.

If Change History is declared for some entity then the tab "Change History" seems to appear on any object page which is dealing with this entity - for different UI services and apps.

This is very generic and of course comfortable (the application itself must not define anything - no any association to changes, no any facet etc.). But nevertheless sometimes it is not desired to show the change history on a certain screen or in a certain view.

Is there any possibility to disable Change History within one UI service annotation? If I set the aspect for ChangeHistoryFacet and set it to "hidden" then Change History disappears for all apps, not only for mine and not only for those dealing with the same entity.

Change History is somehow too generic and too global. It would be great to have a possibility to handle it for different apps and views individually.

Kind regards,
Elena

Changing history view for two apps

Hi colleagues,

You described, how we can customize the change view (annotating

annotate sap.changelog.ChangeView with @(
UI.LineItem : [....

explicitely in the app annotation.

You described as well how we can set change history to be shown at once:

annotate sap.changelog.aspect @(UI.Facets: [{
$Type : 'UI.ReferenceFacet',
ID : 'ChangeHistoryFacet',
Label : '{i18n>ChangeHistory}',
Target: 'changes/@UI.PresentationVariant',
![@UI.PartOfPreview]
}]);

I tried it out in one of the apps and it worked correctly. I was able to hide some technical columns, to change some column labels.

However when I tried to do the same in the second app annotation I got the following error during npm run build:dev

[ERROR] app\masterData\businessPartners\annotations.cds:6:3-14: Duplicate assignment with “@UI.LineItem” (in annotate:“sap.changelog.ChangeView”)
[ERROR] app\masterData\businessPartners\annotations.cds:68:33-42: Duplicate assignment with “@UI.Facets” (in annotate:“sap.changelog.aspect”)
[ERROR] app\payment\businessTransactions\annotations.cds:5:42-53: Duplicate assignment with “@UI.LineItem” (in annotate:“sap.changelog.ChangeView”)
[ERROR] app\payment\businessTransactions\annotations.cds:64:33-42: Duplicate assignment with “@UI.Facets” (in annotate:“sap.changelog.aspect”)

CDS compilation failed
Command failed: npx cds deploy --to hana:D032660 --store-credentials --auto-undeploy

Could you please advise?

Kind regards,
Elena Gurevitch

Change tracking not working in Multi-tenant CAP Nodejs Project

I am trying to add the plugin @cap-js/change-tracking to store change logs for an Entity in my CAP Nodejs multi tenant Project.

I have followed the guide to implement this Change Tracking Plugin for SAP Cloud Application Programming Model (CAP).

I have added the @changelog annotations to an entity for which I am trying to track changes. This brings the facet in the fiori elements object page. And when I trying to edit a record and save it from the app I am getting below error:

no such table: sap_changelog_ChangeLog in: INSERT INTO sap_changelog_ChangeLog

Below is how I have added the annotation to my service entity in file app/managebooks/annotations.cds :

annotate service.Books with {
title @changelog;
};

It needs the table sap_changelog_ChangeLog to persist the change log entries but just by adding the module in package.json and adding annotation to properties is not generating the table while doing local testing with sqlite. Please let me know if there are some steps missed here.

Thanks & Regards,
Vishal Sharma

Change tracking not showing

Hi Team,
We have managebusinesspartners/webapp/index.html application which when edited, the change tracking disappears and we can see no data in the change history , on commenting out the specified annotation for to show the 'show more' in change history.
The annotation in the change tracking file:

annotate sap.changelog.aspect @(UI.Facets: [{ $Type : 'UI.ReferenceFacet', ID : 'ChangeHistoryFacet', Label : '{i18n>ChangeHistory}', Target: 'changes/@UI.PresentationVariant', ![@UI.PartOfPreview], }]);
Could you please look into the above.

Regards,
Nandini

Error Message with CDS 7 / lean_draft:false and change-tracking Plugin

Dear team,

We have installed the plugin (https://github.com/cap-js/change-tracking) in our project and are using the latest version of CDS 7. Although we are using the current CDS 7 version, we are still using the old draft mode for our entities. This is currently supported by the attribute ("lean_draft": false).

The combination of CDS 7 / lean_draft:false and the plugin leads to problems. The error is located in the CDS 7 standard code, as shown in the screenshot attached to this note. The error message and the content of the object are also detailed in the screenshot.

Issue:
Error message when using CDS 7 / lean_draft:false with the change-tracking plugin

Cause:
Incompatibility between the plugin and CDS 7 standard code when using lean_draft:false

Steps to Reproduce:
Install the change-tracking plugin (https://github.com/cap-js/change-tracking)
Set "lean_draft": false in your CDS entity definitions
Create or update an entity
Observe the error message in the console
Expected Behavior:
The plugin should work seamlessly with CDS 7 / lean_draft:false
Actual Behavior:
An error message is displayed in the console

Screenshot:
Attached screenshot showing the error message and the content of the object
code

Additional Information:
Link to the GitHub repository of the change-tracking plugin (https://github.com/cap-js/change-tracking)

Request:
Please provide a solution for this issue.
Thank you for your time and support.

Sincerely

A field of type "Date" cannot be used for change tracking

Hi colleagues,

If we are declaring a field in a CDS entity to be saved in the Changelog and this field has Data type:

@changelog
dueDate : Date;

then it causes an error during saving the changes. What happens:

**const _formatCompositionContext = async function (changes, reqData) {
const childNodeChanges = []

for (const change of changes) {
if (typeof change.valueChangedTo === "object") {**

In node_modules@cap-js\change-tracking\lib\change-log.js type of this field is considered to be an object (valueChangedTo is shown as “Thu Jan 01 1970 01:00:00 GMT+0100 (Central European Standard Time)”; valueDataType is "cds.Date") and is coverted to an Array:

if (!Array.isArray(change.valueChangedTo)) {
change.valueChangedTo = [change.valueChangedTo]
}

Then an attempt is done:
for (const childNodeChange of change.valueChangedTo) {
const curChange = Object.assign({}, change)
const path = childNodeChange._path.split('/')

However childNodeChange is a string, not a real object, and does not have any path. So it dumps.

Could you please check why cds,Date is considered to be an object? May be it is concerning also other types?

Kind regards,
Elena Gurevitch

Issue with numeric key format

Hello,

I have activated change tracking with below version:
"@cap-js/change-tracking": "^1.0.5",

And when activating the change tracking on an entity with numeric key I get following error during save.
The key of entity has integer64 format but the expected format should be a string in sap_changelog_ChangeLog.

[cds] - Error: Cannot set parameter at row: 1. Argument must be a string at next (/home/user/projects/MyWB/node_modules/hdb/lib/protocol/ExecuteTask.js:175:19) at ExecuteTask.getParameters (/home/user/projects/MyWB/node_modules/hdb/lib/protocol/ExecuteTask.js:189:3) at ExecuteTask.sendExecute (/home/user/projects/MyWB/node_modules/hdb/lib/protocol/ExecuteTask.js:196:8) at execute (/home/user/projects/MyWB/node_modules/hdb/lib/protocol/ExecuteTask.js:73:10) at ExecuteTask.run (/home/user/projects/MyWB/node_modules/hdb/lib/protocol/ExecuteTask.js:115:3) at run (/home/user/projects/MyWB/node_modules/hdb/lib/util/Queue.js:96:12) at next (/home/user/projects/MyWB/node_modules/hdb/lib/util/Queue.js:85:7) at receive (/home/user/projects/MyWB/node_modules/hdb/lib/util/Queue.js:114:5) at Connection.receive (/home/user/projects/MyWB/node_modules/hdb/lib/protocol/Connection.js:385:3) at TLSSocket.ondata (/home/user/projects/MyWB/node_modules/hdb/lib/protocol/Connection.js:243:12) { query: 'INSERT INTO sap_changelog_ChangeLog ( entity, entityKey, serviceEntity, createdAt, createdBy, modifiedAt, modifiedBy, ID ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )', values: [ [ 'my.db.Worklist', 110026,

Is there a possible correction or a workaround?

Thank you

Change Tracking not working for Locale aspects

Hello Team,

We are using a string field localized aspect to store descriptions in multiple languages. We have noticed that this scenario is not supported by change-tracking.

Kindly let us know if there is a roadmap to support this.

CDS Definition

@assert.unique: {businessKey: [name]}
entity PreDefinedText : cuid, managed {
  name : String;
  description : localized String;

Change tracking annotation:

annotate PreDefinedText.PreDefinedText with @title: 'PreDefinedText'{
    name        @changelog ;
    texts       @Changelog: [texts.description] @Common.Label: '{i18n>texts}';
}

Fiori App Screenshot:
We are changing the description. However, the values are not tracked.
image

Best Regards,
Rahul

Adding the facet manually

Hello,

We have our app with annotations etc. change-tracking is not added to the view automatically.
Can it be added explicitly?

BR,
Jacek

@cap-js/change-tracking How to remove Change Log table from child entities object page

Hi,

we added this package in our solution and its working fine but we are facing issues that all child entities (Compositions) object page also start showing this change log table but there is no data shown specifically for that child entities and all change logs is being shown in the root level entity (which is fine to show in root entity).

But how to remove this table from the child entities or how to show data only for that child entities?

Changelogs erased for deleted entities

Hello team,

I have noticed that all the changelogs for a parent entity are erased on entity delete:
image

However, we have usecase where we are interested in whole entity lifecycle tracking (including the delete action) and keeping these logs. Is there any way to achieve this?

Thank you,
Hana

App reports Error when change tracking enabled for Entities with a key field not named ID

I generated a sample application using cds add samples.
I renamed the field ID of Books to BookID in db/schema.cds and updated test data too.

entity Books : managed {
  key BookID : Integer;
  @mandatory title  : localized String(111);
  descr  : localized String(1111);
  @mandatory author : Association to Authors;
  genre  : Association to Genres;
  stock  : Integer;
  price  : Decimal;
  currency : Currency;
  image : LargeBinary @Core.MediaType : 'image/png';
}

I enabled change tracking for the entity Books of AdminService with annotations:

annotate AdminService.Books with @changelog : [BookID] {
	title @changelog;
	descr @changelog;	
	price @changelog;
	currency @changelog;	
	stock @changelog;
}

Now when I try to change the title of Book with title "Catweazle" using fiori preview for Books entity, the application reports error.: Error: "ID" not found in the elements of "AdminService.Books"

I see in the console the following error.

odata] - POST /odata/v4/admin/$batch 
[odata] - > PATCH Books(BookID=271,IsActiveEntity=false) 
[odata] - > draftPrepare Books(BookID=271,IsActiveEntity=false)/AdminService.draftPrepare 
[odata] - > draftActivate Books(BookID=271,IsActiveEntity=false)/AdminService.draftActivate {
  '$select': 'BookID,HasActiveEntity,HasDraftEntity,IsActiveEntity,author_AuthorID,createdAt,createdBy,currency_code,descr,genre_code,modifiedAt,modifiedBy,price,stock,title',
  '$expand': 'DraftAdministrativeData($select=DraftIsCreatedByMe,DraftUUID,InProcessByUser),author($select=ID,name),genre($select=ID,name)'
}
[cds] - Error: "ID" not found in the elements of "AdminService.Books"
    at stepNotFoundInCombinedElements (D:\book-shop\node_modules\@cap-js\db-service\lib\infer\index.js:807:15)
    at D:\book-shop\node_modules\@cap-js\db-service\lib\infer\index.js:543:13
    at Array.forEach (<anonymous>)
    at inferQueryElement (D:\book-shop\node_modules\@cap-js\db-service\lib\infer\index.js:489:18)
    at processToken (D:\book-shop\node_modules\@cap-js\db-service\lib\infer\index.js:371:11)
    at Array.forEach (<anonymous>)
    at walkTokenStream (D:\book-shop\node_modules\@cap-js\db-service\lib\infer\index.js:375:19)
    at inferQueryElements (D:\book-shop\node_modules\@cap-js\db-service\lib\infer\index.js:344:16)
    at infer (D:\book-shop\node_modules\@cap-js\db-service\lib\infer\index.js:69:22)
    at cqn4sql (D:\book-shop\node_modules\@cap-js\db-service\lib\cqn4sql.js:47:20) {
  id: '1344032',
  level: 'ERROR',
  timestamp: 1701262020937
}

There were no issues before I renamed the field.

Change Log for a CDS view

Hello colleagues!

We are working on this project.

We want to show change log for an entity which is not persisted as a table but is a view representing a union of several selects from DB tables.

This view is declared in db\payment\businessTransactions\BusinessTransactions.cds.

UI Service view is defined in srv\payment\businessTransactions\ui-service-businesstransactions.cds.

I tried to define change log in BusinessTransactions.cds as following declaring the corresponding field in each select for the change log (However it does not work):

**@changelog.objectID: [
    displayId,
    Type.code
]**
entity BusinessTransactions          as(
    select from payment.payments.Payments {
        key ID,
            Usage,
            createdAt,
            createdBy,
            modifiedAt,
            modifiedBy,
            Type.code            as Type_code,
            Direction.code       as Direction_code,
            displayId,
            Company,
            BusinessPartner,
            PaymentOrder,
            Wallet,
            Transaction,
            cryptoAmount,
            CryptoAmountCurrency,
            fiatAmount,
            FiatAmountCurrency,
            paymentExecutionDateTime,
            **@changelog**
            LifecycleStatus.code as LifecycleStatus_code,
            case
                when
                    LifecycleStatus.code    = 'IN_PROCESS'
                    or LifecycleStatus.code = 'ERRONEOUS'
                then
                    'OPEN'
                when
                    LifecycleStatus.code    = 'COMPLETED'
                    or LifecycleStatus.code = 'COMPLETED_N_MATCHED'
                    or LifecycleStatus.code = 'CANCELED'
                then
                    'COMPLETED'
                else
                    null
            end                  as completeness           : String,

            case
                when
                    (
                        Transaction.ID    =  ''
                        or Transaction.ID is null
                    )
                then
                    PaymentOrder.ID
                else
                    Transaction.ID
            end                  as transactionReferenceId : String,
            Fee,
            null                 as externalId             : String,
            null                 as documentDate           : Date,
            null                 as dueDate                : Date,
            Type                                           : Association to one codelists.BusinessTransactionTypeCodes on Type.code = Type_code,
            LifecycleStatus                                : Association to one codelists.BusinessTransactionLifecycleStatusCodes on LifecycleStatus.code = LifecycleStatus_code,
            Network,
            Account,
            Account.name         as AccountName,
            ExchangeRate,
            PaymentAgreementOutgoing,
            PaymentAgreementIncoming,

    }
)
union all
(
    select from payment.payables.Payables {
        key ID,
            Usage,
            createdAt,
            createdBy,
            modifiedAt,
            modifiedBy,
            'FOREC_OUTG_PAYMENT' as Type_code,
            'OUTGOING'           as Direction_code,
            displayId,
            Company,
            BusinessPartner,
            null                 as PaymentOrder,
            null                 as Wallet,
            null                 as Transaction,
            cryptoAmount,
            CryptoAmountCurrency,
            fiatAmount,
            FiatAmountCurrency,
            null                 as paymentExecutionDateTime,
            **@changelog**
            case
                when
                    LifecycleStatus.code    = 'OPEN'
                    or LifecycleStatus.code = 'SCHEDULED'
                then
                    'OPEN'
                else
                    LifecycleStatus.code
            end                  as LifecycleStatus_code,
            case
                when
                    LifecycleStatus.code    = 'OPEN'
                    or LifecycleStatus.code = 'SCHEDULED'
                    or LifecycleStatus.code = 'PARTIALLY_PAID'
                then
                    'OPEN'
                else
                    null
            end                  as completeness           : String,
            null                 as transactionReferenceId,
            null                 as Fee,
            externalId,
            documentDate,
            dueDate,
            Type                                           : Association to one codelists.BusinessTransactionTypeCodes on Type.code = Type_code,
            LifecycleStatus                                : Association to one codelists.BusinessTransactionLifecycleStatusCodes on LifecycleStatus.code = LifecycleStatus_code,
            Network,
            Account,
            Account.name         as AccountName,
            ExchangeRate,
            PaymentAgreementOutgoing,
            null                 as PaymentAgreementIncoming,
    }
)
union all
(
    select from payment.receivables.Receivables {
        key ID,
            Usage,
            createdAt,
            createdBy,
            modifiedAt,
            modifiedBy,
            'FOREC_INC_PAYMENT'  as Type_code,
            'INCOMING'           as Direction_code,
            displayId,
            Company,
            BusinessPartner,
            null                 as PaymentOrder,
            null                 as Wallet,
            null                 as Transaction,
            cryptoAmount,
            CryptoAmountCurrency,
            fiatAmount,
            FiatAmountCurrency,
            null                 as paymentExecutionDateTime,
            **@changelog**
            LifecycleStatus.code as LifecycleStatus_code,
            case
                when
                    LifecycleStatus.code    = 'OPEN'
                    or LifecycleStatus.code = 'PARTIALLY_PAID'
                then
                    'OPEN'
                else
                    null
            end                  as completeness           : String,
            null                 as transactionReferenceId,
            null                 as Fee,
            externalId,
            documentDate,
            dueDate,
            Type                                           : Association to one codelists.BusinessTransactionTypeCodes on Type.code = Type_code,
            LifecycleStatus                                : Association to one codelists.BusinessTransactionLifecycleStatusCodes on LifecycleStatus.code = LifecycleStatus_code,
            Network,
            Account,
            Account.name         as AccountName,
            ExchangeRate,
            null                 as PaymentAgreementOutgoing,
            PaymentAgreementIncoming,
    }
);

I tried to define change log for every selected entity as well but this does not work as well.

Could you please advise how we can track change history for such an entity?

I am working in this branch.

Thank you and kind regards,
Elena

Change history/tracking does not work on multiple records

Hi Team,

I am trying to post the data via CQL after enabling change tracking for the service and connecting to it.
const srv = await cds.connect.to("MasterDataMapService");
const masterEntity = srv.entities[entity];
const insertResult = await INSERT.into(masterEntity).entries(aInsertData);

Above Insert Query shows the change tracking only if I insert one record into it, otherwise it does not show any change tracking.
Can you please check on this?

Change tracking annotation file source code:
using { MasterDataMapService } from './masterdatamap-service';
using from '@cap-js/change-tracking';

annotate MasterDataMapService.TaxCodeMap with @title: 'Tax Code' @changelog: [author, timestamp]{
companyCode @changelog;
sourceTaxCode @changelog;
targetTaxCode @changelog;

}
annotate sap.changelog.aspect @(UI.Facets: [{
$Type : 'UI.ReferenceFacet',
ID : 'ChangeHistoryFacet',
Label : '{i18n>ChangeHistory}',
Target: 'changes/@UI.PresentationVariant',
![@UI.PartOfPreview]
}]);

annotate sap.changelog.ChangeView with @(
UI.LineItem : [
{ Value: modification, @HTML5.CssDefaults: { width: 'auto' }},
{ Value: createdAt, @HTML5.CssDefaults: { width: 'auto' }},
{ Value: createdBy, @HTML5.CssDefaults: { width:'auto' }},
{ Value : attribute, @HTML5.CssDefaults: { width:'auto' }},
{ Value : valueChangedFrom, @HTML5.CssDefaults: { width:'auto' }},
{ Value : valueChangedTo, @HTML5.CssDefaults: { width:'auto' }},

]
);

Regards,
Vishal Kwatra

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.