Skip to content

Commit

Permalink
Merge branch 'refs/heads/main' into feature/962-notification-model-up…
Browse files Browse the repository at this point in the history
…date
  • Loading branch information
ds-mwesener committed Jun 24, 2024
2 parents 249f3a9 + a02f407 commit 13d5612
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ _**For better traceability add the corresponding GitHub issue number in each cha
- #962 Changed notification model to new one in frontend/backend
- #962 Removed initial notification message for notification flow
- #753 Refactored message history in notification detail view
- XXX updated local deployment documentation

### Added
- #832 added policymanagement list view, creator and editor
Expand Down
2 changes: 1 addition & 1 deletion docs/src/docs/user/user-manual.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Possibility to check the network status based on logfiles and will provide acces

==== BPN-EDC configuration

In the BPN-EDC configuration screen an admin user can add new URLs for BPNs. After adding URLs here, notifications will be sent to the corresponding URL. Existing configurations can be edited or removed.
In the BPN-EDC configuration screen an admin user can add URLs for BPNs. Any URLs here will be used directly for the configured BPN instead of looking up the URL with the EDC DiscoveryFinder service. Existing configurations can be edited or removed.

image::https://raw.githubusercontent.com/eclipse-tractusx/traceability-foss/main/docs/src/images/user-manual/navigation/bpn_edc_configuration.png[]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
</mat-card-header>
<mat-card-content>
<div class="policy--header--container flex justify-between mt-3">
<div class="policy--header--container--selector flex">
<div class="policy--header--container--selector flex mb-4">
<app-view-selector
(click)="defaultViewIsActivated = true;"
onkeydown="defaultViewIsActivated = true;"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
matTooltipPosition="above"
[class.mdc-tooltip--multiline]="true"
[matTooltipShowDelay]="500"
(mouseenter)="validateAllFields()"
*ngIf="viewMode === ViewMode.EDIT || viewMode === ViewMode.CREATE"
>
<app-button
Expand Down Expand Up @@ -174,14 +175,14 @@ <h4 class="pb-2">{{ 'pageAdmin.policyManagement.constraints' | i18n }} {{ '(' +
</div>
<div class="constraints--header--label flex-1">
{{ "pageAdmin.policyManagement.operator" | i18n }}
</div>
<div class="constraints--header--label flex-1">
{{ "pageAdmin.policyManagement.rightOperand" | i18n }}
<div class="constraints--header--sub-label">
{{ "pageAdmin.policyManagement.rightOperandHint" | i18n }}

</div>
</div>
<div class="constraints--header--label flex-1">
{{ "pageAdmin.policyManagement.rightOperand" | i18n }}
</div>
</div>
<div *ngFor="let constraint of constraints.controls; let i=index;" [formGroupName]="i"
class="flex w-full gap-2">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { APP_INITIALIZER } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, convertToParamMap, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { PoliciesFacade } from '@page/admin/presentation/policy-management/policies/policies.facade';
Expand Down Expand Up @@ -253,4 +253,76 @@ describe('PolicyEditorComponent', () => {

});

it('should mark all form controls and form array elements as touched', async () => {
const { fixture } = await renderPolicyEditorComponent();
const { componentInstance } = fixture;
componentInstance.policyForm = componentInstance.fb.group({
policyName: [ '', Validators.required ],
constraints: componentInstance.fb.array([
componentInstance.fb.group({
leftOperand: [ '', Validators.required ],
operator: [ '', Validators.required ],
rightOperand: [ '', Validators.required ],
}),
]),
});

spyOn(componentInstance.policyForm.get('policyName'), 'markAsTouched');
spyOn(componentInstance.constraints.at(0).get('leftOperand'), 'markAsTouched');

componentInstance.validateAllFields();

expect(componentInstance.policyForm.get('policyName').markAsTouched).toHaveBeenCalled();
expect(componentInstance.constraints.at(0).get('leftOperand').markAsTouched).toHaveBeenCalled();
});

it('should mark all elements in a FormArray as touched', async () => {
const { fixture } = await renderPolicyEditorComponent();
const { componentInstance } = fixture;
componentInstance.policyForm = componentInstance.fb.group({
constraints: componentInstance.fb.array([
componentInstance.fb.group({
leftOperand: [ '', Validators.required ],
operator: [ '', Validators.required ],
rightOperand: [ '', Validators.required ],
}),
componentInstance.fb.control(''),
]),
});

const formArray = componentInstance.policyForm.get('constraints') as FormArray;
spyOn(formArray.at(0).get('leftOperand'), 'markAsTouched');
spyOn(formArray.at(1), 'markAsTouched');

componentInstance.validateFormArray(formArray);

expect(formArray.at(0).get('leftOperand').markAsTouched).toHaveBeenCalled();
expect(formArray.at(1).markAsTouched).toHaveBeenCalled();
});

it('should mark all fields in a FormGroup within a FormArray as touched', async () => {
const { fixture } = await renderPolicyEditorComponent();
const { componentInstance } = fixture;
componentInstance.policyForm = componentInstance.fb.group({
constraints: componentInstance.fb.array([
componentInstance.fb.group({
leftOperand: [ '', Validators.required ],
operator: [ '', Validators.required ],
rightOperand: [ '', Validators.required ],
}),
]),
});

const formGroup = componentInstance.constraints.at(0) as FormGroup;
spyOn(formGroup.get('leftOperand'), 'markAsTouched');
spyOn(formGroup.get('operator'), 'markAsTouched');
spyOn(formGroup.get('rightOperand'), 'markAsTouched');

componentInstance.validateAllFieldsInFormGroup(formGroup);

expect(formGroup.get('leftOperand').markAsTouched).toHaveBeenCalled();
expect(formGroup.get('operator').markAsTouched).toHaveBeenCalled();
expect(formGroup.get('rightOperand').markAsTouched).toHaveBeenCalled();
});

});
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class PolicyEditorComponent {


this.policyForm = this.fb.group({
policyName: new FormControl('', [ Validators.required, Validators.minLength(8), Validators.maxLength(40), this.noSpacesValidator() ]),
policyName: new FormControl('', [ Validators.required, Validators.maxLength(40), this.noSpacesValidator() ]),
validUntil: new FormControl('', [ Validators.required, this.futureDateValidator ]),
bpns: new FormControl('', [ Validators.required, this.viewMode === ViewMode.CREATE ? BaseInputHelper.getCustomPatternValidator(bpnRegex, 'bpn') : BaseInputHelper.getCustomPatternValidator(bpnListRegex, 'bpn') ]),
accessType: new FormControl<string>(PolicyAction.ACCESS),
Expand Down Expand Up @@ -333,9 +333,38 @@ export class PolicyEditorComponent {
};
}

validateAllFields() {
Object.keys(this.policyForm.controls).forEach(field => {
const control = this.policyForm.get(field);
if (control instanceof FormArray) {
this.validateFormArray(control);
} else {
control.markAsTouched({ onlySelf: true });
}
});
}

validateFormArray(formArray: FormArray) {
formArray.controls.forEach(control => {
control.markAsTouched();
if (control instanceof FormGroup) {
this.validateAllFieldsInFormGroup(control);
}
});
}

validateAllFieldsInFormGroup(formGroup: FormGroup) {
Object.keys(formGroup.controls).forEach(field => {
const control = formGroup.get(field);
control.markAsTouched({ onlySelf: true });
});
}


protected readonly ViewMode = ViewMode;
protected readonly OperatorTypesAsSelectOptionsList = OperatorTypesAsSelectOptionsList;
protected readonly ConstraintLogicTypeAsSelectOptionsList = ConstraintLogicTypeAsSelectOptionsList;


}

Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,17 @@ export class NotificationReasonComponent {
const sortedMessagesAfterDates = messages.sort((a, b) => new Date(a.messageDate).valueOf() - new Date(b.messageDate).valueOf());

sortedMessagesAfterDates.forEach(message => {
this.textMessages.push({
message: message.message,
direction: environment.bpn === message.sentBy ? 'right' : 'left',
user: message.sentByName,
bpn: message.sentBy,
status: message.status,
date: message.messageDate,
errorMessage: message.errorMessage,
});
if (message?.message?.length > 0) {
this.textMessages.push({
message: message.message,
direction: environment.bpn === message.sentBy ? 'right' : 'left',
user: message.sentByName,
bpn: message.sentBy,
status: message.status,
date: message.messageDate,
errorMessage: message.errorMessage,
});
}
});

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
<ng-container [ngTemplateOutlet]="{flat}[this.variant]"></ng-container>
<ng-template #flat>
<button [ngClass]="{'selected': isSelected}" [disabled]="isDisabled" [color]="color" mat-flat-button>
<div class="flex items-center">
<ng-container [ngTemplateOutlet]="buttonContent"></ng-container>
</div>
</button>
</ng-template>

Expand All @@ -32,5 +34,6 @@

<ng-template #content>
<ng-content></ng-content>
<mat-icon *ngIf="isSelected">check</mat-icon>
</ng-template>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe('AppViewSelector', () => {
imports: [ SharedModule, TemplateModule ],
});

expect(screen.getByText('Test').parentNode).toHaveClass('mat-accent');
expect(screen.getByText('Test').parentNode.parentNode).toHaveClass('mat-accent');
});

it('should render warn button', async () => {
Expand All @@ -58,7 +58,7 @@ describe('AppViewSelector', () => {
imports: [ SharedModule, TemplateModule ],
});

expect(screen.getByText('Test').parentNode).toHaveClass('mat-warn');
expect(screen.getByText('Test').parentNode.parentNode).toHaveClass('mat-warn');
});

it('should render enabled button', async () => {
Expand All @@ -79,7 +79,7 @@ describe('AppViewSelector', () => {
imports: [ SharedModule, TemplateModule ],
});

const buttonEl = screen.getByText('Test').parentNode;
const buttonEl = screen.getByText('Test').parentNode.parentNode;
expect(buttonEl).toBeDisabled();
});
});
2 changes: 1 addition & 1 deletion frontend/src/assets/locales/de/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@
"maxLength": "Bitte geben Sie maximal {{maxLength}} Zeichen ein. Momentan: {{current}}",
"pattern": "Bitte geben Sie die Daten in folgendem Format ein: {{- pattern}}.",
"url": "Bitte geben Sie eine valide URL ein.",
"bpn" : "Bitte geben Sie eine valide BPN ein.",
"bpn" : "Bitte geben Sie eine valide BPN ein (Beispiel: BPNL00000001ABC2).",
"maxDate": "Bitte wählen Sie ein Datum vor dem {{- maxDate}}.",
"minDate": "Bitte wählen Sie ein Datum nach dem {{- minDate}}.",
"currentDate": "Bitte wählen Sie ein Datum nach dem {{- currentDate}}.",
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/assets/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,14 @@
"maxLength": "Please enter a text that is smaller than: {{maxLength}}. Current: {{current}}",
"pattern": "Please enter data that matches this pattern: {{- pattern}}.",
"url": "Please enter a valid URL.",
"bpn": "Please enter a valid BPN.",
"bpn" : "Please enter a valid BPN (example: BPNL00000001ABC2).",
"maxDate": "Please select a date that is before {{- maxDate}}.",
"minDate": "Please select a date that is after {{- minDate}}.",
"currentDate": "Please select a date that is after {{- currentDate}}.",
"generic": "Please enter valid data.",
"invalidBpn" : "Must not be own BPN.",
"pastDate" : "Please select a date in the future.",
"minimumOneConstraint" : "Please add atleast one valid constraint to the policy"
"minimumOneConstraint" : "Please add at least one valid constraint to the policy"
},
"unitTest": {
"test01": "This is for unit tests purposes.",
Expand Down
21 changes: 4 additions & 17 deletions tx-backend/INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,12 @@
## Clone the source locally:

```sh
$ git clone git@github.com:catenax-ng/tx-traceability-foss.git
$ cd tx-traceability-foss/backend
$ git clone https://github.com/eclipse-tractusx/traceability-foss.git
$ cd traceability-foss
```
Please note: Local deployment of the app is not supported.

## Local deployment
* Start the necessary infrastructure by running: ```docker-compose up``` inside [docker folder](https://github.com/eclipse-tractusx/traceability-foss/blob/main/backend//docker)
* Export environment variables required by the service:
* `SPRING_DATASOURCE_URL` - with value `jdbc:postgresql://localhost:5432/trace`
* `SPRING_DATASOURCE_USERNAME` - with value `trace` [see database initialization script](https://github.com/eclipse-tractusx/traceability-foss/blob/main/backend/docker/db-init/create_db.sql)
* `SPRING_DATASOURCE_PASSWORD` - with value `docker` [see docker-compose file](https://github.com/eclipse-tractusx/traceability-foss/blob/main/backend/docker/docker-compose.yml)
* `OAUTH2_CLIENT_ID` - with OAuth2 provider client registration id specific value
* `OAUTH2_CLIENT_SECRET` - with OAuth2 provider client registration secret specific value
* `OAUTH2_PROVIDER_TOKEN_URI` - with OAuth2 provider url to obtain tokens
* `OAUTH2_JWK_SET_URI` - with OAuth2 provider certs url
* `JWT_RESOURCE_CLIENT` - with JWT resource client name
* `SPRING_PROFILES_ACTIVE` - with profile to be picked when starting the service. One of `[dev|int]`.
* `EDC_PROVIDER_URL` - with url for the EDC provider
* `TRACEABILITY_URL` - with url for the backend
* Start the service by invoking following command in project root directory `./gradlew bootRun`
For deployment please find our helm chart github actions here: https://github.com/eclipse-tractusx/traceability-foss/actions/workflows/helm-upgrade.yaml and https://github.com/eclipse-tractusx/traceability-foss/actions/workflows/helm-test-backwards-compatability.yaml. Within this actions the full application is configured to start up.

## OAuth2 configuration
Product Traceability FOSS Backend relies on properly configured OAuth2 instance. In order to work, it must be configured with proper realm, clients and roles.
Expand Down

0 comments on commit 13d5612

Please sign in to comment.