diff --git a/src/app/core/config/api-config.ts b/src/app/core/config/api-config.ts index b2da3f118d1c008b1dd37df8c75072560c9f7d5c..01952b426b0363907a6ef2bacd4855eec67975b1 100644 --- a/src/app/core/config/api-config.ts +++ b/src/app/core/config/api-config.ts @@ -55,4 +55,6 @@ export const apiConfig = { urlComment: '/api/comments', urlGetActiveUsers: '/api/users/activeUserDetails', urlShareWithTeam: '/api/solution/userAccess', + urlAddToCatalog: '/api/webBasedOnBoarding/addToCatalog', + urlMessagingStatus: '/api/webBasedOnBoarding/messagingStatus', }; diff --git a/src/app/core/services/shared-data/shared-data.service.ts b/src/app/core/services/shared-data/shared-data.service.ts index 8cf26e5200d113d571820708035e40d1df89a140..bc50defd5a2bc7dd9d36d4b1df0a02e8f1586c26 100644 --- a/src/app/core/services/shared-data/shared-data.service.ts +++ b/src/app/core/services/shared-data/shared-data.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; import { AuthorPublisherModel, + LicenseProfileModel, PublicSolution, Revision, } from 'src/app/shared/models'; @@ -47,19 +48,20 @@ export class SharedDataService { private _authorListSubject: BehaviorSubject<AuthorPublisherModel[]> = new BehaviorSubject<AuthorPublisherModel[]>([]); - private _selectedRevisionSubject: BehaviorSubject<{ - version: string; - revisionId: string; - }> = new BehaviorSubject<Revision>({ - version: '', - revisionId: '', - onBoarded: '', - }); + private _selectedRevisionSubject: BehaviorSubject<Revision> = + new BehaviorSubject<Revision>({ + version: '', + revisionId: '', + onBoarded: '', + }); private _ratingSubject: BehaviorSubject<number> = new BehaviorSubject<number>( 0, ); + private _licenseProfileSubject = + new BehaviorSubject<LicenseProfileModel | null>(null); + constructor() {} get versionId$(): Observable<string> { @@ -117,4 +119,12 @@ export class SharedDataService { set rating(value: number) { this._ratingSubject.next(value); } + + get licenseProfile$(): Observable<LicenseProfileModel | null> { + return this._licenseProfileSubject.asObservable(); + } + + set licenseProfile(value: LicenseProfileModel | null) { + this._licenseProfileSubject.next(value); + } } diff --git a/src/app/features/dashboard/on-boarding-model/on-boarding-model.component.html b/src/app/features/dashboard/on-boarding-model/on-boarding-model.component.html index b19248ea1c26274f79b8e08b37d50f187aaa6d6d..d2fb782b9f28b5d81383e64d4ca3435daaecc02e 100644 --- a/src/app/features/dashboard/on-boarding-model/on-boarding-model.component.html +++ b/src/app/features/dashboard/on-boarding-model/on-boarding-model.component.html @@ -1 +1,236 @@ -<p>on-boarding-model works!</p> +<div style="display: flex; flex-direction: column; margin: 40px"> + <gp-headline [headlineTitle]="'On-Boarding Model'"></gp-headline> + <gp-breadcrumb-navigation + [firstNavigationLabel]="{ label: 'Home' }" + [secondNavigationLabel]="{ label: 'On-Boarding Model', disabled: true }" + (firstNavigationClicked)="onHomeClick()" + ></gp-breadcrumb-navigation> +</div> +<mat-divider></mat-divider> +<div style="display: flex; flex-direction: column; margin: 40px; width: 100%"> + <div></div> + <mat-divider></mat-divider> + <div style="display: flex; flex-direction: column; width: 100%"> + <mat-divider></mat-divider> + <!-- on boarding--> + <div> + <gp-headline + [headlineTitle]="'ON-BOARD DOCKERIZED MODEL URI'" + ></gp-headline> + </div> + <!--process model--> + <div> + @if (solutionTrackId) { + <mat-list role="list" style="display: flex"> + <mat-list-item role="listitem" + ><div style="display: flex; flex-direction: column"> + <span + class="image-content micro-service-process-completed" + alt="" + title="" + ></span> + + <span>Create solution</span> + </div></mat-list-item + > + <mat-list-item + ><span class="progress-status progress-status-completed"></span + ></mat-list-item> + <mat-list-item role="listitem" + ><div style="display: flex; flex-direction: column"> + <span + class="image-content add-repository-completed" + alt="Add Artifacts" + title="Add Artifacts" + ></span> + <span>Add Artifacts </span> + </div></mat-list-item + > + <mat-list-item + ><span class="progress-status progress-status-completed"></span + ></mat-list-item> + <mat-list-item role="listitem" + ><div style="display: flex; flex-direction: column"> + <span + class="image-content onboarded-completed" + alt="Onboarding status" + title="Onboarding status" + ></span> + <button>View model</button> + <span>Model is on-boarded and available in Private catalog </span> + </div></mat-list-item + > + </mat-list> + } @else { + <mat-list role="list" style="display: flex"> + <mat-list-item role="listitem" + ><div style="display: flex; flex-direction: column"> + <span class="image-content micro-service" alt="" title=""></span> + + <span>Create solution</span> + </div></mat-list-item + > + <mat-list-item + ><span class="progress-status process-status-not-yet-started"></span + ></mat-list-item> + <mat-list-item role="listitem" + ><div style="display: flex; flex-direction: column"> + <span + class="image-content add-repository" + alt="Add Artifacts" + title="Add Artifacts" + ></span> + <span>Add Artifacts </span> + </div></mat-list-item + > + <mat-list-item + ><span class="progress-status process-status-not-yet-started"></span + ></mat-list-item> + <mat-list-item role="listitem" + ><div style="display: flex; flex-direction: column"> + <span + class="image-content not-yet-onboarded" + alt="Not yet on-boarded" + title="Not yet on-boarded" + ></span> + <span>Not yet on-boarded </span> + </div></mat-list-item + > + </mat-list> + } + </div> + <div style="display: flex"> + <div style="display: flex; flex-direction: column; width: 100%"> + <!-- onboarding model form--> + <form style="width: 100" [formGroup]="onboardingModelForm"> + <!--model name--> + <div style="display: flex; flex-direction: column"> + <mat-label>Model name</mat-label> + <mat-form-field> + <input matInput formControlName="name" /> + @if ( + onboardingModelForm.controls["name"].errors?.["pattern"] && + onboardingModelForm.controls["name"].touched + ) { + <mat-error class="modal-error" + >Name must consist of lower case alphanumeric characters, '-' + or '.', and must start and end with an alphanumeric + character</mat-error + > + } + @if ( + onboardingModelForm.controls["name"].errors?.["required"] && + onboardingModelForm.controls["name"].touched + ) { + <mat-error class="modal-error">Name is required</mat-error> + } + </mat-form-field> + </div> + <!--docker URI--> + <div style="display: flex; flex-direction: column"> + <mat-label>Docker URI </mat-label> + <mat-hint class="modal-note green" + ><strong>Dockerhub image example:</strong> + docker.io/myimage:latest + </mat-hint> + <mat-hint class="modal-note green" + ><strong>General public registry image example:</strong> + cicd.ai4eu-dev.eu:7444/myimage:v1 + </mat-hint> + <mat-form-field> + <input matInput formControlName="dockerURI" /> + @if ( + onboardingModelForm.controls["dockerURI"].errors?.[ + "required" + ] && onboardingModelForm.controls["dockerURI"].touched + ) { + <mat-error class="modal-error" + >Docker URI is required</mat-error + > + } + </mat-form-field> + </div> + <!--protobuf file--> + <div style="display: flex; flex-direction: column; width: 100%"> + <mat-label>Upload Protobuf File </mat-label> + <div style="display: flex; width: 100%; gap: 10px"> + <mat-form-field style="height: 70px"> + <input matInput [value]="fileName" /> + <mat-hint class="modal-note full-width no-padding"> + Supported files type: .proto</mat-hint + > + + <input + #fileDropRef + type="file" + id="fileInput" + name="fileInput" + (change)="selectFile($event)" + hidden + formControlName="protobufFile" + /> + </mat-form-field> + + <button + style="height: 48px" + color="primary" + mat-raised-button + (click)="uploadFile()" + > + Upload file + </button> + </div> + @if (message !== "") { + <span class="modal-error">.proto file is required.</span> + } + <!-- @if ( + onboardingModelForm.controls["protobufFile"].errors?.[ + "required" + ] && onboardingModelForm.controls["protobufFile"].touched + ) { + <span class="modal-error">.proto file is required.</span> + } --> + </div> + <!--license profile--> + <div style="display: flex; flex-direction: column"> + <mat-checkbox + color="primary" + formControlName="addLicenseProfile" + (change)="onClickUpload($event)" + >Add License Profile</mat-checkbox + > + + <!-- <mat-radio-group color="primary"> + <mat-radio-button value="auto" (click)="onCreateLicenseProfile()" + >Create license profile</mat-radio-button + > + <mat-radio-button + value="always" + (click)="onClickUploadLicenseProfile()" + >Upload license profile</mat-radio-button + > + </mat-radio-group> --> + </div> + @if ( + onboardingModelForm.controls["addLicenseProfile"].value === true + ) { + <gp-model-details-license-profile></gp-model-details-license-profile> + } + + <div style="display: flex"> + <button mat-raised-button (click)="resetData()">Reset form</button> + <button + mat-raised-button + color="primary" + [disabled]="!enableSubmit" + > + On-board model + </button> + </div> + </form> + </div> + <!--onboarding history--> + <div></div> + </div> + </div> +</div> diff --git a/src/app/features/dashboard/on-boarding-model/on-boarding-model.component.scss b/src/app/features/dashboard/on-boarding-model/on-boarding-model.component.scss index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..36effac1c75b2568e40eb2fe13a01a6a7e4b496f 100644 --- a/src/app/features/dashboard/on-boarding-model/on-boarding-model.component.scss +++ b/src/app/features/dashboard/on-boarding-model/on-boarding-model.component.scss @@ -0,0 +1,121 @@ +.flex-column { + display: flex; + flex-direction: column; +} +#fileInput { + position: absolute; + cursor: pointer; + z-index: 10; + opacity: 0; + height: 100%; + left: 0px; + top: 0px; +} +.asterisk--after:after { + content: "*"; + color: red; +} + +.modal-error { + color: red; + font-size: 12px; + font-family: "Open Sans", sans-serif !important; + padding: 0; +} + +.modal-note { + color: #888; + font-size: 12px; + font-family: "Open Sans", sans-serif !important; +} + +.full-width { + width: 100%; +} + +.green { + color: green; +} +::ng-deep.mat-mdc-form-field-hint-wrapper, +::ng-deep.mat-mdc-form-field-error-wrapper { + padding: 0 !important; +} +.micro-service { + background-image: url(../../../../assets/images/ico_create_micro_service.png); + background-repeat: no-repeat; + background-position: center; +} + +.micro-service-process-completed { + background-image: url(../../../../assets/images/ico_create_micro_service_green.png); + background-repeat: no-repeat; + background-position: center; +} + +/* .progress-status:after { + content: "" !important; + background: url("../../../../assets/images/loading_deactive.png") no-repeat + left center; + display: inline-block; + width: 45px; + height: 12px; + transform: scale(0.8); +} + */ +.process-status-not-yet-started { + background: url("../../../../assets/images/loading_deactive.png") no-repeat + left center; +} + +.progress-status-completed { + background: url("../../../../assets/images/stepper_progress_completed.png") + no-repeat left center; +} + +.progress-status { + display: inline-block; + width: 47px; + height: 11px; + transform: scale(0.8); +} + +.add-repository { + background-image: url(../../../../assets/images/ico_add_to_repository.png); + background-repeat: no-repeat; + background-position: center; +} + +.add-repository-completed { + background-image: url(../../../../assets/images/ico_add_to_repository_green.png); + background-repeat: no-repeat; + background-position: center; +} + +.not-yet-onboarded { + background-image: url(../../../../assets/images/ico_not_yet_onboarded.png); + background-repeat: no-repeat; + background-position: center; +} + +.onboarded-completed { + background-image: url(../../../../assets/images/ico-checkmark.png); + background-repeat: no-repeat; + background-position: center; +} + +.image-content { + width: 62px; + height: 62px; + border-radius: 62px; + + border: 3px solid #fff; + background-color: #ebebeb; + display: inline-block; + position: relative; + text-align: center; + line-height: 68px; +} + +.mdc-list-item.mdc-list-item--with-one-line { + height: 90px; +} diff --git a/src/app/features/dashboard/on-boarding-model/on-boarding-model.component.ts b/src/app/features/dashboard/on-boarding-model/on-boarding-model.component.ts index 26137a8aa3c1ca2c6d75f22cd6a08a1c985b8f48..69ca6e269e6fca4ed430578fd92c871934af6500 100644 --- a/src/app/features/dashboard/on-boarding-model/on-boarding-model.component.ts +++ b/src/app/features/dashboard/on-boarding-model/on-boarding-model.component.ts @@ -1,13 +1,262 @@ -import { Component } from '@angular/core'; +import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { HeadlineComponent } from 'src/app/shared/components/headline/headline.component'; +import { BreadcrumbNavigationComponent } from 'src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component'; +import { MatDividerModule } from '@angular/material/divider'; +import { + FormBuilder, + FormGroup, + ReactiveFormsModule, + Validators, +} from '@angular/forms'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { + MatCheckboxChange, + MatCheckboxModule, +} from '@angular/material/checkbox'; +import { MatButtonModule } from '@angular/material/button'; +import { UploadLicenseProfileComponent } from 'src/app/shared/components/upload-license-profile/upload-license-profile.component'; +import { MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { CreateEditLicenseProfileComponent } from 'src/app/shared/components/create-edit-license-profile/create-edit-license-profile.component'; +import { MatRadioModule } from '@angular/material/radio'; +import { ModelDetailsLicenseProfileComponent } from 'src/app/shared/components/model-details-license-profile/model-details-license-profile.component'; +import { SharedDataService } from 'src/app/core/services/shared-data/shared-data.service'; +import { Alert, AlertType, LicenseProfileModel } from 'src/app/shared/models'; +import { HttpEventType } from '@angular/common/http'; +import { AlertService } from 'src/app/core/services/alert.service'; +import { PrivateCatalogsService } from 'src/app/core/services/private-catalogs.service'; +import { BrowserStorageService } from 'src/app/core/services/storage/browser-storage.service'; +import { Observable, Subject, Subscription, map, takeUntil } from 'rxjs'; +import { MatListModule } from '@angular/material/list'; @Component({ selector: 'gp-on-boarding-model', standalone: true, - imports: [CommonModule], + imports: [ + CommonModule, + HeadlineComponent, + BreadcrumbNavigationComponent, + MatDividerModule, + ReactiveFormsModule, + MatFormFieldModule, + MatInputModule, + MatCheckboxModule, + MatButtonModule, + UploadLicenseProfileComponent, + MatRadioModule, + ModelDetailsLicenseProfileComponent, + MatListModule, + ], templateUrl: './on-boarding-model.component.html', - styleUrl: './on-boarding-model.component.scss' + styleUrl: './on-boarding-model.component.scss', }) -export class OnBoardingModelComponent { +export class OnBoardingModelComponent implements OnInit { + @ViewChild('fileDropRef') fileDropRef!: ElementRef<HTMLInputElement>; + currentFile?: File; + fileSize = 0; + message = ''; + fileName = 'No chosen file'; + onboardingModelForm!: FormGroup; + modelUploadError: boolean = false; + modelUploadErrorMsg: string[] = []; + userId$: Observable<string | undefined>; + solutionTrackId!: string; + enableSubmit: boolean = false; + private onDestroy = new Subject<void>(); + private subscription: Subscription = new Subscription(); + modelLicense: LicenseProfileModel | null = null; + constructor( + private formBuilder: FormBuilder, + private sharedDataService: SharedDataService, + public dialog: MatDialog, + private alertService: AlertService, + private privateCatalogsService: PrivateCatalogsService, + private browserStorageService: BrowserStorageService, + ) { + this.onboardingModelForm = this.formBuilder.group({ + name: [ + '', + [ + Validators.required, + Validators.pattern('^(?=.*[a-z])[A-Za-z0-9]+[-.][A-Za-z0-9]+$'), + // this.notSameAsPublisher(this.publisherName), + ], + // [], + ], + dockerURI: ['', [Validators.required]], + protobufFile: [null, [Validators.required]], + addLicenseProfile: [false], + licenseProfile: [null], + }); + + this.userId$ = this.browserStorageService + .getUserDetails() + .pipe(map((details) => details?.userId)); + } + ngOnInit(): void { + this.subscription.add( + this.sharedDataService.licenseProfile$.subscribe((licenseProfile) => { + this.modelLicense = licenseProfile; + this.onboardingModelForm.patchValue({ + licenseProfile: licenseProfile, + }); + /** + * this.cd.detectChanges(); // Manually trigger change detection + */ + if (licenseProfile) { + console.log('License profile updated:', licenseProfile); + } else { + console.log('License profile reset to null'); + } + }), + ); + + this.onboardingModelForm.valueChanges + .pipe(takeUntil(this.onDestroy)) + .subscribe(() => { + this.checkFormValidity(); + }); + } + + checkFormValidity() { + const { name, dockerURI, addLicenseProfile, protobufFile } = + this.onboardingModelForm.value; + console.log({ protobufFile }); + if (!addLicenseProfile) { + console.log('currentFile', this.currentFile); + this.enableSubmit = name && dockerURI && protobufFile; + } else { + this.enableSubmit = + name && dockerURI && this.currentFile && this.modelLicense; + } + } + + onHomeClick() {} + + ngOnDestroy() { + this.onDestroy.next(); + this.onDestroy.complete(); + } + + selectFile(event: any): void { + this.message = ''; + + if (event.target.files && event.target.files[0]) { + const file: File = event.target.files[0]; + this.currentFile = file; + this.fileName = this.currentFile.name; + this.onboardingModelForm.patchValue({ protobufFile: file }); + console.log('file info', this.currentFile); + const extensionFile = this.getFilenameExtension(this.fileName); + if (extensionFile !== 'proto') { + this.message = '.proto file is required.'; + } else if (this.currentFile && extensionFile === 'proto') { + console.log('inside proto'); + this.privateCatalogsService + .uploadProtoBufFile(this.currentFile) + .subscribe({ + next: (event) => this.processEvent(event), + error: (error) => {}, // To catch any errors not caught by catchError + complete: () => {}, + }); + } + } else { + this.fileName = 'No chosen file'; + } + } + /* + handleFileInput(event: Event | File) { + let file: File | null = null; + if (event instanceof File) { + file = event; + } else { + const element = event.target as HTMLInputElement; + file = element.files?.[0] || null; + } + if (file) { + this.currentFile = file; + if (this.currentFile.size / 1024 / 1024 < 1) { + this.fileSize = Math.ceil(file.size / 1024); + } + } + } */ + + uploadFile() { + event?.preventDefault(); + this.fileDropRef.nativeElement.click(); + if (this.currentFile) { + console.log('current file', this.currentFile); + this.privateCatalogsService + .uploadProtoBufFile(this.currentFile) + .subscribe({ + next: (event) => this.processEvent(event), + error: (error) => {}, // To catch any errors not caught by catchError + complete: () => {}, + }); + } + } + + getFilenameExtension(filename: string): string { + // Split the filename by dot (.) and get the last element of the array + const parts = filename.split('.'); + return parts[parts.length - 1]; + } + + onClickUpload(event: MatCheckboxChange) {} + + onCreateLicenseProfile() { + const dialogRef: MatDialogRef<CreateEditLicenseProfileComponent> = + this.dialog.open(CreateEditLicenseProfileComponent, { + data: { + dataKey: { + isEditMode: false, + solutionId: '', + revisionId: '', + }, + }, + }); + dialogRef.afterClosed().subscribe((result) => { + // This will be executed when the dialog is closed + // Reload data to fetch the updated license profile + }); + } + + onClickUploadLicenseProfile() { + const dialogRef: MatDialogRef<UploadLicenseProfileComponent> = + this.dialog.open(UploadLicenseProfileComponent); + } + + resetData() { + this.onboardingModelForm.reset(); + this.sharedDataService.licenseProfile = null; + } + + processEvent(event: any): void { + if (event && event.type === HttpEventType.Response) { + this.handleUploadSuccess(event.body); + } + } + + private handleUploadSuccess(response: any) { + const alert: Alert = { + message: 'File uploaded successfully', + type: AlertType.Success, + }; + this.alertService.notify(alert, 5000); + } + + private handleUploadError(error: any) { + // Error handling logic here + this.modelUploadError = true; + if (error) { + this.modelUploadErrorMsg = [error]; + } else if (error.error) { + const messageError = error.error.response_detail ?? error.error; + this.modelUploadErrorMsg = [messageError]; + } + + // Additional error handling + } } diff --git a/src/app/features/login/local-login/local-login.component.ts b/src/app/features/login/local-login/local-login.component.ts index 45e4c6b433747b40e3782da8adff0d8f230b5dba..866f1d410f50bae176860c2d541c98eca2229d6c 100644 --- a/src/app/features/login/local-login/local-login.component.ts +++ b/src/app/features/login/local-login/local-login.component.ts @@ -19,7 +19,7 @@ import { import { AuthService } from 'src/app/core/services/auth/auth.service'; import { LocalLoginService } from 'src/app/core/services/auth/local-login.service'; -import { NavigationStart, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { diff --git a/src/app/features/marketplace/marketplace.component.html b/src/app/features/marketplace/marketplace.component.html index b40fe121e3c128c55d03afa30ad23049dd359e2a..c6b476cda8fc74766c1c462064c37dc9517b9fcf 100644 --- a/src/app/features/marketplace/marketplace.component.html +++ b/src/app/features/marketplace/marketplace.component.html @@ -1,9 +1,7 @@ <section class="pageheadsection mob-pageheadsection1"> <div class="mdl-grid mdl-grid.mdl-grid--no-spacing"> <div> - <div class="headline"> - <span>Marketplace | </span> - </div> + <gp-headline [headlineTitle]="'Marketplace |'"></gp-headline> <div style="display: flex; flex-direction: row; align-items: center" *ngIf="loginUserId" diff --git a/src/app/features/marketplace/marketplace.component.ts b/src/app/features/marketplace/marketplace.component.ts index 069ef68c804a05a52bbb2a7e33681d0d0a4171ea..da672de7f55a0c19652a8f1f913e46e73a81a591 100644 --- a/src/app/features/marketplace/marketplace.component.ts +++ b/src/app/features/marketplace/marketplace.component.ts @@ -34,6 +34,7 @@ import { BrowserStorageService } from 'src/app/core/services/storage/browser-sto import { Observable, Subscription, map } from 'rxjs'; import { PrivateCatalogsService } from 'src/app/core/services/private-catalogs.service'; import { MatButtonModule } from '@angular/material/button'; +import { HeadlineComponent } from 'src/app/shared/components/headline/headline.component'; @Component({ selector: 'gp-marketplace', @@ -50,6 +51,7 @@ import { MatButtonModule } from '@angular/material/button'; SolutionsToggleViewComponent, ListItemComponent, MatButtonModule, + HeadlineComponent, ], templateUrl: './marketplace.component.html', styleUrl: './marketplace.component.scss', diff --git a/src/app/features/model-details/model-details.component.html b/src/app/features/model-details/model-details.component.html index 4b6be61e308c35ae80e4f057cdd114ea6932a80a..92898d7172751a53f159b69a73e77368d315fb67 100644 --- a/src/app/features/model-details/model-details.component.html +++ b/src/app/features/model-details/model-details.component.html @@ -89,8 +89,8 @@ <div class="md-head-container2" style="margin-top: 12px"> <gp-breadcrumb-navigation [solution]="data.solution" - [firstNavigationLabel]="'Home'" - [secondNavigationLabel]="'MarketPlace'" + [firstNavigationLabel]="{ label: 'Home' }" + [secondNavigationLabel]="{ label: 'MarketPlace' }" (firstNavigationClicked)="onHomeClick()" (secondNavigationClicked)="onMarketPlaceClick()" ></gp-breadcrumb-navigation> diff --git a/src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component.html b/src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component.html index f6cb9cd59a826250aa1d1c222608de8c06145847..ee84a488b625a7d2230d7ad29e76dff79c63b456 100644 --- a/src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component.html +++ b/src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component.html @@ -1,18 +1,26 @@ <ul class="c-breadcrumb"> - <li> - <a (click)="onFirstNavigationLabelClick()">{{ firstNavigationLabel }}</a> - </li> - <li> - <a (click)="onSecondNavigationClick()">{{ secondNavigationLabel }}</a> - </li> - <li> - <span - class="md-breadcrumb-item" - matTooltip="{{ solution?.name?.toString()?.split('_')?.join(' ') }}" - >{{ solution?.name?.toString()?.split("_")?.join(" ") }}</span - > - </li> - <li> - <gp-solution-id [solutionId]="solution.solutionId"></gp-solution-id> + <li [ariaDisabled]="firstNavigationLabel.disabled"> + <a (click)="onFirstNavigationLabelClick()">{{ + firstNavigationLabel.label + }}</a> </li> + @if (secondNavigationLabel) { + <li [ariaDisabled]="secondNavigationLabel.disabled"> + <a (click)="onSecondNavigationClick()">{{ + secondNavigationLabel.label + }}</a> + </li> + } + @if (solution) { + <li> + <span + class="md-breadcrumb-item" + matTooltip="{{ solution?.name?.toString()?.split('_')?.join(' ') }}" + >{{ solution?.name?.toString()?.split("_")?.join(" ") }}</span + > + </li> + <li> + <gp-solution-id [solutionId]="solution.solutionId"></gp-solution-id> + </li> + } </ul> diff --git a/src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component.scss b/src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component.scss index 6124c0035ec62241ee2976ed94667994c4863f0f..bbae9c7c9fec83107d31126cfcadfbbcd40efcbe 100644 --- a/src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component.scss +++ b/src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component.scss @@ -54,3 +54,7 @@ display: inline-block; padding: 0 5px; } + +[aria-disabled="true"] { + pointer-events: none; +} diff --git a/src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component.ts b/src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component.ts index 2fbc2dbb8e1b5ccb78d7d8e1d261ab48309da9c3..be996a5db782028cc018878910671f4e062f412f 100644 --- a/src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component.ts +++ b/src/app/shared/components/breadcrumb-navigation/breadcrumb-navigation.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SolutionIdComponent } from '../solution-id/solution-id.component'; -import { PublicSolutionDetailsModel } from '../../models'; +import { NavigationLabelModel, PublicSolutionDetailsModel } from '../../models'; import { MatTooltipModule } from '@angular/material/tooltip'; @Component({ @@ -12,8 +12,8 @@ import { MatTooltipModule } from '@angular/material/tooltip'; styleUrl: './breadcrumb-navigation.component.scss', }) export class BreadcrumbNavigationComponent { - @Input() firstNavigationLabel!: string; - @Input() secondNavigationLabel!: string; + @Input() firstNavigationLabel!: NavigationLabelModel; + @Input() secondNavigationLabel!: NavigationLabelModel; @Input() solution!: PublicSolutionDetailsModel; @Output() firstNavigationClicked = new EventEmitter<void>(); diff --git a/src/app/shared/components/create-edit-license-profile/create-edit-license-profile.component.ts b/src/app/shared/components/create-edit-license-profile/create-edit-license-profile.component.ts index 9dc835d3b49e08b6c5fad43f4af96acc063c804c..6328626a39d43480257c442091503b6e1ab3d55a 100644 --- a/src/app/shared/components/create-edit-license-profile/create-edit-license-profile.component.ts +++ b/src/app/shared/components/create-edit-license-profile/create-edit-license-profile.component.ts @@ -117,6 +117,7 @@ export class CreateEditLicenseProfileComponent implements OnInit { this.isEditMode = this.data.dataKey.isEditMode; this.solutionId = this.data.dataKey.solutionId; this.revisionId = this.data.dataKey.revisionId; + this.initializeForm(); this.setupFormValueChangesSubscription(); if (this.modelLicense) this.updateFormValues(); @@ -235,6 +236,7 @@ export class CreateEditLicenseProfileComponent implements OnInit { next: (event) => { if (event.type === HttpEventType.Response) { this.handleUploadSuccess(event.body); + this.sharedDataService.licenseProfile = licenseProfile; this.dialogRef.close(); } }, diff --git a/src/app/shared/components/delete-user-dialog-confirmation-action/delete-user-dialog-confirmation-action.component.ts b/src/app/shared/components/delete-user-dialog-confirmation-action/delete-user-dialog-confirmation-action.component.ts index fbfaa3af718d861ffb25f27fb703fa7dcbcc482a..ac06ec9215a3af145450563bb706266a5c93f985 100644 --- a/src/app/shared/components/delete-user-dialog-confirmation-action/delete-user-dialog-confirmation-action.component.ts +++ b/src/app/shared/components/delete-user-dialog-confirmation-action/delete-user-dialog-confirmation-action.component.ts @@ -8,9 +8,7 @@ import { import { MatButtonModule } from '@angular/material/button'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatIconModule } from '@angular/material/icon'; -import { PrivateCatalogsService } from 'src/app/core/services/private-catalogs.service'; -import { SharedDataService } from 'src/app/core/services/shared-data/shared-data.service'; -import { Alert, AlertType, UserDetails } from '../../models'; +import { AlertType } from '../../models'; import { AlertService } from 'src/app/core/services/alert.service'; @Component({ diff --git a/src/app/shared/components/headline/headline.component.html b/src/app/shared/components/headline/headline.component.html new file mode 100644 index 0000000000000000000000000000000000000000..1448e86874a2f1d8ba3b085e4ff7d7f7325f74fb --- /dev/null +++ b/src/app/shared/components/headline/headline.component.html @@ -0,0 +1,3 @@ +<div class="headline"> + <span>{{ headlineTitle }} </span> +</div> diff --git a/src/app/shared/components/headline/headline.component.scss b/src/app/shared/components/headline/headline.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..f370b200175baa2dd9f174a7c59dfc885860788f --- /dev/null +++ b/src/app/shared/components/headline/headline.component.scss @@ -0,0 +1,14 @@ +.headline { + font-size: 20px; + height: 30px; + font-weight: 600; + line-height: 24px; + letter-spacing: 0.02em; + margin: 3px 0; + padding: 0; + color: #671c9d; + text-overflow: ellipsis; + float: left; + overflow: hidden; + white-space: nowrap; +} diff --git a/src/app/shared/components/headline/headline.component.spec.ts b/src/app/shared/components/headline/headline.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3fa01aa628042a4429fcf0c654fdb3ceff8dd93 --- /dev/null +++ b/src/app/shared/components/headline/headline.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeadlineComponent } from './headline.component'; + +describe('HeadlineComponent', () => { + let component: HeadlineComponent; + let fixture: ComponentFixture<HeadlineComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [HeadlineComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(HeadlineComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/headline/headline.component.ts b/src/app/shared/components/headline/headline.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..4979684f69eeb5726fc1a13186f673d74a638bc6 --- /dev/null +++ b/src/app/shared/components/headline/headline.component.ts @@ -0,0 +1,13 @@ +import { Component, Input } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'gp-headline', + standalone: true, + imports: [CommonModule], + templateUrl: './headline.component.html', + styleUrl: './headline.component.scss', +}) +export class HeadlineComponent { + @Input() headlineTitle!: string; +} diff --git a/src/app/shared/components/home/home.component.html b/src/app/shared/components/home/home.component.html index 68855e5ba232bdbc7e8a7323906c895b9b35bc12..00ac690862ea3ca1171defdb8e861b3c61fe3489 100644 --- a/src/app/shared/components/home/home.component.html +++ b/src/app/shared/components/home/home.component.html @@ -15,7 +15,6 @@ > Marketplace </button> - <button mat-button (click)="onClickUpload()">Onboard Model</button> </div> </div> </div> diff --git a/src/app/shared/components/home/home.component.ts b/src/app/shared/components/home/home.component.ts index ef2cba0c75ace8116f2155924939562326d3d7fd..6129ac5664cc388cec37e9655d860439f3602cd9 100644 --- a/src/app/shared/components/home/home.component.ts +++ b/src/app/shared/components/home/home.component.ts @@ -35,7 +35,6 @@ export class HomeComponent { constructor( private publicSolutionsService: PublicSolutionsService, private router: Router, - public dialog: MatDialog, private browserStorageService: BrowserStorageService, ) { this.userId$ = this.browserStorageService @@ -77,11 +76,4 @@ export class HomeComponent { }), ); } - - onClickUpload() { - if (this.userId$) { - const dialogRef: MatDialogRef<UploadLicenseProfileComponent> = - this.dialog.open(UploadLicenseProfileComponent); - } - } } diff --git a/src/app/shared/components/model-details-license-profile/model-details-license-profile.component.html b/src/app/shared/components/model-details-license-profile/model-details-license-profile.component.html index 15b3f0cf48508f107b6018364c85af4aa0eef782..8bb11d0304b87440a993ec5f8d493311051ceed5 100644 --- a/src/app/shared/components/model-details-license-profile/model-details-license-profile.component.html +++ b/src/app/shared/components/model-details-license-profile/model-details-license-profile.component.html @@ -35,7 +35,9 @@ <div style="margin-left: 20px" *ngIf="!modelLicense"> {{ modelLicenseError }} </div> -<div style="margin-left: 20px"> +<!--<div *ngIf="(sharedDataService.licenseProfile$ | async) as modelLicense; else noLicenseTemplate"> +--> +<div style="margin-left: 20px" *ngIf="modelLicense; else noLicenseTemplate"> <pre class="licensedisplay"> <span *ngIf="modelLicense?.keyword"><strong>keyword: </strong></span>{{ modelLicense?.keyword }} <span *ngIf="modelLicense?.licenseName"><strong>licenseName: </strong></span>{{ modelLicense?.licenseName }} @@ -53,3 +55,6 @@ <span *ngIf="modelLicense?.additionalInfo"><strong>additionalInfo: </strong></span>{{ modelLicense?.additionalInfo }} </pre> </div> +<ng-template #noLicenseTemplate> + <p>No license found.</p> +</ng-template> diff --git a/src/app/shared/components/model-details-license-profile/model-details-license-profile.component.ts b/src/app/shared/components/model-details-license-profile/model-details-license-profile.component.ts index 138f5ed19a4a05db844c8b1b4433ca7601fecf54..fefd446df9f73ed175a9e804dfb04823070b1522 100644 --- a/src/app/shared/components/model-details-license-profile/model-details-license-profile.component.ts +++ b/src/app/shared/components/model-details-license-profile/model-details-license-profile.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { ChangeDetectorRef, Component, Input } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedDataService } from 'src/app/core/services/shared-data/shared-data.service'; import { PublicSolutionsService } from 'src/app/core/services/public-solutions.service'; @@ -19,7 +19,7 @@ import { LicenseProfileModel } from '../../models'; styleUrl: './model-details-license-profile.component.scss', }) export class ModelDetailsLicenseProfileComponent { - modelLicense!: LicenseProfileModel; + modelLicense: LicenseProfileModel | null = null; isLicenseFound = false; isLoadingLicense = true; isLicenseJson = false; @@ -29,13 +29,15 @@ export class ModelDetailsLicenseProfileComponent { versionId: string = ''; versionIdSubscription: Subscription | undefined; isUserIdAvailable$: Observable<boolean | undefined>; + private subscription: Subscription = new Subscription(); constructor( private activatedRoute: ActivatedRoute, private publicSolutionsService: PublicSolutionsService, - private sharedDataService: SharedDataService, + protected sharedDataService: SharedDataService, public dialog: MatDialog, private browserStorageService: BrowserStorageService, + private cd: ChangeDetectorRef, ) { this.isUserIdAvailable$ = this.browserStorageService .getUserDetails() @@ -43,6 +45,19 @@ export class ModelDetailsLicenseProfileComponent { } ngOnInit() { + this.subscription.add( + this.sharedDataService.licenseProfile$.subscribe((profile) => { + this.modelLicense = profile; + /** + * this.cd.detectChanges(); // Manually trigger change detection + */ + if (profile) { + console.log('License profile updated:', profile); + } else { + console.log('License profile reset to null'); + } + }), + ); this.activatedRoute.parent?.paramMap.subscribe((paramMap) => { this.solutionId = paramMap.get('solutionId') || ''; this.revisionId = paramMap.get('revisionId') || ''; diff --git a/src/app/shared/components/model-management/model-management.component.html b/src/app/shared/components/model-management/model-management.component.html index caf10af8337522c9f74806f8f3ad752348380a71..5d8139d8a3e741bedba0bb317ca403a3193ba75f 100644 --- a/src/app/shared/components/model-management/model-management.component.html +++ b/src/app/shared/components/model-management/model-management.component.html @@ -74,8 +74,8 @@ <div> <gp-breadcrumb-navigation [solution]="data" - [firstNavigationLabel]="'Home'" - [secondNavigationLabel]="'Manage my model'" + [firstNavigationLabel]="{ label: 'Home' }" + [secondNavigationLabel]="{ label: 'Manage my model' }" (firstNavigationClicked)="onHomeClick()" (secondNavigationClicked)="onManageMyModelClick()" ></gp-breadcrumb-navigation> diff --git a/src/app/shared/components/upload-license-profile/upload-license-profile.component.html b/src/app/shared/components/upload-license-profile/upload-license-profile.component.html index 9935a52a7ebb9fd6c87c498cd1e4068a51969096..8161fa963b5e1842bfbaeb8b438d54d5f08f929c 100644 --- a/src/app/shared/components/upload-license-profile/upload-license-profile.component.html +++ b/src/app/shared/components/upload-license-profile/upload-license-profile.component.html @@ -57,12 +57,6 @@ mode="determinate" [value]="progressBarValue" ></mat-progress-bar> - <!-- <div class="pro-status" *ngIf="progressBarValue > 0"> - <span *ngIf="progressBarValue != 100 && progressBarValue != 0" - >Uploading</span - > - <span *ngIf="progressBarValue === 100">Done</span> - </div>--> </div> <div style=" diff --git a/src/app/shared/components/upload-license-profile/upload-license-profile.component.ts b/src/app/shared/components/upload-license-profile/upload-license-profile.component.ts index a8739d76110d0f0ccb93d74ca8aa558bc1227552..079e1d0c210e92d4e5ffb462a2ce9454999f0316 100644 --- a/src/app/shared/components/upload-license-profile/upload-license-profile.component.ts +++ b/src/app/shared/components/upload-license-profile/upload-license-profile.component.ts @@ -2,6 +2,7 @@ import { Component, ElementRef, Inject, + Input, OnDestroy, OnInit, ViewChild, @@ -29,6 +30,7 @@ import { of, switchMap, takeUntil, + tap, throwError, } from 'rxjs'; import { BrowserStorageService } from 'src/app/core/services/storage/browser-storage.service'; @@ -56,8 +58,8 @@ export class UploadLicenseProfileComponent implements OnInit, OnDestroy { filename: string | null = null; progressBar = 0; modelUploadError: boolean = false; - solutionId: string = ''; - revisionId: string = ''; + @Input() solutionId: string = ''; + @Input() revisionId: string = ''; versionId: string = ''; versionIdSubscription: Subscription | undefined; modelLicense!: LicenseProfileModel; @@ -67,6 +69,7 @@ export class UploadLicenseProfileComponent implements OnInit, OnDestroy { modelUploadErrorMsg: string[] = []; fileSize = 0; userId$: Observable<string | undefined>; + licenseProfile!: LicenseProfileModel; private onDestroy = new Subject<void>(); constructor( @@ -107,18 +110,36 @@ export class UploadLicenseProfileComponent implements OnInit, OnDestroy { } uploadLicenseFile(): void { + event?.preventDefault(); combineLatest([this.userId$, of(this.file)]) .pipe( filter(([userId, file]) => !!userId && !!file), switchMap(([userId, file]) => { - if (userId && file) { - return this.privateCatalogsService.uploadFileToUrl( + if ( + userId && + file && + this.versionId && + this.solutionId && + this.versionId + ) { + return this.privateCatalogsService.uploadExistingModelLicenseProfile( userId, this.solutionId, this.revisionId, this.versionId, file, ); + } else if ( + userId && + file && + !this.versionId && + !this.solutionId && + !this.versionId + ) { + return this.privateCatalogsService.uploadNewModelLicenseProfile( + userId, + file, + ); } else { return throwError(() => new Error('Missing user ID or file')); } @@ -126,26 +147,28 @@ export class UploadLicenseProfileComponent implements OnInit, OnDestroy { takeUntil(this.onDestroy), catchError((error) => { console.error('Upload failed', error); + this.handleUploadError(error.error); // Handle the error and continue return of(null); }), finalize(() => this.resetProgress()), ) - .subscribe((event) => { - if ( - event && - event.type === HttpEventType.UploadProgress && - event.total - ) { - this.progressBarValue = Math.round( - (100 * event.loaded) / event.total, - ); - } else if (event && event.type === HttpEventType.Response) { - this.handleUploadSuccess(event.body); - } + .subscribe({ + next: (event) => this.processEvent(event), + error: (error) => {}, // To catch any errors not caught by catchError + complete: () => {}, }); } + processEvent(event: any): void { + if (event && event.type === HttpEventType.UploadProgress && event.total) { + this.progressBarValue = Math.round((100 * event.loaded) / event.total); + } else if (event && event.type === HttpEventType.Response) { + this.handleUploadSuccess(event.body); + this.sharedDataService.licenseProfile = this.licenseProfile; + } + } + private handleUploadSuccess(response: any) { const alert: Alert = { message: 'License uploaded successfully', @@ -157,10 +180,13 @@ export class UploadLicenseProfileComponent implements OnInit, OnDestroy { private handleUploadError(error: any) { // Error handling logic here this.modelUploadError = true; - const messageError = error.error.response_detail - ? error.error.response_detail - : error.error; - this.modelUploadErrorMsg = [messageError]; + if (error) { + this.modelUploadErrorMsg = [error]; + } else if (error.error) { + const messageError = error.error.response_detail ?? error.error; + this.modelUploadErrorMsg = [messageError]; + } + // Additional error handling } @@ -174,7 +200,26 @@ export class UploadLicenseProfileComponent implements OnInit, OnDestroy { this.filename = file.name; } - handleFileInput(event: Event | File) { + readFile(file: File) { + const reader = new FileReader(); + reader.onload = () => { + try { + this.licenseProfile = JSON.parse(reader.result as string); + console.log('License Profile Loaded:', this.licenseProfile); + // Proceed with any operations now that the license profile is loaded + } catch (e) { + console.error('Error parsing the license profile:', e); + // Handle errors in reading or parsing the file + } + }; + reader.onerror = () => { + console.error('Error reading the file:', reader.error); + }; + reader.readAsText(file); + } + + handleFileInput(event: any) { + event.preventDefault(); let file: File | null = null; if (event instanceof File) { file = event; @@ -184,6 +229,7 @@ export class UploadLicenseProfileComponent implements OnInit, OnDestroy { } if (file) { this.file = file; + this.readFile(this.file); if (this.file.size / 1024 / 1024 < 1) { this.fileSize = Math.ceil(file.size / 1024); } diff --git a/src/app/shared/models/index.ts b/src/app/shared/models/index.ts index d9d61d61f365f9e65081dc4e3fc0d5262b4a9d14..937eb62ee4f96b08e5c69dc37ca1f908eca7c4ac 100644 --- a/src/app/shared/models/index.ts +++ b/src/app/shared/models/index.ts @@ -3,3 +3,4 @@ export * from './filter.model'; export * from './user-details'; export * from './public-solution.model'; export * from './comment'; +export * from './navigation-label.model'; diff --git a/src/app/shared/models/message-status.model.ts b/src/app/shared/models/message-status.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..93761dc974a208f5dd2b2ab6552826ec963a8618 --- /dev/null +++ b/src/app/shared/models/message-status.model.ts @@ -0,0 +1,15 @@ +export interface MessageStatusModel { + taskId: string; + stepResultId: string; + trackingId: string; + stepCode: string; + solutionId: string; + revisionId: string; + artifactId: string; + userId: string; + name: string; + statusCode: string; + result: string; + startDate: string; + endDate: string; +} diff --git a/src/app/shared/models/navigation-label.model.ts b/src/app/shared/models/navigation-label.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..c4c4dd9014215a25e283bb3ceee1e3eca0757412 --- /dev/null +++ b/src/app/shared/models/navigation-label.model.ts @@ -0,0 +1,4 @@ +export interface NavigationLabelModel { + label: string; + disabled?: boolean; +} diff --git a/src/assets/images/ico-checkmark.png b/src/assets/images/ico-checkmark.png new file mode 100644 index 0000000000000000000000000000000000000000..68f1686279b683ee53e82a4a2a29f2b5e758a368 Binary files /dev/null and b/src/assets/images/ico-checkmark.png differ diff --git a/src/assets/images/ico_add_to_repository.png b/src/assets/images/ico_add_to_repository.png new file mode 100644 index 0000000000000000000000000000000000000000..832ab796b44a493bd18f89433e4fd3688b902be1 Binary files /dev/null and b/src/assets/images/ico_add_to_repository.png differ diff --git a/src/assets/images/ico_add_to_repository_green.png b/src/assets/images/ico_add_to_repository_green.png new file mode 100644 index 0000000000000000000000000000000000000000..a53a33ce31ee54497da50b09ecf0668bc092dd5e Binary files /dev/null and b/src/assets/images/ico_add_to_repository_green.png differ diff --git a/src/assets/images/ico_add_to_repository_red.png b/src/assets/images/ico_add_to_repository_red.png new file mode 100644 index 0000000000000000000000000000000000000000..36369caee5882085b7431e43caa7bf08eebd6b2e Binary files /dev/null and b/src/assets/images/ico_add_to_repository_red.png differ diff --git a/src/assets/images/ico_create_micro_service.png b/src/assets/images/ico_create_micro_service.png new file mode 100644 index 0000000000000000000000000000000000000000..7385f982364e66f7161fee248bfe5103b1bdb225 Binary files /dev/null and b/src/assets/images/ico_create_micro_service.png differ diff --git a/src/assets/images/ico_create_micro_service_green.png b/src/assets/images/ico_create_micro_service_green.png new file mode 100644 index 0000000000000000000000000000000000000000..0fd720776498a4daa90eaefd2e6bd62b3cfc1e80 Binary files /dev/null and b/src/assets/images/ico_create_micro_service_green.png differ diff --git a/src/assets/images/ico_create_micro_service_red.png b/src/assets/images/ico_create_micro_service_red.png new file mode 100644 index 0000000000000000000000000000000000000000..d044b5d2e91fe65f3547854ad68948c5609fb41d Binary files /dev/null and b/src/assets/images/ico_create_micro_service_red.png differ diff --git a/src/assets/images/ico_not_yet_onboarded.png b/src/assets/images/ico_not_yet_onboarded.png new file mode 100644 index 0000000000000000000000000000000000000000..672cccf271b839c48e6c860f2641a8d2f1d1ac9a Binary files /dev/null and b/src/assets/images/ico_not_yet_onboarded.png differ diff --git a/src/assets/images/loading_deactive.png b/src/assets/images/loading_deactive.png new file mode 100644 index 0000000000000000000000000000000000000000..5d737e07b46bccaa738e2511d13cabe3b70d3625 Binary files /dev/null and b/src/assets/images/loading_deactive.png differ diff --git a/src/assets/images/stepper_progress_completed.png b/src/assets/images/stepper_progress_completed.png new file mode 100644 index 0000000000000000000000000000000000000000..e2ef453bedbf98b8b6c3ce86716d0292fd383c7e Binary files /dev/null and b/src/assets/images/stepper_progress_completed.png differ