diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f5030135..86b76053e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,9 @@ the detailed section referring to by linking pull requests or issues. #### Minor +- Both providers and consumers can now terminate contracts. +- Contracts can be filtered by their termination status. + #### Patch ### Deployment Migration Notes diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 330b2953a..4582103ee 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,5 +1,5 @@ import {NgModule} from '@angular/core'; -import {RouterModule, ROUTES, Routes} from '@angular/router'; +import {ROUTES, RouterModule, Routes} from '@angular/router'; import {PageNotFoundComponent} from './component-library/error-404-component/page-not-found.component'; import {APP_CONFIG, AppConfig} from './core/config/app-config'; diff --git a/src/app/component-library/catalog/asset-detail-dialog/asset-detail-dialog-data.service.ts b/src/app/component-library/catalog/asset-detail-dialog/asset-detail-dialog-data.service.ts index d440a700b..299c13cda 100644 --- a/src/app/component-library/catalog/asset-detail-dialog/asset-detail-dialog-data.service.ts +++ b/src/app/component-library/catalog/asset-detail-dialog/asset-detail-dialog-data.service.ts @@ -60,6 +60,7 @@ export class AssetDetailDialogDataService { contractAgreementDetails( contractAgreement: ContractAgreementCardMapped, + refreshCallback: () => void, ): AssetDetailDialogData { const asset = contractAgreement.asset; @@ -85,6 +86,7 @@ export class AssetDetailDialogDataService { asset: contractAgreement.asset, contractAgreement, propertyGridGroups, + refreshCallback, }; } } diff --git a/src/app/component-library/catalog/asset-detail-dialog/asset-detail-dialog-data.ts b/src/app/component-library/catalog/asset-detail-dialog/asset-detail-dialog-data.ts index 4753a2e8c..b219cf004 100644 --- a/src/app/component-library/catalog/asset-detail-dialog/asset-detail-dialog-data.ts +++ b/src/app/component-library/catalog/asset-detail-dialog/asset-detail-dialog-data.ts @@ -4,10 +4,7 @@ import {ContractAgreementCardMapped} from '../../../routes/connector-ui/contract import {PropertyGridGroup} from '../../property-grid/property-grid-group/property-grid-group'; export interface AssetDetailDialogData { - type: - | 'asset-details' - | 'data-offer' - | 'contract-agreement' + type: 'asset-details' | 'data-offer' | 'contract-agreement'; propertyGridGroups: PropertyGridGroup[]; asset: UiAssetMapped; dataOffer?: DataOffer; @@ -15,6 +12,7 @@ export interface AssetDetailDialogData { showDeleteButton?: boolean; showEditButton?: boolean; onAssetEditClick?: OnAssetEditClickFn; + refreshCallback?: () => void; } export type OnAssetEditClickFn = ( diff --git a/src/app/component-library/catalog/asset-detail-dialog/asset-detail-dialog.component.html b/src/app/component-library/catalog/asset-detail-dialog/asset-detail-dialog.component.html index 680348c62..ec61141e1 100644 --- a/src/app/component-library/catalog/asset-detail-dialog/asset-detail-dialog.component.html +++ b/src/app/component-library/catalog/asset-detail-dialog/asset-detail-dialog.component.html @@ -7,11 +7,16 @@ + class="mat-card-avatar-icon" + [class.text-warn]="data.contractAgreement?.terminationStatus === 'TERMINATED'"> {{ data.contractAgreement!!.direction === 'PROVIDING' - ? 'upload' - : 'download' + ? data.contractAgreement!!.isTerminated + ? 'file_upload_off' + : 'file_upload' + : data.contractAgreement!!.isTerminated + ? 'file_download_off' + : 'file_download' }} + +
+
+
+ +
+
+
+ {{ data.contractAgreement!!.terminationInformation!!.reason }} +
+
+ {{ data.contractAgreement!!.terminationInformation!!.detail }} +
+
+ + · terminated by + {{ + data.contractAgreement!!.terminationInformation?.terminatedBy === + 'SELF' + ? 'you' + : 'the counter-party' + }} +
+
+
+
+ -
+
+
+ +
+
- @@ -139,10 +199,12 @@ + + + + diff --git a/src/app/routes/connector-ui/contract-agreement-page/contract-agreement-termination-dialog/contract-agreement-termination-dialog.component.ts b/src/app/routes/connector-ui/contract-agreement-page/contract-agreement-termination-dialog/contract-agreement-termination-dialog.component.ts new file mode 100644 index 000000000..84a32dc84 --- /dev/null +++ b/src/app/routes/connector-ui/contract-agreement-page/contract-agreement-termination-dialog/contract-agreement-termination-dialog.component.ts @@ -0,0 +1,88 @@ +import {Component, Inject, OnDestroy} from '@angular/core'; +import {MatCheckboxChange} from '@angular/material/checkbox'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {Observable, Subject} from 'rxjs'; +import {finalize} from 'rxjs/operators'; +import {IdResponseDto} from '@sovity.de/edc-client'; +import {EdcApiService} from '../../../../core/services/api/edc-api.service'; +import {NotificationService} from '../../../../core/services/notification.service'; +import {ContractAgreementTerminationDialogData} from './contract-agreement-termination-dialog-data'; +import {ContractAgreementTerminationDialogForm} from './contract-agreement-termination-dialog-form'; +import {ContractAgreementTerminationDialogResult} from './contract-agreement-termination-dialog-result'; + +@Component({ + selector: 'contract-agreement-transfer-dialog', + templateUrl: './contract-agreement-termination-dialog.component.html', + providers: [ContractAgreementTerminationDialogForm], +}) +export class ContractAgreementTerminationDialogComponent implements OnDestroy { + loading = false; + checkboxChecked = false; + + constructor( + public form: ContractAgreementTerminationDialogForm, + private dialogRef: MatDialogRef, + private edcApiService: EdcApiService, + private notificationService: NotificationService, + @Inject(MAT_DIALOG_DATA) + public data: ContractAgreementTerminationDialogData, + ) {} + + public onCheckboxChange($event: MatCheckboxChange) { + this.checkboxChecked = $event.checked; + } + + onSave() { + if (this.loading && !this.form.all.valid) { + return; + } + + this.initiateTermination(); + } + + private initiateTermination() { + this.loading = true; + this.form.all.disable(); + + const value = this.form.value; + let request$: Observable; + request$ = this.edcApiService.terminateContractAgreement({ + contractAgreementId: this.data.contractId, + contractTerminationRequest: { + reason: value.shortReason!, + detail: value.detailedReason!, + }, + }); + + request$ + .pipe( + finalize(() => { + this.loading = false; + this.form.all.enable(); + }), + ) + .subscribe({ + next: (response) => { + this.close({ + contractId: response.id, + lastUpdatedTime: response.lastUpdatedDate, + }); + }, + error: (error) => { + this.notificationService.showError('Contract termination failed!'); + console.error('Contract termination failed', error); + }, + }); + } + + private close(params: ContractAgreementTerminationDialogResult) { + this.dialogRef.close(params); + } + + ngOnDestroy$ = new Subject(); + + ngOnDestroy(): void { + this.ngOnDestroy$.next(null); + this.ngOnDestroy$.complete(); + } +}