From 5aa63038a041cdcb3d5a789572a5e64cf2f58ecb Mon Sep 17 00:00:00 2001 From: efiege <105237007+efiege@users.noreply.github.com> Date: Tue, 30 Aug 2022 11:37:03 +0200 Subject: [PATCH] Add functionality for EDC Demo (#9) * 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. --- .../workflows/build-and-release-image.yaml | 1 + .../asset-editor-dialog.component.html | 32 +++--- .../asset-editor-dialog.component.ts | 22 ++-- ...log-browser-transfer-dialog.component.html | 30 +++-- ...talog-browser-transfer-dialog.component.ts | 4 +- .../catalog-browser.component.ts | 2 +- .../contract-viewer.component.ts | 20 +--- .../transfer-history-viewer.component.ts | 106 ++++++++++-------- .../models/contract-offer-response.ts | 6 + .../services/catalog-browser.service.ts | 5 +- 10 files changed, 112 insertions(+), 116 deletions(-) create mode 100644 src/modules/edc-demo/models/contract-offer-response.ts diff --git a/.github/workflows/build-and-release-image.yaml b/.github/workflows/build-and-release-image.yaml index 24f132e7b..5c10a9f4f 100644 --- a/.github/workflows/build-and-release-image.yaml +++ b/.github/workflows/build-and-release-image.yaml @@ -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 diff --git a/src/modules/edc-demo/components/asset-editor-dialog/asset-editor-dialog.component.html b/src/modules/edc-demo/components/asset-editor-dialog/asset-editor-dialog.component.html index d46bcab78..b10624366 100644 --- a/src/modules/edc-demo/components/asset-editor-dialog/asset-editor-dialog.component.html +++ b/src/modules/edc-demo/components/asset-editor-dialog/asset-editor-dialog.component.html @@ -22,28 +22,24 @@
- - Destination - - - {{storageType.name}} - - + + Type + - - Account - + + Description + - - - Container - +
+
+ + Originator + - - - Blob Name - + + Data Destination (JSON) +
diff --git a/src/modules/edc-demo/components/asset-editor-dialog/asset-editor-dialog.component.ts b/src/modules/edc-demo/components/asset-editor-dialog/asset-editor-dialog.component.ts index e95f54e04..00175e3c1 100644 --- a/src/modules/edc-demo/components/asset-editor-dialog/asset-editor-dialog.component.ts +++ b/src/modules/edc-demo/components/asset-editor-dialog/asset-editor-dialog.component.ts @@ -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, @Inject('STORAGE_TYPES') public storageTypes: StorageType[]) { @@ -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 }); diff --git a/src/modules/edc-demo/components/catalog-browser-transfer-dialog/catalog-browser-transfer-dialog.component.html b/src/modules/edc-demo/components/catalog-browser-transfer-dialog/catalog-browser-transfer-dialog.component.html index be3be07a4..a6d64eaa2 100644 --- a/src/modules/edc-demo/components/catalog-browser-transfer-dialog/catalog-browser-transfer-dialog.component.html +++ b/src/modules/edc-demo/components/catalog-browser-transfer-dialog/catalog-browser-transfer-dialog.component.html @@ -1,26 +1,24 @@ - - Destination - - - {{storageType.name}} - - - + + Data Destination (JSON) + +
- + - -
- + + +
diff --git a/src/modules/edc-demo/components/catalog-browser-transfer-dialog/catalog-browser-transfer-dialog.component.ts b/src/modules/edc-demo/components/catalog-browser-transfer-dialog/catalog-browser-transfer-dialog.component.ts index 9555bcf04..0f24956ef 100644 --- a/src/modules/edc-demo/components/catalog-browser-transfer-dialog/catalog-browser-transfer-dialog.component.ts +++ b/src/modules/edc-demo/components/catalog-browser-transfer-dialog/catalog-browser-transfer-dialog.component.ts @@ -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, @@ -23,7 +23,7 @@ export class CatalogBrowserTransferDialog implements OnInit { onTransfer() { - this.dialogRef.close({storageTypeId: this.storageTypeId}); + this.dialogRef.close({dataDestination: this.dataDestination}); } } diff --git a/src/modules/edc-demo/components/catalog-browser/catalog-browser.component.ts b/src/modules/edc-demo/components/catalog-browser/catalog-browser.component.ts index bcc06c844..09be30c95 100644 --- a/src/modules/edc-demo/components/catalog-browser/catalog-browser.component.ts +++ b/src/modules/edc-demo/components/catalog-browser/catalog-browser.component.ts @@ -63,7 +63,7 @@ export class CatalogBrowserComponent implements OnInit { assetId: contractOffer.asset.id, policy: contractOffer.policy, }, - connectorId: 'yomama', + connectorId: 'my-connector', protocol: 'ids-multipart' }; diff --git a/src/modules/edc-demo/components/contract-viewer/contract-viewer.component.ts b/src/modules/edc-demo/components/contract-viewer/contract-viewer.component.ts index 3d1e4865e..4ba838034 100644 --- a/src/modules/edc-demo/components/contract-viewer/contract-viewer.component.ts +++ b/src/modules/edc-demo/components/contract-viewer/contract-viewer.component.ts @@ -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!); @@ -95,20 +91,14 @@ export class ContractViewerComponent implements OnInit { return !!this.runningTransfers.find(rt => rt.contractId === contractId); } - private createTransferRequest(contract: ContractAgreementDto, storageTypeId: string): Observable { + private createTransferRequest(contract: ContractAgreementDto, dataDestination: string): Observable { 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' diff --git a/src/modules/edc-demo/components/transfer-history/transfer-history-viewer.component.ts b/src/modules/edc-demo/components/transfer-history/transfer-history-viewer.component.ts index bbde4a5eb..1a8e4bf95 100644 --- a/src/modules/edc-demo/components/transfer-history/transfer-history-viewer.component.ts +++ b/src/modules/edc-demo/components/transfer-history/transfer-history-viewer.component.ts @@ -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 = 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 = 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() : ''; + } } diff --git a/src/modules/edc-demo/models/contract-offer-response.ts b/src/modules/edc-demo/models/contract-offer-response.ts new file mode 100644 index 000000000..6b6b2875e --- /dev/null +++ b/src/modules/edc-demo/models/contract-offer-response.ts @@ -0,0 +1,6 @@ +import {ContractOffer} from "./contract-offer"; + +export interface ContractOfferResponse { + id: string; + contractOffers: ContractOffer[]; +} diff --git a/src/modules/edc-demo/services/catalog-browser.service.ts b/src/modules/edc-demo/services/catalog-browser.service.ts index df30e8f15..f3366014e 100644 --- a/src/modules/edc-demo/services/catalog-browser.service.ts +++ b/src/modules/edc-demo/services/catalog-browser.service.ts @@ -16,6 +16,7 @@ import { TransferProcessService, TransferRequestDto } from "../../edc-dmgmt-client"; +import {ContractOfferResponse} from "../models/contract-offer-response"; /** @@ -34,8 +35,8 @@ export class CatalogBrowserService { } getContractOffers(): Observable { - return this.post(this.catalogApiUrl) - .pipe(map(contractOffers => contractOffers.map(contractOffer => { + return this.httpClient.get(this.catalogApiUrl) + .pipe(map(contractOfferResponse => contractOfferResponse.contractOffers.map(contractOffer => { contractOffer.asset = new Asset(contractOffer.asset.properties) return contractOffer; })));