Skip to content

Commit

Permalink
Add functionality for EDC Demo (#9)
Browse files Browse the repository at this point in the history
* ci: Added support for building images on tag on main branch. Renamed action.

* feature: Added support for catalog. Added possibility to create assets with arbitrary dataDestinations. Added possibility to start data transfers to arbitrary dataDestinations. Transfer Hirstory entries will be sorted by createDate now.
  • Loading branch information
efiege committed Aug 31, 2022
1 parent e49e294 commit 5aa6303
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 116 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build-and-release-image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:
tags: |
type=semver,pattern={{version}},enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
type=raw,value=latest,enable={{is_default_branch}}
type=sha
- name: Build EDC-UI image
uses: docker/build-push-action@v2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,24 @@
</div>

<div>
<mat-form-field class="form-field" color="accent" id="form-field-destination">
<mat-label>Destination</mat-label>
<mat-select [(ngModel)]="storageTypeId" disabled>
<mat-option *ngFor="let storageType of storageTypes " [value]="storageType.id">
{{storageType.name}}
</mat-option>
</mat-select>
<mat-form-field class="form-field" color="accent">
<mat-label>Type</mat-label>
<input [(ngModel)]="type" matInput [placeholder]="'text/plain'">
</mat-form-field>

<mat-form-field class="form-field" color="accent" id="form-field-account">
<mat-label>Account</mat-label>
<input [(ngModel)]="account" matInput>
<mat-form-field class="form-field" color="accent">
<mat-label>Description</mat-label>
<input [(ngModel)]="description" matInput [placeholder]="'1.0'">
</mat-form-field>

<mat-form-field class="form-field" color="accent" id="form-field-container">
<mat-label>Container</mat-label>
<input disabled [(ngModel)]="container" matInput>
</div>
<div>
<mat-form-field class="form-field" color="accent">
<mat-label>Originator</mat-label>
<input [(ngModel)]="originator" matInput [placeholder]="'text/plain'">
</mat-form-field>

<mat-form-field class="form-field" color="accent" id="form-field-blobname">
<mat-label>Blob Name</mat-label>
<input [(ngModel)]="blobname" matInput>
<mat-form-field class="form-field" color="accent">
<mat-label>Data Destination (JSON)</mat-label>
<input [(ngModel)]="dataDestination" matInput [placeholder]="'text/plain'">
</mat-form-field>
</div>
</mat-dialog-content>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ export class AssetEditorDialog implements OnInit {
version: string = '';
name: string = '';
contenttype: string = '';

storageTypeId: string = 'AzureStorage';
account: string = '';
container: string = 'src-container';
blobname: string = '';
type: string = '';
description: string = '';
originator: string = '';
dataDestination: string = '';

constructor(private assetService: AssetService, private dialogRef: MatDialogRef<AssetEditorDialog>,
@Inject('STORAGE_TYPES') public storageTypes: StorageType[]) {
Expand All @@ -36,17 +35,12 @@ export class AssetEditorDialog implements OnInit {
"asset:prop:version": this.version,
"asset:prop:id": this.id,
"asset:prop:contenttype": this.contenttype,
"asset:prop:type": this.type,
"asset:prop:description": this.description,
"asset:prop:originator": this.originator,
}
},
dataAddress: {
properties: {
"type": this.storageTypeId,
"account": this.account,
"container": this.container,
"blobname": this.blobname,
"keyName": `${this.account}-key1`
},
}
dataAddress: JSON.parse(this.dataDestination)
};

this.dialogRef.close({ assetEntryDto });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
<mat-dialog-content *ngIf="storageTypes as storageTypes">

<mat-form-field class="form-field" color="accent" id="form-field-destination">
<mat-label>Destination</mat-label>
<mat-select [(ngModel)]="storageTypeId">
<mat-option *ngFor="let storageType of storageTypes" [value]="storageType.id">
{{storageType.name}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="form-field-stretch" color="accent" id="form-field-permissions">
<mat-label>Data Destination (JSON)</mat-label>
<input [(ngModel)]="dataDestination" matInput>
</mat-form-field>

</mat-dialog-content>

<mat-dialog-actions>
<div>
<button (click)="onTransfer()" color="accent" mat-stroked-button>
<mat-icon>downloading</mat-icon> Start transfer
</button>
<button (click)="onTransfer()" color="accent" mat-stroked-button>
<mat-icon>downloading</mat-icon>
Start transfer
</button>

<button color="accent" mat-dialog-close mat-stroked-button>
<mat-icon>cancel</mat-icon> Cancel
</button>
</div>
<!-- <mat-progress-bar mode="indeterminate" color="accent"></mat-progress-bar> -->
<button color="accent" mat-dialog-close mat-stroked-button>
<mat-icon>cancel</mat-icon>
Cancel
</button>
</div>
<!-- <mat-progress-bar mode="indeterminate" color="accent"></mat-progress-bar> -->

</mat-dialog-actions>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {StorageType} from '../../models/storage-type';
export class CatalogBrowserTransferDialog implements OnInit {

name: string = '';
storageTypeId = '';
dataDestination: string = '';

constructor(@Inject('STORAGE_TYPES') public storageTypes: StorageType[],
private dialogRef: MatDialogRef<CatalogBrowserTransferDialog>,
Expand All @@ -23,7 +23,7 @@ export class CatalogBrowserTransferDialog implements OnInit {


onTransfer() {
this.dialogRef.close({storageTypeId: this.storageTypeId});
this.dialogRef.close({dataDestination: this.dataDestination});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class CatalogBrowserComponent implements OnInit {
assetId: contractOffer.asset.id,
policy: contractOffer.policy,
},
connectorId: 'yomama',
connectorId: 'my-connector',
protocol: 'ids-multipart'
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,8 @@ export class ContractViewerComponent implements OnInit {
const dialogRef = this.dialog.open(CatalogBrowserTransferDialog);

dialogRef.afterClosed().pipe(first()).subscribe(result => {
const storageTypeId: string = result.storageTypeId;
if (storageTypeId !== 'AzureStorage') {
this.notificationService.showError("Only storage type \"AzureStorage\" is implemented currently!")
return;
}
this.createTransferRequest(contract, storageTypeId)
const dataDestination: string = result.dataDestination;
this.createTransferRequest(contract, dataDestination)
.pipe(switchMap(trq => this.transferService.initiateTransfer(trq)))
.subscribe(transferId => {
this.startPolling(transferId, contract.id!);
Expand All @@ -95,20 +91,14 @@ export class ContractViewerComponent implements OnInit {
return !!this.runningTransfers.find(rt => rt.contractId === contractId);
}

private createTransferRequest(contract: ContractAgreementDto, storageTypeId: string): Observable<TransferRequestDto> {
private createTransferRequest(contract: ContractAgreementDto, dataDestination: string): Observable<TransferRequestDto> {
return this.getOfferedAssetForId(contract.assetId!).pipe(map(offeredAsset => {
return {
assetId: offeredAsset.id,
contractId: contract.id,
connectorId: "consumer", //doesn't matter, but cannot be null
dataDestination: {
properties: {
"type": storageTypeId,
account: this.homeConnectorStorageAccount, // CAUTION: hardcoded value for AzureBlob
// container: omitted, so it will be auto-assigned by the EDC runtime
}
},
managedResources: true,
dataDestination: JSON.parse(dataDestination),
managedResources: false,
transferType: {isFinite: true}, //must be there, otherwise NPE on backend
connectorAddress: offeredAsset.originator,
protocol: 'ids-multipart'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,68 @@ import {Component, OnInit} from '@angular/core';
import {Observable, of} from 'rxjs';
import {TransferProcessDto, TransferProcessService} from "../../../edc-dmgmt-client";
import {AppConfigService} from "../../../app/app-config.service";
import {ConfirmationDialogComponent, ConfirmDialogModel} from "../confirmation-dialog/confirmation-dialog.component";
import {
ConfirmationDialogComponent,
ConfirmDialogModel
} from "../confirmation-dialog/confirmation-dialog.component";
import {MatDialog} from "@angular/material/dialog";
import {map} from "rxjs/operators";

@Component({
selector: 'edc-demo-transfer-history',
templateUrl: './transfer-history-viewer.component.html',
styleUrls: ['./transfer-history-viewer.component.scss']
selector: 'edc-demo-transfer-history',
templateUrl: './transfer-history-viewer.component.html',
styleUrls: ['./transfer-history-viewer.component.scss']
})
export class TransferHistoryViewerComponent implements OnInit {

columns: string[] = ['id', 'creationDate', 'state', 'lastUpdated', 'connectorId', 'assetId', 'contractId', 'action'];
transferProcesses$: Observable<TransferProcessDto[]> = of([]);
storageExplorerLinkTemplate: string | undefined;

constructor(private transferProcessService: TransferProcessService,
private dialog : MatDialog,
private appConfigService: AppConfigService) {
}

ngOnInit(): void {
this.loadTransferProcesses();
this.storageExplorerLinkTemplate = this.appConfigService.getConfig()?.storageExplorerLinkTemplate
}

onDeprovision(transferProcess: TransferProcessDto): void {

const dialogData = new ConfirmDialogModel("Confirm deprovision", `Deprovisioning resources for transfer [${transferProcess.id}] will take some time and once started, it cannot be stopped.`)
dialogData.confirmColor = "warn";
dialogData.confirmText = "Confirm";
dialogData.cancelText = "Abort";
const ref = this.dialog.open(ConfirmationDialogComponent, {maxWidth: '20%', data: dialogData});

ref.afterClosed().subscribe(res => {
if (res) {
this.transferProcessService.deprovisionTransferProcess(transferProcess.id).subscribe(() => this.loadTransferProcesses());
}
});
}

showStorageExplorerLink(transferProcess: TransferProcessDto) {
return transferProcess.dataDestination?.properties?.type === 'AzureStorage' && transferProcess.state === 'COMPLETED';
}

showDeprovisionButton(transferProcess: TransferProcessDto) {
return ['COMPLETED', 'PROVISIONED', 'REQUESTED', 'REQUESTED_ACK', 'IN_PROGRESS', 'STREAMING'].includes(transferProcess.state);
}

loadTransferProcesses() {
this.transferProcesses$ = this.transferProcessService.getAllTransferProcesses();
}

asDate(epochMillis?: number) {
return epochMillis ? new Date(epochMillis).toLocaleDateString() : '';
}
columns: string[] = ['id', 'creationDate', 'state', 'lastUpdated', 'connectorId', 'assetId', 'contractId', 'action'];
transferProcesses$: Observable<TransferProcessDto[]> = of([]);
storageExplorerLinkTemplate: string | undefined;

constructor(private transferProcessService: TransferProcessService,
private dialog: MatDialog,
private appConfigService: AppConfigService) {
}

ngOnInit(): void {
this.loadTransferProcesses();
this.storageExplorerLinkTemplate = this.appConfigService.getConfig()?.storageExplorerLinkTemplate
}

onDeprovision(transferProcess: TransferProcessDto): void {

const dialogData = new ConfirmDialogModel("Confirm deprovision", `Deprovisioning resources for transfer [${transferProcess.id}] will take some time and once started, it cannot be stopped.`)
dialogData.confirmColor = "warn";
dialogData.confirmText = "Confirm";
dialogData.cancelText = "Abort";
const ref = this.dialog.open(ConfirmationDialogComponent, {
maxWidth: '20%',
data: dialogData
});

ref.afterClosed().subscribe(res => {
if (res) {
this.transferProcessService.deprovisionTransferProcess(transferProcess.id).subscribe(() => this.loadTransferProcesses());
}
});
}

showStorageExplorerLink(transferProcess: TransferProcessDto) {
return transferProcess.dataDestination?.properties?.type === 'AzureStorage' && transferProcess.state === 'COMPLETED';
}

showDeprovisionButton(transferProcess: TransferProcessDto) {
return ['COMPLETED', 'PROVISIONED', 'REQUESTED', 'REQUESTED_ACK', 'IN_PROGRESS', 'STREAMING'].includes(transferProcess.state);
}

loadTransferProcesses() {
this.transferProcesses$ = this.transferProcessService.getAllTransferProcesses()
.pipe(map(transferProcesses => transferProcesses.sort(function (a, b) {
return b.createdTimestamp?.valueOf()!-a.createdTimestamp?.valueOf()!;
})));
}

asDate(epochMillis?: number) {
return epochMillis ? new Date(epochMillis).toLocaleDateString() : '';
}
}
6 changes: 6 additions & 0 deletions src/modules/edc-demo/models/contract-offer-response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {ContractOffer} from "./contract-offer";

export interface ContractOfferResponse {
id: string;
contractOffers: ContractOffer[];
}
5 changes: 3 additions & 2 deletions src/modules/edc-demo/services/catalog-browser.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
TransferProcessService,
TransferRequestDto
} from "../../edc-dmgmt-client";
import {ContractOfferResponse} from "../models/contract-offer-response";


/**
Expand All @@ -34,8 +35,8 @@ export class CatalogBrowserService {
}

getContractOffers(): Observable<ContractOffer[]> {
return this.post<ContractOffer[]>(this.catalogApiUrl)
.pipe(map(contractOffers => contractOffers.map(contractOffer => {
return this.httpClient.get<ContractOfferResponse>(this.catalogApiUrl)
.pipe(map(contractOfferResponse => contractOfferResponse.contractOffers.map(contractOffer => {
contractOffer.asset = new Asset(contractOffer.asset.properties)
return contractOffer;
})));
Expand Down

0 comments on commit 5aa6303

Please sign in to comment.