11import { Component , Inject , OnInit } from '@angular/core' ;
2- import { HttpDataAddress , DataAddress , AssetInput } from '@think-it-labs/edc-connector-client' ;
3- import { MatDialogRef } from "@angular/material/dialog" ;
2+ import { HttpDataAddress , DataAddress } from '@think-it-labs/edc-connector-client' ;
43import { JsonDoc } from "../../../shared/models/json-doc" ;
54import { StorageType } from "../../../shared/models/storage-type" ;
65import { AmazonS3DataAddress } from "../../../shared/models/amazon-s3-data-address" ;
@@ -19,6 +18,7 @@ import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
1918import { AssetService } from 'src/app/shared/services/asset.service' ;
2019import { BehaviorSubject } from 'rxjs' ;
2120import { Router } from '@angular/router' ;
21+ import { MatSlideToggleChange } from '@angular/material/slide-toggle' ;
2222
2323
2424@Component ( {
@@ -89,7 +89,7 @@ export class AssetCreateComponent implements OnInit {
8989 type : 'InesDataStore'
9090 } ;
9191
92- assetType :any ;
92+ assetType : any ;
9393 assetTypes = Object . entries ( ASSET_TYPES ) ;
9494 defaultForms : JsonFormData [ ]
9595 selectedForms : JsonFormData [ ]
@@ -101,7 +101,7 @@ export class AssetCreateComponent implements OnInit {
101101 config = CKEDITOR_CONFIG
102102 selectedAssetTypeVocabularies : Vocabulary [ ]
103103
104- urlPattern : RegExp = / ^ ( f i l e | f t p | h t t p | h t t p s | i m a p | i r c | n n t p | a c a p | i c a p | m t q p | w s s ) : \/ \/ ( l o c a l h o s t | ( [ a - z \d ] ( [ a - z \d - ] * [ a - z \d ] ) * ) | ( ( [ a - z \d ] ( [ a - z \d - ] * [ a - z \d ] ) * ) \. ) + [ a - z ] { 2 , } | ( ( \d { 1 , 3 } \. ) { 3 } \d { 1 , 3 } ) ) ( : \d + ) ? ( \/ [ - a - z \d % _ . ~ + ] * ) * ( \? [ ; & a - z \d % _ . ~ + = - ] * ) ? ( \# [ - a - z \d _ ] * ) ? $ / i ;
104+ urlPattern : RegExp = / ^ h t t p s ? : \/ \/ ( w w w \. ) ? [ - a - z A - Z 0 - 9 @ : % . _ + ~ # = ] { 1 , 256 } \. [ a - z A - Z ] { 2 , 6 } \b ( [ - a - z A - Z 0 - 9 ( ) @ : % _ + . ~ # ? & / / = ] * ) $ / ;
105105
106106 private fetch$ = new BehaviorSubject ( null ) ;
107107
@@ -122,7 +122,7 @@ export class AssetCreateComponent implements OnInit {
122122 }
123123 if ( this . selectedVocabularies ?. length > 0 ) {
124124 this . selectedVocabularies . forEach ( s => {
125- if ( this . selectedAssetTypeVocabularies . find ( satv => satv [ '@id' ] === s [ '@id' ] ) ) {
125+ if ( this . selectedAssetTypeVocabularies . find ( satv => satv [ '@id' ] === s [ '@id' ] ) ) {
126126 this . initVocabularyForm ( s , false )
127127 }
128128 } )
@@ -168,7 +168,7 @@ export class AssetCreateComponent implements OnInit {
168168 const forms : JsonFormData [ ] = [ ...this . defaultForms , ...this . selectedForms ]
169169
170170 let assetDataProperty : any = { }
171- forms . forEach ( async f => {
171+ forms . forEach ( async f => {
172172 if ( f . schema && f . schema . hasOwnProperty ( "@context" ) ) {
173173 // Add context if it is provided in the Json Schema
174174 const jsonSchema : JsonDoc = f . schema as JsonDoc ;
@@ -197,7 +197,7 @@ export class AssetCreateComponent implements OnInit {
197197 dataAddress = this . amazonS3DataAddress ;
198198 } else if ( this . storageTypeId === DATA_ADDRESS_TYPES . httpData ) {
199199 dataAddress = this . httpDataAddress ;
200- } else if ( this . storageTypeId === DATA_ADDRESS_TYPES . inesDataStore ) {
200+ } else if ( this . storageTypeId === DATA_ADDRESS_TYPES . inesDataStore ) {
201201 dataAddress = this . inesDataStoreAddress ;
202202 } else {
203203 this . notificationService . showError ( "Incorrect destination value" ) ;
@@ -213,6 +213,7 @@ export class AssetCreateComponent implements OnInit {
213213 } ;
214214
215215 if ( this . storageTypeId === DATA_ADDRESS_TYPES . inesDataStore && this . inesDataStoreAddress ?. file ) {
216+ this . loadingService . showLoading ( 'Processing the file...' ) ;
216217 const file = this . inesDataStoreAddress ?. file ;
217218
218219 const chunkSize = 1024 * 1024 ;
@@ -229,7 +230,7 @@ export class AssetCreateComponent implements OnInit {
229230 assetInput . blob = new Blob ( chunks ) ;
230231 }
231232
232- this . createAsset ( assetInput )
233+ await this . createAsset ( assetInput )
233234 }
234235 addInfoProperties ( properties : JsonDoc ) {
235236 // Add default information
@@ -245,7 +246,7 @@ export class AssetCreateComponent implements OnInit {
245246 this . addKeywords ( properties ) ;
246247 }
247248
248- addKeywords ( properties : JsonDoc ) {
249+ addKeywords ( properties : JsonDoc ) {
249250 const parsedKeywords : string [ ] = [ ] ;
250251 this . keywords . split ( "," ) . forEach ( keyword => parsedKeywords . push ( keyword . trim ( ) ) ) ;
251252 properties [ "dcat:keyword" ] = parsedKeywords ;
@@ -286,7 +287,7 @@ export class AssetCreateComponent implements OnInit {
286287 if ( ! this . id || ! this . storageTypeId || ! this . name || ! this . version || ! this . description || ! this . keywords || ! this . shortDescription || ! this . assetType ) {
287288 return false ;
288289 } else {
289- if ( this . storageTypeId === DATA_ADDRESS_TYPES . httpData && ( ! this . httpDataAddress . name || ! this . httpDataAddress . baseUrl || ! this . validateUrl ( ) ) ) {
290+ if ( this . storageTypeId === DATA_ADDRESS_TYPES . httpData && ( ! this . httpDataAddress . name || ! this . httpDataAddress . baseUrl || ! this . validateUrl ( ) ) ) {
290291 return false ;
291292 }
292293 if ( this . storageTypeId === DATA_ADDRESS_TYPES . amazonS3 && ! this . amazonS3DataAddress . region ) {
@@ -328,7 +329,7 @@ export class AssetCreateComponent implements OnInit {
328329
329330 if ( this . selectedVocabularies . length > 0 ) {
330331 this . selectedVocabularies . forEach ( s => {
331- if ( this . selectedAssetTypeVocabularies . find ( satv => satv [ '@id' ] === s [ '@id' ] ) ) {
332+ if ( this . selectedAssetTypeVocabularies . find ( satv => satv [ '@id' ] === s [ '@id' ] ) ) {
332333 this . initVocabularyForm ( s , false )
333334 }
334335 } )
@@ -339,24 +340,24 @@ export class AssetCreateComponent implements OnInit {
339340 * Transform to text asset type value
340341 * @returns asset type text
341342 */
342- getAssetTypeText ( ) {
343- return this . assetType ? ASSET_TYPES [ this . assetType as keyof typeof ASSET_TYPES ] : '' ;
343+ getAssetTypeText ( ) {
344+ return this . assetType ? ASSET_TYPES [ this . assetType as keyof typeof ASSET_TYPES ] : '' ;
344345 }
345346
346- setFiles ( event :File [ ] ) {
347- if ( event ?. length > 0 ) {
347+ setFiles ( event : File [ ] ) {
348+ if ( event ?. length > 0 ) {
348349 this . inesDataStoreAddress . file = event [ 0 ]
349- } else {
350+ } else {
350351 delete this . inesDataStoreAddress . file
351352 }
352353 }
353354
354- onSelectionChangeVocabulary ( ) {
355+ onSelectionChangeVocabulary ( ) {
355356 this . selectedForms = [ ]
356357
357358 if ( this . selectedVocabularies . length > 0 ) {
358359 this . selectedVocabularies . forEach ( s => {
359- if ( this . selectedAssetTypeVocabularies . find ( satv => satv [ '@id' ] === s [ '@id' ] ) ) {
360+ if ( this . selectedAssetTypeVocabularies . find ( satv => satv [ '@id' ] === s [ '@id' ] ) ) {
360361 this . initVocabularyForm ( s , false )
361362 }
362363 } )
@@ -366,46 +367,80 @@ export class AssetCreateComponent implements OnInit {
366367 validateUrl ( ) : boolean {
367368 const regex = new RegExp ( this . urlPattern ) ;
368369 return regex . test ( this . httpDataAddress . baseUrl ) ;
369- }
370+ }
370371
371372
372- private createAsset ( asset : AssetInput ) {
373- const newAsset = asset ;
374- if ( newAsset ) {
375- if ( newAsset . dataAddress . type !== DATA_ADDRESS_TYPES . inesDataStore ) {
376- this . assetService . createAsset ( newAsset ) . subscribe ( {
377- next : ( ) => this . fetch$ . next ( null ) ,
378- error : err => this . showError ( err , "This asset cannot be created" ) ,
379- complete : ( ) => {
380- this . navigateToAsset ( )
381- this . notificationService . showInfo ( "Successfully created" ) ;
382- this . loadingService . hideLoading ( ) ;
383- }
384- } )
385- } else {
386- this . assetService . createStorageAsset ( newAsset ) . subscribe ( {
387- next : ( ) => this . fetch$ . next ( null ) ,
388- error : err => this . showError ( err , "This asset cannot be created" ) ,
389- complete : ( ) => {
390- this . navigateToAsset ( )
391- this . notificationService . showInfo ( "Successfully created" ) ;
392- this . loadingService . hideLoading ( ) ;
373+ async createAsset ( assetInput : any ) {
374+ if ( this . storageTypeId === DATA_ADDRESS_TYPES . inesDataStore && this . inesDataStoreAddress . file ) {
375+ const file = this . inesDataStoreAddress . file ;
376+ const chunkSize = 50 * 1024 * 1024 ; // 50 MB
377+ const totalChunks = Math . ceil ( file . size / chunkSize ) ;
378+ const fileName = file . name ;
379+ const maxRetries = 3 ;
380+
381+ for ( let chunkIndex = 0 ; chunkIndex < totalChunks ; chunkIndex ++ ) {
382+ const start = chunkIndex * chunkSize ;
383+ const chunk = file . slice ( start , start + chunkSize ) ;
384+
385+ let attempt = 0 ;
386+ let success = false ;
387+
388+ const progressPercentage = Math . floor ( ( ( chunkIndex + 1 ) / totalChunks ) * 100 ) ;
389+
390+ while ( attempt < maxRetries && ! success ) {
391+ try {
392+ this . loadingService . updateMessage ( `Uploading file: ${ progressPercentage } % completed` ) ;
393+
394+ await this . assetService . uploadChunk ( assetInput , chunk , fileName , chunkIndex , totalChunks ) ;
395+ success = true ;
396+ } catch ( error ) {
397+ attempt ++ ;
398+ if ( attempt >= maxRetries ) {
399+ this . loadingService . hideLoading ( ) ;
400+ this . notificationService . showError ( `Error uploading chunk ${ chunkIndex + 1 } . Maximum retries reached.` ) ;
401+ return ;
402+ }
393403 }
394- } )
404+ }
395405 }
396406
407+ try {
408+ await this . assetService . finalizeUpload ( assetInput , fileName ) ;
409+ this . loadingService . hideLoading ( ) ;
410+ this . notificationService . showInfo ( 'Asset created successfully' ) ;
411+ this . navigateToAsset ( ) ;
412+ } catch ( error : any ) {
413+ this . loadingService . hideLoading ( ) ;
414+ this . notificationService . showError ( 'Error finalizing the asset creation: ' + error . error [ 0 ] . message ) ;
415+ }
416+ } else {
417+ this . assetService . createAsset ( assetInput ) . subscribe ( {
418+ next : ( ) => this . fetch$ . next ( null ) ,
419+ error : ( err ) => {
420+ this . loadingService . hideLoading ( ) ;
421+ this . showError ( err , "Error creating the asset: " + err . error [ 0 ] . message ) ;
422+ } ,
423+ complete : ( ) => {
424+ this . loadingService . hideLoading ( ) ;
425+ this . notificationService . showInfo ( 'Asset created successfully' ) ;
426+ this . navigateToAsset ( ) ;
427+ } ,
428+ } ) ;
397429 }
398430 }
399431
400432
401-
402433 private showError ( error : string , errorMessage : string ) {
403434 this . notificationService . showError ( errorMessage ) ;
404435 console . error ( error ) ;
405436 this . loadingService . hideLoading ( ) ;
406437 }
407438
408- navigateToAsset ( ) {
439+ navigateToAsset ( ) {
409440 this . router . navigate ( [ 'assets' ] )
410441 }
442+
443+ onToggleChange ( propertyName : string , event : MatSlideToggleChange ) : void {
444+ this . httpDataAddress [ propertyName ] = event ? 'true' : 'false' ;
445+ }
411446}
0 commit comments