diff --git a/ui/ui-frontend/projects/pastis/src/app/core/services/file.service.ts b/ui/ui-frontend/projects/pastis/src/app/core/services/file.service.ts
index cce5cf56f73..aa31e3cd764 100644
--- a/ui/ui-frontend/projects/pastis/src/app/core/services/file.service.ts
+++ b/ui/ui-frontend/projects/pastis/src/app/core/services/file.service.ts
@@ -133,6 +133,11 @@ export class FileService implements OnDestroy {
* Get profile from backend with id
*/
getProfileAndUpdateTree(element: ProfileDescription) {
+ // Cancel previous request if still pending to avoid data race conditions
+ if (this._profileServiceGetProfileSubscription != null) {
+ this._profileServiceGetProfileSubscription.unsubscribe();
+ }
+
this.loaderService.start();
this._profileServiceGetProfileSubscription = this.profileService
.getProfile(element)
diff --git a/ui/ui-frontend/projects/pastis/src/app/main/main.component.ts b/ui/ui-frontend/projects/pastis/src/app/main/main.component.ts
index c6b30b8c6e1..0cf759c8c30 100644
--- a/ui/ui-frontend/projects/pastis/src/app/main/main.component.ts
+++ b/ui/ui-frontend/projects/pastis/src/app/main/main.component.ts
@@ -75,7 +75,7 @@ import { CdkTextareaAutosize } from '@angular/cdk/text-field';
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ToastContainerDirective, ToastrService } from 'ngx-toastr';
-import { finalize, Subscription } from 'rxjs';
+import { finalize, map, Subscription, switchMap } from 'rxjs';
import { FileService } from '../core/services/file.service';
import { ToggleSidenavService } from '../core/services/toggle-sidenav.service';
import { FileNode, FileNodeInsertAttributeParams, FileNodeInsertParams } from '../models/file-node';
@@ -110,6 +110,7 @@ export class MainComponent implements OnInit, OnDestroy {
uploadedProfileSelected: ProfileDescription;
private _routeParamsSubscription: Subscription;
+ private _profileLoadingSubscription: Subscription;
constructor(
public fileService: FileService,
@@ -121,9 +122,6 @@ export class MainComponent implements OnInit, OnDestroy {
private loaderService: NgxUiLoaderService,
private router: Router,
) {
- this.uploadedProfileResponse = this.router.getCurrentNavigation().extras.state as ProfileResponse;
- this.uploadedProfileSelected = this.router.getCurrentNavigation().extras.state as ProfileDescription;
-
this.sideNavService.isOpened.subscribe((status) => {
this.opened = status;
});
@@ -137,29 +135,20 @@ export class MainComponent implements OnInit, OnDestroy {
this.toastrService.overlayContainer = this.toastContainer;
this._routeParamsSubscription = this.route.params.subscribe((params) => {
const profileId = params.id;
+
// If a profileId has been defined, it is retrieved from backend
if (profileId !== undefined) {
- if (this.uploadedProfileSelected === undefined) {
- this.router.navigate(['/pastis/tenant/1'], { skipLocationChange: false });
- } else {
- this.fileService.getProfileAndUpdateTree(this.uploadedProfileSelected);
- }
+ this.loadProfileById(profileId);
} else {
- // Otherwise we must have an user uploaded profile
- this.uploadedProfileResponse.id = null;
-
- this.loaderService.start();
- this.profileService
- .getMetaModel(this.uploadedProfileResponse.sedaVersion)
- .pipe(
- tap((metaModel) => {
- this.sedaService.setMetaModel(metaModel);
- this.fileService.linkFileNodeToSedaData(null, [this.uploadedProfileResponse.profile]);
- this.fileService.updateTreeWithProfile(this.uploadedProfileResponse);
- }),
- finalize(() => this.loaderService.stop()),
- )
- .subscribe();
+ // Check for query params to create a new profile
+ this.route.queryParams.subscribe((queryParams) => {
+ if (queryParams['type'] && queryParams['version']) {
+ this.createNewProfile(queryParams['type'], queryParams['version']);
+ } else {
+ // No valid params, redirect to list
+ this.router.navigate(['/'], { skipLocationChange: false });
+ }
+ });
}
});
this.opened = true;
@@ -197,6 +186,55 @@ export class MainComponent implements OnInit, OnDestroy {
if (this._routeParamsSubscription != null) {
this._routeParamsSubscription.unsubscribe();
}
+ if (this._profileLoadingSubscription != null) {
+ this._profileLoadingSubscription.unsubscribe();
+ }
if (this.pendingSub) this.pendingSub.unsubscribe();
}
+
+ private loadProfileById(profileId: string) {
+ // Unsubscribe from previous profile loading to avoid multiple concurrent requests
+ if (this._profileLoadingSubscription != null) {
+ this._profileLoadingSubscription.unsubscribe();
+ }
+
+ // Subscribe to profiles list
+ this._profileLoadingSubscription = this.profileService.retrievedProfiles.subscribe((profiles) => {
+ if (!profiles || profiles.length === 0) {
+ // Profiles not loaded yet, refresh the list
+ this.profileService.refreshListProfiles();
+ return;
+ }
+
+ // Find the profile in the list
+ const profileDescription = profiles.find((p) => p.id === profileId);
+ if (profileDescription) {
+ this.fileService.getProfileAndUpdateTree(profileDescription);
+ } else {
+ this.router.navigate(['/'], { skipLocationChange: false });
+ }
+ });
+ }
+
+ private createNewProfile(profileType: string, profileVersion: string) {
+ this.loaderService.start();
+ this.profileService
+ .createProfile('/pastis/profile', profileType as any, profileVersion as any)
+ .pipe(
+ tap((profileResponse) => {
+ this.uploadedProfileResponse = profileResponse;
+ this.uploadedProfileResponse.id = null;
+ }),
+ switchMap((profileResponse) =>
+ this.profileService.getMetaModel(profileResponse.sedaVersion).pipe(map((metaModel) => ({ profileResponse, metaModel }))),
+ ),
+ tap(({ profileResponse, metaModel }) => {
+ this.sedaService.setMetaModel(metaModel);
+ this.fileService.linkFileNodeToSedaData(null, [profileResponse.profile]);
+ this.fileService.updateTreeWithProfile(profileResponse);
+ }),
+ finalize(() => this.loaderService.stop()),
+ )
+ .subscribe();
+ }
}
diff --git a/ui/ui-frontend/projects/pastis/src/app/profile/list-profile/list-profile.component.html b/ui/ui-frontend/projects/pastis/src/app/profile/list-profile/list-profile.component.html
index 4a6577961d9..0d5bac6a011 100644
--- a/ui/ui-frontend/projects/pastis/src/app/profile/list-profile/list-profile.component.html
+++ b/ui/ui-frontend/projects/pastis/src/app/profile/list-profile/list-profile.component.html
@@ -40,7 +40,7 @@
type="file"
/>
-
+
diff --git a/ui/ui-frontend/projects/pastis/src/app/profile/list-profile/list-profile.component.ts b/ui/ui-frontend/projects/pastis/src/app/profile/list-profile/list-profile.component.ts
index 510351501dd..e8a01ae2227 100644
--- a/ui/ui-frontend/projects/pastis/src/app/profile/list-profile/list-profile.component.ts
+++ b/ui/ui-frontend/projects/pastis/src/app/profile/list-profile/list-profile.component.ts
@@ -84,7 +84,6 @@ import { ProfileService } from '../../core/services/profile.service';
import { ToggleSidenavService } from '../../core/services/toggle-sidenav.service';
import { BreadcrumbDataTop } from '../../models/breadcrumb';
import { ProfileDescription } from '../../models/profile-description.model';
-import { ProfileResponse } from '../../models/profile-response';
import { DataGeneriquePopupService } from '../../shared/data-generique-popup.service';
import { PastisDialogData } from '../../shared/pastis-dialog/classes/pastis-dialog-data';
import { CreateProfileComponent, CreateProfileFormResult } from '../create-profile/create-profile.component';
@@ -135,9 +134,6 @@ export class ListProfileComponent extends SidenavPage implem
sedaUrl: string =
this.pastisConfig.pastisPathPrefix + (this.isStandalone ? '' : this.startupService.getTenantIdentifier()) + this.pastisConfig.sedaUrl;
-
- newProfileUrl: string = this.pastisConfig.pastisNewProfile;
-
subscription1$: Subscription;
_uploadProfileSub: Subscription;
subscriptions: Subscription[] = [];
@@ -252,8 +248,7 @@ export class ListProfileComponent extends SidenavPage implem
editProfile(element: ProfileDescription) {
this.profileService.controlSchema.next(element?.controlSchema);
- this.router.navigate([this.pastisConfig.pastisEditPage, element.id], {
- state: element,
+ this.router.navigate(['edit', element.id], {
relativeTo: this.route,
skipLocationChange: false,
});
@@ -266,8 +261,11 @@ export class ListProfileComponent extends SidenavPage implem
const formData = new FormData();
formData.append('file', fileToUpload, fileToUpload.name);
this._uploadProfileSub = this.profileService.uploadProfile(formData).subscribe((response: any) => {
- if (response) {
- this.router.navigate([this.pastisConfig.pastisNewProfile], { state: response, relativeTo: this.route });
+ if (response && response.id) {
+ // Navigate to edit page with the profile ID
+ this.router.navigate(['edit', response.id], {
+ relativeTo: this.route,
+ });
}
});
this.subscriptions.push(this._uploadProfileSub);
@@ -290,16 +288,16 @@ export class ListProfileComponent extends SidenavPage implem
const dialogRef = this.dialog.open(CreateProfileComponent, createProfileDialogConfig);
const subscription = dialogRef
.afterClosed()
- .pipe(
- filter((result) => Boolean(result)),
- switchMap((result) =>
- this.profileService.createProfile(this.pastisConfig.createProfileByTypeUrl, result.profileType, result.profileVersion),
- ),
- filter((profileResponse) => Boolean(profileResponse)),
- )
- .subscribe((profileResponse) =>
- this.router.navigate([this.pastisConfig.pastisNewProfile], { state: profileResponse, relativeTo: this.route }),
- );
+ .pipe(filter((result) => Boolean(result)))
+ .subscribe((result) => {
+ this.router.navigate(['new'], {
+ queryParams: {
+ type: result.profileType,
+ version: result.profileVersion,
+ },
+ relativeTo: this.route,
+ });
+ });
this.subscriptions.push(subscription);
}
diff --git a/ui/ui-frontend/projects/pastis/src/app/shared/pastis-popup-option/pastis-popup-option.component.ts b/ui/ui-frontend/projects/pastis/src/app/shared/pastis-popup-option/pastis-popup-option.component.ts
index 0c2134996e5..de44a97e8e6 100644
--- a/ui/ui-frontend/projects/pastis/src/app/shared/pastis-popup-option/pastis-popup-option.component.ts
+++ b/ui/ui-frontend/projects/pastis/src/app/shared/pastis-popup-option/pastis-popup-option.component.ts
@@ -150,8 +150,11 @@ export class PastisPopupOptionComponent implements OnInit, OnDestroy {
const formData = new FormData();
formData.append('file', fileToUpload, fileToUpload.name);
this.profileService.uploadProfile(formData).subscribe((response: any) => {
- if (response) {
- this.router.navigate([this.newProfileUrl], { state: response, relativeTo: this.route });
+ if (response && response.id) {
+ // Navigate to edit page with the profile ID
+ this.router.navigate(['edit', response.id], {
+ relativeTo: this.route,
+ });
}
});
}