diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 64efaae9..36526e76 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -37,6 +37,7 @@ import { OrganizationCollectionService } from './store/organization-collection.s
import { KubernetesDataServiceFactory } from './store/kubernetes-data.service';
import { KubernetesCollectionServiceFactory } from './store/kubernetes-collection.service';
import { SelfSubjectAccessReviewCollectionService } from './store/ssar-collection.service';
+import { NavigationService } from './shared/navigation.service';
@NgModule({
declarations: [
@@ -72,7 +73,8 @@ import { SelfSubjectAccessReviewCollectionService } from './store/ssar-collectio
SelfSubjectAccessReviewCollectionService,
{
provide: APP_INITIALIZER,
- deps: [AppConfigService, OAuthService],
+ // start the NavigationService early to catch route events.
+ deps: [AppConfigService, OAuthService, NavigationService],
useFactory: initializeAppFactory,
multi: true,
},
diff --git a/src/app/billingentity/billingentity-members/billingentity-members.component.html b/src/app/billingentity/billingentity-members/billingentity-members.component.html
index c27be7b0..71b80cc2 100644
--- a/src/app/billingentity/billingentity-members/billingentity-members.component.html
+++ b/src/app/billingentity/billingentity-members/billingentity-members.component.html
@@ -6,7 +6,7 @@
{{ payload.billingEntity.metadata.name }}
Members
-
+
diff --git a/src/app/billingentity/billingentity-members/billingentity-members.component.ts b/src/app/billingentity/billingentity-members/billingentity-members.component.ts
index 5f8078d2..02015dda 100644
--- a/src/app/billingentity/billingentity-members/billingentity-members.component.ts
+++ b/src/app/billingentity/billingentity-members/billingentity-members.component.ts
@@ -15,6 +15,7 @@ import { defaultIfNotFound } from '../../store/kubernetes-collection.service';
import { ClusterRoleCollectionService } from '../../store/cluster-role-collection.service';
import { ClusterRole } from '../../types/clusterRole';
import { KubeObject } from '../../types/entity';
+import { NavigationService } from '../../shared/navigation.service';
interface Payload {
billingEntity: BillingEntity;
@@ -54,6 +55,7 @@ export class BillingentityMembersComponent implements OnInit, OnDestroy {
constructor(
private route: ActivatedRoute,
private router: Router,
+ private navigationService: NavigationService,
private billingService: BillingEntityCollectionService,
private roleService: ClusterRoleCollectionService,
public rolebindingService: ClusterRolebindingCollectionService,
@@ -234,7 +236,7 @@ export class BillingentityMembersComponent implements OnInit, OnDestroy {
severity: 'success',
summary: $localize`Successfully saved`,
});
- void this.router.navigate(['../..'], { relativeTo: this.route });
+ void this.router.navigate([this.navigationService.previousLocation()], { relativeTo: this.route });
},
error: (error) => {
this.messageService.add({
diff --git a/src/app/billingentity/billingentity-view/billingentity-view.component.html b/src/app/billingentity/billingentity-view/billingentity-view.component.html
index 87cf6a4b..8770e9a8 100644
--- a/src/app/billingentity/billingentity-view/billingentity-view.component.html
+++ b/src/app/billingentity/billingentity-view/billingentity-view.component.html
@@ -4,7 +4,7 @@
{{ billingEntity.metadata.name }}
-
+
diff --git a/src/app/organizations/organization-edit/organization-edit.component.html b/src/app/organizations/organization-edit/organization-edit.component.html
index b352cb8b..a604bdc0 100644
--- a/src/app/organizations/organization-edit/organization-edit.component.html
+++ b/src/app/organizations/organization-edit/organization-edit.component.html
@@ -8,7 +8,7 @@
{{ payload.organization.metadata.name }}
-
+
diff --git a/src/app/organizations/organization-form/organization-form.component.ts b/src/app/organizations/organization-form/organization-form.component.ts
index 5a32b51d..511a5aed 100644
--- a/src/app/organizations/organization-form/organization-form.component.ts
+++ b/src/app/organizations/organization-form/organization-form.component.ts
@@ -8,6 +8,7 @@ import { MessageService } from 'primeng/api';
import { OrganizationNameService } from '../organization-name.service';
import { OrganizationCollectionService } from '../../store/organization-collection.service';
import { BillingEntity } from '../../types/billing-entity';
+import { NavigationService } from '../../shared/navigation.service';
@Component({
selector: 'app-organization-form',
@@ -40,7 +41,8 @@ export class OrganizationFormComponent implements OnInit, OnDestroy {
private activatedRoute: ActivatedRoute,
private messageService: MessageService,
private organizationNameService: OrganizationNameService,
- public organizationCollectionService: OrganizationCollectionService
+ public organizationCollectionService: OrganizationCollectionService,
+ private navigationService: NavigationService
) {}
ngOnInit(): void {
@@ -114,12 +116,11 @@ export class OrganizationFormComponent implements OnInit, OnDestroy {
severity: 'success',
summary: $localize`Successfully saved`,
});
- void this.router.navigate(['..'], { relativeTo: this.activatedRoute });
+ void this.router.navigate([this.navigationService.previousLocation()], { relativeTo: this.activatedRoute });
}
private saveOrUpdateFailure(err: Error): void {
let detail = '';
- console.debug('error!', err);
if ('message' in err) {
detail = err.message;
}
@@ -132,6 +133,7 @@ export class OrganizationFormComponent implements OnInit, OnDestroy {
this.messageService.add({
severity: 'error',
summary: $localize`Error`,
+ sticky: true,
detail,
});
}
diff --git a/src/app/organizations/organization-members-edit/organization-members-edit.component.html b/src/app/organizations/organization-members-edit/organization-members-edit.component.html
index 568d040b..0a7dae3f 100644
--- a/src/app/organizations/organization-members-edit/organization-members-edit.component.html
+++ b/src/app/organizations/organization-members-edit/organization-members-edit.component.html
@@ -6,7 +6,7 @@
{{ payload.members.metadata.namespace }}
Members
-
+
diff --git a/src/app/organizations/organization-members-edit/organization-members-edit.component.ts b/src/app/organizations/organization-members-edit/organization-members-edit.component.ts
index 3753109f..92718e9a 100644
--- a/src/app/organizations/organization-members-edit/organization-members-edit.component.ts
+++ b/src/app/organizations/organization-members-edit/organization-members-edit.component.ts
@@ -8,6 +8,7 @@ import { MessageService } from 'primeng/api';
import { RoleBinding } from 'src/app/types/role-binding';
import { OrganizationMembersCollectionService } from '../../store/organizationmembers-collection.service';
import { RolebindingCollectionService } from '../../store/rolebinding-collection.service';
+import { NavigationService } from '../../shared/navigation.service';
interface Payload {
members: OrganizationMembers;
@@ -47,7 +48,8 @@ export class OrganizationMembersEditComponent implements OnInit {
private messageService: MessageService,
private router: Router,
private membersService: OrganizationMembersCollectionService,
- private rolebindingService: RolebindingCollectionService
+ private rolebindingService: RolebindingCollectionService,
+ private navigationService: NavigationService
) {}
get userRefs(): FormArray | undefined {
@@ -165,7 +167,7 @@ export class OrganizationMembersEditComponent implements OnInit {
severity: 'success',
summary: $localize`Successfully saved`,
});
- void this.router.navigate(['../..'], { relativeTo: this.activatedRoute });
+ void this.router.navigate([this.navigationService.previousLocation()], { relativeTo: this.activatedRoute });
},
error: (error) => {
this.messageService.add({
diff --git a/src/app/shared/back-link.directive.ts b/src/app/shared/back-link.directive.ts
new file mode 100644
index 00000000..b85afe17
--- /dev/null
+++ b/src/app/shared/back-link.directive.ts
@@ -0,0 +1,23 @@
+import { Directive, HostListener, Input } from '@angular/core';
+import { NavigationService } from './navigation.service';
+import { ActivatedRoute, Router } from '@angular/router';
+
+/**
+ * This directive adds a `click` event listener to navigate back in history.
+ * It accepts an input that is used as the default path in case there is no history (e.g. opened link in a new tab).
+ */
+@Directive({
+ selector: '[appBackLink]',
+})
+export class BackLinkDirective {
+ constructor(private navigation: NavigationService, private router: Router, private activatedRoute: ActivatedRoute) {}
+
+ @Input()
+ appBackLink?: string;
+
+ @HostListener('click')
+ onClick(): void {
+ const route = this.navigation.previousLocation(this.appBackLink);
+ void this.router.navigate([route], { relativeTo: this.activatedRoute });
+ }
+}
diff --git a/src/app/shared/navigation.service.ts b/src/app/shared/navigation.service.ts
new file mode 100644
index 00000000..f3230244
--- /dev/null
+++ b/src/app/shared/navigation.service.ts
@@ -0,0 +1,35 @@
+import { Injectable } from '@angular/core';
+import { NavigationEnd, Router } from '@angular/router';
+
+/**
+ * Inspired by https://nils-mehlhorn.de/posts/angular-navigate-back-previous-page/
+ * Modified to be used with a Router working with default and relative paths in case the history is empty.
+ */
+@Injectable({ providedIn: 'root' })
+export class NavigationService {
+ private history: string[] = [];
+
+ constructor(private router: Router) {
+ this.router.events.subscribe((event) => {
+ if (event instanceof NavigationEnd) {
+ this.history.push(event.urlAfterRedirects);
+ this.history.splice(0, this.history.length - 5); // only keep the latest few, no need for more.
+ }
+ });
+ }
+
+ /**
+ * Gets the previous URI location in the history.
+ * @param defaultPath if the history is empty, return this path as fallback value
+ * @returns the URI, or '/' if no default was given.
+ */
+ previousLocation(defaultPath?: string): string {
+ void this.history.pop(); // remove "current" location
+ if (this.history.length > 0) {
+ const previousLocation = this.history.pop();
+ return previousLocation ?? defaultPath ?? '/';
+ } else {
+ return defaultPath ?? '/';
+ }
+ }
+}
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index 9f9fe14b..d56cb6f9 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -20,9 +20,10 @@ import { MessageModule } from 'primeng/message';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { MultiSelectModule } from 'primeng/multiselect';
import { ProgressSpinnerModule } from 'primeng/progressspinner';
+import { BackLinkDirective } from './back-link.directive';
@NgModule({
- declarations: [],
+ declarations: [BackLinkDirective],
imports: [],
exports: [
CommonModule,
@@ -47,6 +48,7 @@ import { ProgressSpinnerModule } from 'primeng/progressspinner';
ConfirmDialogModule,
MultiSelectModule,
ProgressSpinnerModule,
+ BackLinkDirective,
],
})
export class SharedModule {}
diff --git a/src/app/teams/team-edit/team-edit.component.html b/src/app/teams/team-edit/team-edit.component.html
index 6473c453..0c1f1ead 100644
--- a/src/app/teams/team-edit/team-edit.component.html
+++ b/src/app/teams/team-edit/team-edit.component.html
@@ -9,7 +9,7 @@
{{ team.metadata.name }}
-
+
diff --git a/src/app/teams/team-edit/team-edit.component.ts b/src/app/teams/team-edit/team-edit.component.ts
index dd7d036a..067f685f 100644
--- a/src/app/teams/team-edit/team-edit.component.ts
+++ b/src/app/teams/team-edit/team-edit.component.ts
@@ -6,6 +6,7 @@ import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@ang
import { MessageService } from 'primeng/api';
import { Observable, of, take, tap } from 'rxjs';
import { TeamCollectionService } from '../../store/team-collection.service';
+import { NavigationService } from '../../shared/navigation.service';
@Component({
selector: 'app-team-edit',
@@ -26,7 +27,8 @@ export class TeamEditComponent implements OnInit {
private router: Router,
private activatedRoute: ActivatedRoute,
private messageService: MessageService,
- public teamService: TeamCollectionService
+ public teamService: TeamCollectionService,
+ private navigationService: NavigationService
) {}
get userRefs(): FormArray {
@@ -71,7 +73,7 @@ export class TeamEditComponent implements OnInit {
severity: 'success',
summary: $localize`Successfully saved`,
});
- void this.router.navigate(['../..'], { relativeTo: this.activatedRoute });
+ void this.router.navigate([this.navigationService.previousLocation()], { relativeTo: this.activatedRoute });
},
error: (error) => {
let detail = '';
diff --git a/src/app/zones/zone/zone-detail.component.html b/src/app/zones/zone/zone-detail.component.html
index cddafe00..d08c3ff3 100644
--- a/src/app/zones/zone/zone-detail.component.html
+++ b/src/app/zones/zone/zone-detail.component.html
@@ -41,7 +41,7 @@