Skip to content

Commit

Permalink
feat: support multiple contract offers per data offer (#496)
Browse files Browse the repository at this point in the history
  • Loading branch information
richardtreier authored Sep 27, 2023
1 parent 9d8ba39 commit dfa651c
Show file tree
Hide file tree
Showing 19 changed files with 333 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,14 @@ export class AssetDetailDialogDataService {

dataOfferDetails(dataOffer: DataOffer): AssetDetailDialogData {
let asset = dataOffer.asset;
let contractPolicy = dataOffer.contractOffers[0].policy;

const propertyGridGroups = [
this.assetPropertyGridGroupBuilder.buildAssetPropertiesGroup(asset, null),
this.assetPropertyGridGroupBuilder.buildAdditionalPropertiesGroup(asset),
this.assetPropertyGridGroupBuilder.buildPolicyGroup(
asset,
contractPolicy,
),
].filter((it) => it.properties.length);

return {
type: 'data-offer',
asset: dataOffer.asset,
asset: asset,
dataOffer,
propertyGridGroups,
};
Expand All @@ -56,9 +50,9 @@ export class AssetDetailDialogDataService {
this.assetPropertyGridGroupBuilder.buildContractAgreementGroup(
contractAgreement,
),
this.assetPropertyGridGroupBuilder.buildPolicyGroup(
asset,
this.assetPropertyGridGroupBuilder.buildContractPolicyGroup(
contractAgreement.contractPolicy,
asset.name,
),
this.assetPropertyGridGroupBuilder.buildAssetPropertiesGroup(
asset,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,7 @@
<div class="flex flex-col space-y-[10px]" mat-dialog-content>
<!-- Progress Bar -->
<mat-progress-bar
*ngIf="
(data.type === 'data-offer' &&
contractNegotiationService.isBusy(data.dataOffer!.contractOffers[0])) ||
(data.type === 'contract-agreement' &&
data.contractAgreement!.isInProgress)
"
*ngIf="showProgressBar"
color="primary"
mode="indeterminate"></mat-progress-bar>

Expand Down Expand Up @@ -66,6 +61,13 @@
<!-- Properties -->
<property-grid-group class="mt-[15px]" [propGroups]="propGroups">
</property-grid-group>

<!-- Contract Offers -->
<contract-offer-mini-list
*ngIf="data.type === 'data-offer'"
[contractOffers]="data.dataOffer!.contractOffers"
(negotiateClick)="onNegotiateClick($event)">
</contract-offer-mini-list>
</div>

<mat-dialog-actions>
Expand All @@ -83,12 +85,23 @@
</button>

<button
*ngIf="data.type === 'data-offer'"
*ngIf="
data.type === 'data-offer' &&
data.dataOffer?.contractOffers?.length === 1
"
mat-raised-button
color="primary"
[disabled]="negotiationState != 'ready'"
[ngSwitch]="negotiationState"
(click)="onNegotiateClick()">
[disabled]="
contractNegotiationService.negotiationState(
data.dataOffer!.contractOffers[0]
) != 'ready'
"
[ngSwitch]="
contractNegotiationService.negotiationState(
data.dataOffer!.contractOffers[0]
)
"
(click)="onNegotiateClick(data.dataOffer!.contractOffers[0])">
<ng-container *ngSwitchCase="'ready'">Negotiate</ng-container>
<ng-container *ngSwitchCase="'negotiating'">
Negotiating...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from '@angular/material/dialog';
import {Observable, Subject, isObservable} from 'rxjs';
import {filter, finalize, takeUntil} from 'rxjs/operators';
import {UiContractOffer} from '@sovity.de/edc-client';
import {EdcApiService} from '../../../core/services/api/edc-api.service';
import {ContractNegotiationService} from '../../../core/services/contract-negotiation.service';
import {Asset} from '../../../core/services/models/asset';
Expand Down Expand Up @@ -39,17 +40,19 @@ export class AssetDetailDialogComponent implements OnDestroy {

loading = false;

get negotiationState(): 'ready' | 'negotiating' | 'negotiated' {
const dataOffer = this.data.dataOffer!;
let contractOffer = dataOffer.contractOffers[0];
let isNegotiated =
this.contractNegotiationService.isNegotiated(contractOffer);
if (isNegotiated) {
return 'negotiated';
get showProgressBar(): boolean {
switch (this.data.type) {
case 'data-offer':
return (
this.data.dataOffer?.contractOffers?.some((it) =>
this.contractNegotiationService.isBusy(it),
) ?? false
);
case 'contract-agreement':
return this.data.contractAgreement!.isInProgress;
default:
return false;
}

let isBusy = this.contractNegotiationService.isBusy(contractOffer);
return isBusy ? 'negotiating' : 'ready';
}

constructor(
Expand Down Expand Up @@ -87,10 +90,10 @@ export class AssetDetailDialogComponent implements OnDestroy {
});
}

onNegotiateClick() {
onNegotiateClick(contractOffer: UiContractOffer) {
this.contractNegotiationService.negotiate(
this.data.dataOffer!,
this.data.dataOffer!.contractOffers[0],
contractOffer,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ import {
getOnlineStatusColor,
getOnlineStatusIcon,
} from '../icon-with-online-status/online-status-utils';
import {PolicyPropertyFieldBuilder} from './policy-property-field-builder';

@Injectable()
export class AssetPropertyGridGroupBuilder {
constructor(
private activeFeatureSet: ActiveFeatureSet,
private propertyGridUtils: PropertyGridFieldService,
private jsonDialogService: JsonDialogService,
private policyPropertyFieldBuilder: PolicyPropertyFieldBuilder,
) {}

buildAssetPropertiesGroup(
Expand Down Expand Up @@ -183,20 +185,6 @@ export class AssetPropertyGridGroupBuilder {
return {groupLabel, properties};
}

buildPolicyGroup(
asset: Asset,
contractPolicy: UiPolicy | null,
groupLabel: string = 'Policies',
) {
let properties: PropertyGridField[] = [];
if (contractPolicy) {
properties.push(
this.buildContractPolicyField(contractPolicy, asset.name),
);
}
return {groupLabel, properties};
}

buildContractAgreementGroup(contractAgreement: ContractAgreementCardMapped) {
let properties: PropertyGridField[] = [
{
Expand Down Expand Up @@ -251,18 +239,17 @@ export class AssetPropertyGridGroupBuilder {
};
}

buildContractPolicyField(contractPolicy: UiPolicy, subtitle: string) {
buildContractPolicyGroup(
contractPolicy: UiPolicy,
subtitle: string,
): PropertyGridGroup {
return {
icon: 'policy',
label: 'Contract Policy',
text: 'Show Policy Details',
onclick: () =>
this.jsonDialogService.showJsonDetailDialog({
title: 'Contract Policy',
subtitle,
icon: 'policy',
objectForJson: JSON.parse(contractPolicy.policyJsonLd),
}),
groupLabel: 'Contract Policy',
properties: this.policyPropertyFieldBuilder.buildPolicyPropertyFields(
contractPolicy,
'Contract Policy JSON-LD',
subtitle,
),
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {Injectable} from '@angular/core';
import {UiPolicy} from '@sovity.de/edc-client';
import {PolicyCardBuilder} from '../../../routes/connector-ui/policy-definition-page/policy-cards/policy-card-builder';
import {JsonDialogService} from '../../json-dialog/json-dialog/json-dialog.service';
import {PropertyGridField} from '../../property-grid/property-grid/property-grid-field';

@Injectable()
export class PolicyPropertyFieldBuilder {
constructor(
private policyCardBuilder: PolicyCardBuilder,
private jsonDialogService: JsonDialogService,
) {}

buildPolicyPropertyFields(
policy: UiPolicy,
policyDetailDialogTitle: string,
policyDetailDialogSubtitle: string,
): PropertyGridField[] {
let constraints = this.policyCardBuilder.buildPolicyCardConstraints(policy);
let irregularities = policy.errors;
return [
{
icon: 'policy',
label: 'Policy',
additionalClasses: 'whitespace-pre-line',
text: [
...constraints.map((it) => `${it.left} ${it.operator} ${it.right}`),
...irregularities,
].join('\n'),
},
{
icon: 'policy',
label: 'Policy JSON-LD',
text: 'Show JSON-LD',
onclick: () =>
this.jsonDialogService.showJsonDetailDialog({
title: policyDetailDialogTitle,
subtitle: policyDetailDialogSubtitle,
icon: 'policy',
objectForJson: JSON.parse(policy.policyJsonLd),
}),
},
];
}
}
5 changes: 5 additions & 0 deletions src/app/component-library/catalog/catalog.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import {AssetDetailDialogDataService} from './asset-detail-dialog/asset-detail-d
import {AssetDetailDialogComponent} from './asset-detail-dialog/asset-detail-dialog.component';
import {AssetDetailDialogService} from './asset-detail-dialog/asset-detail-dialog.service';
import {AssetPropertyGridGroupBuilder} from './asset-detail-dialog/asset-property-grid-group-builder';
import {PolicyPropertyFieldBuilder} from './asset-detail-dialog/policy-property-field-builder';
import {ContractOfferIconComponent} from './contract-offer-icon/contract-offer-icon.component';
import {ContractOfferMiniListComponent} from './contract-offer-mini-list/contract-offer-mini-list.component';
import {DataOfferCardsComponent} from './data-offer-cards/data-offer-cards.component';
import {IconWithOnlineStatusComponent} from './icon-with-online-status/icon-with-online-status.component';
import {TransferHistoryMiniListComponent} from './transfer-history-mini-list/transfer-history-mini-list.component';
Expand Down Expand Up @@ -43,13 +45,15 @@ import {TransferHistoryMiniListComponent} from './transfer-history-mini-list/tra
declarations: [
AssetDetailDialogComponent,
ContractOfferIconComponent,
ContractOfferMiniListComponent,
DataOfferCardsComponent,
TransferHistoryMiniListComponent,
IconWithOnlineStatusComponent,
],
exports: [
AssetDetailDialogComponent,
ContractOfferIconComponent,
ContractOfferMiniListComponent,
DataOfferCardsComponent,
TransferHistoryMiniListComponent,
IconWithOnlineStatusComponent,
Expand All @@ -58,6 +62,7 @@ import {TransferHistoryMiniListComponent} from './transfer-history-mini-list/tra
AssetPropertyGridGroupBuilder,
AssetDetailDialogDataService,
AssetDetailDialogService,
PolicyPropertyFieldBuilder,
],
})
export class CatalogModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<ng-container *ngIf="!contractOffers?.length">
<div class="flex flex-row flex-wrap property-grid-group-title">
Contract Offers
</div>
<i>No contract offers available.</i>
</ng-container>

<ng-container *ngFor="let contractOffer of contractOffers; let i = index">
<div
class="flex flex-row items-center space-x-[5px] property-grid-group-title">
<span> Contract Offer {{ contractOffers.length >= 2 ? i + 1 : '' }} </span>

<mat-progress-spinner
*ngIf="contractNegotiationService.isBusy(contractOffer)"
class="mat-icon-[14px]"
diameter="14"
color="primary"
mode="indeterminate">
</mat-progress-spinner>
</div>

<property-grid
[columns]="3"
[props]="contractOffer.properties"></property-grid>

<div *ngIf="contractOffers.length > 1" class="flex flex-row mt-[15px]">
<button
mat-raised-button
color="primary"
[disabled]="
contractNegotiationService.negotiationState(contractOffer) != 'ready'
"
[ngSwitch]="contractNegotiationService.negotiationState(contractOffer)"
(click)="negotiateClick.emit(contractOffer)">
<ng-container *ngSwitchCase="'ready'">Negotiate</ng-container>
<ng-container *ngSwitchCase="'negotiating'">
Negotiating...
</ng-container>
<ng-container *ngSwitchCase="'negotiated'">
Successfully Negotiated
</ng-container>
</button>
</div>
</ng-container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {
Component,
EventEmitter,
HostBinding,
Input,
Output,
} from '@angular/core';
import {ContractNegotiationService} from '../../../core/services/contract-negotiation.service';
import {ContractOffer} from '../../../core/services/models/contract-offer';

@Component({
selector: 'contract-offer-mini-list',
templateUrl: 'contract-offer-mini-list.component.html',
})
export class ContractOfferMiniListComponent {
@Input()
contractOffers!: ContractOffer[];

@HostBinding('class.flex')
@HostBinding('class.flex-col')
cls = true;

@Output()
negotiateClick = new EventEmitter<ContractOffer>();

constructor(public contractNegotiationService: ContractNegotiationService) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ let dataOffers: UiDataOffer[] = [
asset: TestAssets.full,
contractOffers: [
{
contractOfferId: 'test-contract-offer-1',
contractOfferId:
'Zmlyc3QtY2Q=:Zmlyc3QtYXNzZXQtMS4w:MjgzNTZkMTMtN2ZhYy00NTQwLTgwZjItMjI5NzJjOTc1ZWNi',
policy: TestPolicies.connectorRestricted,
},
{
contractOfferId: 'test-contract-offer-2',
contractOfferId:
'Bmlyf3Qt62Q=:Zmlyc3QtYXNzZXQtMS4w:NigzNTZkMTMtN2ZhYy00NTQwLTgwZjItMjI5NzJjOTc1ZWNj',
policy: TestPolicies.warnings,
},
],
Expand Down
Loading

0 comments on commit dfa651c

Please sign in to comment.