From a1fee4de585321572f6ef2137e5e3a69f47f997a Mon Sep 17 00:00:00 2001 From: RIHTARSIC Joze <joze.rihtarsic@ext.ec.europa.eu> Date: Wed, 14 Jun 2023 08:56:01 +0200 Subject: [PATCH] Fix navigation issues --- smp-angular/src/app/app.routes.ts | 6 +- .../password-change-dialog.component.html | 9 +-- .../resource-document-panel.component.ts | 3 +- .../guards/activate-child-document.guard.ts | 20 +++++++ .../src/app/login/login.component.html | 1 - .../src/app/security/security.service.ts | 2 +- .../sidenav/nav-tree/nav-tree.component.html | 4 +- .../sidenav/navigation-model.service.ts | 56 +++++++++++++++++-- .../app/window/toolbar/toolbar.component.html | 4 +- .../app/window/toolbar/toolbar.component.ts | 4 ++ smp-angular/src/styles.css | 1 + 11 files changed, 90 insertions(+), 20 deletions(-) create mode 100644 smp-angular/src/app/guards/activate-child-document.guard.ts diff --git a/smp-angular/src/app/app.routes.ts b/smp-angular/src/app/app.routes.ts index 7942823f9..698dd2eab 100644 --- a/smp-angular/src/app/app.routes.ts +++ b/smp-angular/src/app/app.routes.ts @@ -19,6 +19,7 @@ import {EditResourceComponent} from "./edit/edit-resources/edit-resource.compone import {ResourceDocumentPanelComponent} from "./edit/edit-resources/resource-document-panel/resource-document-panel.component"; import {SubresourceDocumentPanelComponent} from "./edit/edit-resources/subresource-document-panel/subresource-document-panel.component"; import {authorizeChildSystemAdminGuard} from "./guards/authorize-child-system-admin.guard"; +import {activateChildResourceGuard} from "./guards/activate-child-document.guard"; const appRoutes: Routes = [ @@ -34,11 +35,10 @@ const appRoutes: Routes = [ {path: 'edit-group', component: EditGroupComponent, canDeactivate: [dirtyDeactivateGuard]}, { path: 'edit-resource', - canDeactivate: [dirtyDeactivateGuard], children: [ - {path: 'resource-document', component: ResourceDocumentPanelComponent, canDeactivate: [dirtyDeactivateGuard]}, - {path: 'subresource-document', component: SubresourceDocumentPanelComponent, canDeactivate: [dirtyDeactivateGuard]}, + {path: 'resource-document', canActivate: [activateChildResourceGuard], component: ResourceDocumentPanelComponent, canDeactivate: [dirtyDeactivateGuard]}, + {path: 'subresource-document', canActivate: [activateChildResourceGuard], component: SubresourceDocumentPanelComponent, canDeactivate: [dirtyDeactivateGuard]}, {path: '', component: EditResourceComponent, canDeactivate: [dirtyDeactivateGuard]}, ] } diff --git a/smp-angular/src/app/common/dialogs/password-change-dialog/password-change-dialog.component.html b/smp-angular/src/app/common/dialogs/password-change-dialog/password-change-dialog.component.html index a91d88f85..1c85aec01 100644 --- a/smp-angular/src/app/common/dialogs/password-change-dialog/password-change-dialog.component.html +++ b/smp-angular/src/app/common/dialogs/password-change-dialog/password-change-dialog.component.html @@ -1,5 +1,5 @@ <h2 mat-dialog-title>{{formTitle}}</h2> -<mat-dialog-content style="width:500px"> +<mat-dialog-content style="width:500px;padding-bottom: 0"> <div *ngIf="message" [ngClass]="{ 'alert-message': message, 'alert-message-success': messageType === 'success', 'alert-message-error':messageType === 'error' }" @@ -8,14 +8,14 @@ {{message}} </div> <form [formGroup]="dialogForm"> - <div style="display:flex;flex-direction: column"> + <div style="display:flex;flex-direction: column;"> <mat-form-field style="width:100%"> <mat-label>Change password for Username</mat-label> <input matInput formControlName="username" id="un_id" readonly="true"> </mat-form-field> - <div class="password-panel" style="display: flex;flex-direction: column"> + <div class="password-panel" style="display: flex;flex-direction: column;"> <mat-form-field *ngIf="showCurrentPasswordField" style="width:100%"> <mat-label>{{getPasswordTitle}}</mat-label> @@ -48,11 +48,12 @@ </mat-form-field> </div> + <div class="required-fields">* required fields</div> </div> </form> </mat-dialog-content> -<div class="required-fields">* required fields</div> + <mat-dialog-actions> <button id="changeCurrentUserPasswordButton" mat-raised-button color="primary" (click)="changeCurrentUserPassword()" diff --git a/smp-angular/src/app/edit/edit-resources/resource-document-panel/resource-document-panel.component.ts b/smp-angular/src/app/edit/edit-resources/resource-document-panel/resource-document-panel.component.ts index 83c317d50..ceebfd4ad 100644 --- a/smp-angular/src/app/edit/edit-resources/resource-document-panel/resource-document-panel.component.ts +++ b/smp-angular/src/app/edit/edit-resources/resource-document-panel/resource-document-panel.component.ts @@ -79,9 +79,8 @@ export class ResourceDocumentPanelComponent implements AfterViewInit, BeforeLeav @Input() set resource(value: ResourceRo) { this._resource = value; - if (!this._resource) { - this.navigationService.reset(); + this.navigationService.navigateToHome(); return; } diff --git a/smp-angular/src/app/guards/activate-child-document.guard.ts b/smp-angular/src/app/guards/activate-child-document.guard.ts new file mode 100644 index 000000000..c244d1949 --- /dev/null +++ b/smp-angular/src/app/guards/activate-child-document.guard.ts @@ -0,0 +1,20 @@ +import {inject} from '@angular/core'; +import {SecurityService} from '../security/security.service'; +import {AlertMessageService} from "../common/alert-message/alert-message.service"; +import {Authority} from "../security/authority.model"; +import {ActivatedRouteSnapshot, CanActivateChildFn, CanActivateFn, RouterStateSnapshot} from "@angular/router"; +import {EditResourceService} from "../edit/edit-resources/edit-resource.service"; + + +export const activateChildResourceGuard: CanActivateFn = + (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + console.log("Is user is authorized"); + const alertService: AlertMessageService = inject(AlertMessageService); + const editResourceService: EditResourceService = inject(EditResourceService); + + let resourceUndefined:boolean = !editResourceService.selectedResource; + if (resourceUndefined) { + alertService.error('Resource/Subresource is not selected! Please select resource from resource edit panel.', true); + } + return !resourceUndefined; + }; diff --git a/smp-angular/src/app/login/login.component.html b/smp-angular/src/app/login/login.component.html index 36416885f..0f96e24f2 100644 --- a/smp-angular/src/app/login/login.component.html +++ b/smp-angular/src/app/login/login.component.html @@ -33,7 +33,6 @@ <mat-icon>input</mat-icon> <span> Login</span> </button> - </form> </mat-card-content> </mat-card> diff --git a/smp-angular/src/app/security/security.service.ts b/smp-angular/src/app/security/security.service.ts index 464a3ecfc..f5f4c0b50 100644 --- a/smp-angular/src/app/security/security.service.ts +++ b/smp-angular/src/app/security/security.service.ts @@ -166,7 +166,7 @@ export class SecurityService { return localStorage.getItem(this.LOCAL_STORAGE_KEY_CURRENT_USER); } - private clearLocalStorage() { + public clearLocalStorage() { localStorage.removeItem(this.LOCAL_STORAGE_KEY_CURRENT_USER); } diff --git a/smp-angular/src/app/window/sidenav/nav-tree/nav-tree.component.html b/smp-angular/src/app/window/sidenav/nav-tree/nav-tree.component.html index b7239bece..132776fe6 100644 --- a/smp-angular/src/app/window/sidenav/nav-tree/nav-tree.component.html +++ b/smp-angular/src/app/window/sidenav/nav-tree/nav-tree.component.html @@ -2,8 +2,8 @@ [treeControl]="treeControl" class="nav-tree"> <!-- Leaf nodes --> - <mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle> - <li class="mat-tree-node nav-tree-leaf" [ngClass]="{ 'navigation-selected': navigationModel.selected === node}"> + <mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle> + <li *ngIf="!node.transient" class="mat-tree-node nav-tree-leaf" [ngClass]="{ 'navigation-selected': navigationModel.selected === node}"> <button [id]="node.code+'Button'" mat-menu-item (click)="menuClickHandler(node)"> <mat-icon *ngIf="node.icon">{{node.icon}}</mat-icon> <span *ngIf="fullMenu">{{node.name}}</span> diff --git a/smp-angular/src/app/window/sidenav/navigation-model.service.ts b/smp-angular/src/app/window/sidenav/navigation-model.service.ts index fc96ae3a5..ec61e088a 100644 --- a/smp-angular/src/app/window/sidenav/navigation-model.service.ts +++ b/smp-angular/src/app/window/sidenav/navigation-model.service.ts @@ -5,8 +5,9 @@ import {SecurityEventService} from "../../security/security-event.service"; import {SmpConstants} from "../../smp.constants"; import {HttpClient} from "@angular/common/http"; import {User} from "../../security/user.model"; -import {Router} from "@angular/router"; +import {NavigationEnd, Router} from "@angular/router"; import {Observable, Subject} from "rxjs"; +import {filter, map} from "rxjs/operators"; /** * The smp navigation tree @@ -50,7 +51,6 @@ export interface NavigationNode { tooltip?: string; routerLink?: string; children?: NavigationNode[]; - selected?: boolean; transient?: boolean; // if true then node must be ignored } @@ -58,6 +58,20 @@ export interface NavigationNode { @Injectable() export class NavigationService extends MatTreeNestedDataSource<NavigationNode> { + private sub = this.router.events + .pipe( + filter(event => event instanceof NavigationEnd), + map(event => event as NavigationEnd), // appease typescript + ) + .subscribe( + event => { + console.log('NavigationService: ' + event.url) + let path: string[] = event.url.split('/'); + this.setNavigationTreeByPath(path, this.rootNode); + } + ); + + private selectedPathSubject = new Subject<NavigationNode[]>(); selected: NavigationNode; @@ -93,8 +107,11 @@ export class NavigationService extends MatTreeNestedDataSource<NavigationNode> { this.refreshNavigationTree(); } ); + } - + ngOnDestroy() { + console.log('>> STOP listening to route events '); + this.sub.unsubscribe(); } select(node: NavigationNode) { @@ -325,16 +342,45 @@ export class NavigationService extends MatTreeNestedDataSource<NavigationNode> { } public navigateToLogin(): void { + this.securityService.clearLocalStorage() this.reset(); - this.router.navigate(['/login'], {queryParams: {returnUrl: this.router.url}}); - this.router.parseUrl('/login'); + let node: NavigationNode = this.createNew(); + this.rootNode.children.push(node); + this.select(node); + + //this.reset(); + //this.router.navigate(['/login'], {queryParams: {returnUrl: this.router.url}}); + //this.router.parseUrl('/login'); } public navigateToHome(): void { this.select(this.rootNode); } + public navigateUp(): void { + this.selectedPath?.pop(); + if (this.selectedPath?.length > 0) { + this.select(this.selectedPath[this.selectedPath.length - 1]); + } + + + } + public navigateToUserDetails(): void { this.setNavigationTreeByPath(['user-settings', 'user-profile'], this.rootNode) } + + + public createNew(): NavigationNode { + return { + code: "login", + icon: "login", + name: "Login", + routerLink: "login", + selected: true, + tooltip: "", + transient: true, + } + } + } diff --git a/smp-angular/src/app/window/toolbar/toolbar.component.html b/smp-angular/src/app/window/toolbar/toolbar.component.html index d8db49ff0..641a16c4e 100644 --- a/smp-angular/src/app/window/toolbar/toolbar.component.html +++ b/smp-angular/src/app/window/toolbar/toolbar.component.html @@ -6,8 +6,8 @@ [attr.width]="fullMenu ? '180px' : '50px'"/> </div> <span class="window-toolbar-spacer"></span> - <a id="login_id" class="window-toolbar-item" *ngIf="!currentUser" [routerLink]="['/login']" - (click)="clearWarning()"> Login </a> + <a id="login_id" class="window-toolbar-item" *ngIf="!currentUser" + (click)="navigateToLogin()"> Login </a> <span class="window-toolbar-item" *ngIf="currentUser">{{currentUserRoleDescription}}: {{currentUser}} </span> <button class="window-toolbar-item" [mat-menu-trigger-for]="settingsMenu" id="settingsmenu_id" matTooltip="Menu"> diff --git a/smp-angular/src/app/window/toolbar/toolbar.component.ts b/smp-angular/src/app/window/toolbar/toolbar.component.ts index cc0bc9a22..2cd76be97 100644 --- a/smp-angular/src/app/window/toolbar/toolbar.component.ts +++ b/smp-angular/src/app/window/toolbar/toolbar.component.ts @@ -56,6 +56,10 @@ export class ToolbarComponent { return this.securityService.isCurrentUserInRole([Authority.SERVICE_GROUP_ADMIN]); } + navigateToLogin(): void { + this.clearWarning(); + this.navigation.navigateToLogin(); + } logout(event: Event): void { event.preventDefault(); diff --git a/smp-angular/src/styles.css b/smp-angular/src/styles.css index 2b2cd3c2a..cee796e55 100644 --- a/smp-angular/src/styles.css +++ b/smp-angular/src/styles.css @@ -112,6 +112,7 @@ ngx-datatable span:before { text-align: left; font-size: 65%; margin: 0 3px; + padding: 0; } .mat-toolbar-multiple-rows { -- GitLab