From 6a573110e84033452a04f78ee4e1a31399922d5f Mon Sep 17 00:00:00 2001 From: Lebeau Elise Date: Tue, 25 Jan 2022 14:17:54 +0000 Subject: [PATCH] Permissions management, add paginator and filters --- src/app/app.module.ts | 9 +- .../group-details/paginator.pipe.ts | 8 +- .../group-management.component.html | 12 +-- .../filter-complete.pipe.ts | 12 +++ .../path-auto-complete.component.ts | 12 +++ .../permissions-filter.pipe.spec.ts | 8 ++ .../permissions-filter.pipe.ts | 32 +++++++ .../permissions-management.component.html | 32 ++++++- .../permissions-management.component.scss | 7 ++ .../permissions-management.component.ts | 39 ++++++-- .../permissions-type-filter.pipe.spec.ts | 8 ++ .../permissions-type-filter.pipe.ts | 32 +++++++ .../permission-editor.component.html | 2 +- .../role-permissions.component.ts | 12 +++ .../user-detail/user-detail.component.ts | 1 - src/app/resolvers/user-detail.resolver.ts | 12 +++ src/app/resolvers/user-groups.resolver.ts | 12 +++ .../resolvers/user-permissions.resolver.ts | 12 +++ src/app/services/api-information.service.ts | 92 +++++++++++++------ 19 files changed, 299 insertions(+), 55 deletions(-) create mode 100644 src/app/components/permissions-management/permissions-filter.pipe.spec.ts create mode 100644 src/app/components/permissions-management/permissions-filter.pipe.ts create mode 100644 src/app/components/permissions-management/permissions-type-filter.pipe.spec.ts create mode 100644 src/app/components/permissions-management/permissions-type-filter.pipe.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 6c4f19b9..ff98ff72 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,5 +1,4 @@ /* tslint:disable */ -/* tslint:disable:max-line-length */ import {DragDropModule} from '@angular/cdk/drag-drop'; import {OverlayModule} from '@angular/cdk/overlay'; import {CdkTableModule} from '@angular/cdk/table'; @@ -300,7 +299,6 @@ import { PermissionEditorValidateDialogComponent } from './components/role-manag import { PermissionsManagementComponent } from './components/permissions-management/permissions-management.component'; import { PermissionEditLineComponent } from '@components/permissions-management/permission-edit-line/permission-edit-line.component'; import {MatSlideToggleModule} from '@angular/material/slide-toggle'; -import { RolePermissionsComponent } from './components/role-management/role-detail/role-permissions/role-permissions.component'; import { UserPermissionsComponent } from './components/user-management/user-detail/user-permissions/user-permissions.component'; import {MatAutocompleteModule} from "@angular/material/autocomplete"; import {PathAutoCompleteComponent} from './components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component'; @@ -311,6 +309,8 @@ import { ActionButtonComponent } from './components/permissions-management/actio import { DeletePermissionDialogComponent } from './components/permissions-management/delete-permission-dialog/delete-permission-dialog.component'; import { AddRoleToGroupComponent } from './components/group-details/add-role-to-group/add-role-to-group.component'; import {MatFormFieldModule} from "@angular/material/form-field"; +import { PermissionsFilterPipe } from './components/permissions-management/permissions-filter.pipe'; +import { PermissionsTypeFilterPipe } from './components/permissions-management/permissions-type-filter.pipe'; @NgModule({ declarations: [ @@ -531,8 +531,9 @@ import {MatFormFieldModule} from "@angular/material/form-field"; DeletePermissionDialogComponent, PathAutoCompleteComponent, FilterCompletePipe, - RolePermissionsComponent, - UserPermissionsComponent + UserPermissionsComponent, + PermissionsFilterPipe, + PermissionsTypeFilterPipe ], imports: [ BrowserModule, diff --git a/src/app/components/group-details/paginator.pipe.ts b/src/app/components/group-details/paginator.pipe.ts index 86dba9f8..7bc69424 100644 --- a/src/app/components/group-details/paginator.pipe.ts +++ b/src/app/components/group-details/paginator.pipe.ts @@ -19,21 +19,21 @@ import {PageEvent} from "@angular/material/paginator"; }) export class PaginatorPipe implements PipeTransform { - transform(members: User[] | undefined, paginatorEvent: PageEvent | undefined): User[] { - if (!members) { + transform(elements: T[] | undefined, paginatorEvent: PageEvent | undefined): T[] { + if (!elements) { return []; } if (!paginatorEvent) { paginatorEvent = { - length: members.length, + length: elements.length, pageIndex: 0, pageSize: 5 }; } - return members.slice( + return elements.slice( paginatorEvent.pageIndex * paginatorEvent.pageSize, (paginatorEvent.pageIndex + 1) * paginatorEvent.pageSize); } diff --git a/src/app/components/group-management/group-management.component.html b/src/app/components/group-management/group-management.component.html index bff63406..43d54c66 100644 --- a/src/app/components/group-management/group-management.component.html +++ b/src/app/components/group-management/group-management.component.html @@ -21,23 +21,23 @@ - + + - + @@ -47,7 +47,7 @@ - + diff --git a/src/app/components/permissions-management/add-permission-line/path-auto-complete/filter-complete.pipe.ts b/src/app/components/permissions-management/add-permission-line/path-auto-complete/filter-complete.pipe.ts index 94519809..d42c242f 100644 --- a/src/app/components/permissions-management/add-permission-line/path-auto-complete/filter-complete.pipe.ts +++ b/src/app/components/permissions-management/add-permission-line/path-auto-complete/filter-complete.pipe.ts @@ -1,3 +1,15 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ import { Pipe, PipeTransform } from '@angular/core'; import {IFormatedList} from "@services/api-information.service"; diff --git a/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.ts b/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.ts index 5f9a8a2b..7d5ef529 100644 --- a/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.ts +++ b/src/app/components/permissions-management/add-permission-line/path-auto-complete/path-auto-complete.component.ts @@ -1,3 +1,15 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import {ApiInformationService, IFormatedList} from "@services/api-information.service"; import {Server} from "@models/server"; diff --git a/src/app/components/permissions-management/permissions-filter.pipe.spec.ts b/src/app/components/permissions-management/permissions-filter.pipe.spec.ts new file mode 100644 index 00000000..b73d1b5d --- /dev/null +++ b/src/app/components/permissions-management/permissions-filter.pipe.spec.ts @@ -0,0 +1,8 @@ +import { PermissionsFilterPipe } from './permissions-filter.pipe'; + +describe('PermissionsFilterPipe', () => { + it('create an instance', () => { + const pipe = new PermissionsFilterPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src/app/components/permissions-management/permissions-filter.pipe.ts b/src/app/components/permissions-management/permissions-filter.pipe.ts new file mode 100644 index 00000000..71b4e75f --- /dev/null +++ b/src/app/components/permissions-management/permissions-filter.pipe.ts @@ -0,0 +1,32 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import { Pipe, PipeTransform } from '@angular/core'; +import {Permission} from "@models/api/permission"; + +@Pipe({ + name: 'permissionsFilter' +}) +export class PermissionsFilterPipe implements PipeTransform { + + transform(permissions: Permission[], filterText: string): Permission[] { + if (!permissions) { + return []; + } + if (filterText === undefined || filterText === null || filterText === '') { + return permissions; + } + + return permissions.filter((permissions: Permission) => permissions.path.toLowerCase().includes(filterText.toLowerCase())); + } + +} diff --git a/src/app/components/permissions-management/permissions-management.component.html b/src/app/components/permissions-management/permissions-management.component.html index 07049b82..05086799 100644 --- a/src/app/components/permissions-management/permissions-management.component.html +++ b/src/app/components/permissions-management/permissions-management.component.html @@ -5,14 +5,38 @@ (addPermissionEvent)="refresh()">
- - -
+ + + Filter : + + + All + {{elt.view}} + + + + + + {{option.name}} + + + +
+
diff --git a/src/app/components/permissions-management/permissions-management.component.scss b/src/app/components/permissions-management/permissions-management.component.scss index 72573ef6..f4a7bf80 100644 --- a/src/app/components/permissions-management/permissions-management.component.scss +++ b/src/app/components/permissions-management/permissions-management.component.scss @@ -28,3 +28,10 @@ border-bottom: 1px solid; align-items: center;*/ } + +.permission-filter { + border-bottom: 1px solid; + width : 200px; + margin: 5px; + border-bottom-color: #b0bec5; +} diff --git a/src/app/components/permissions-management/permissions-management.component.ts b/src/app/components/permissions-management/permissions-management.component.ts index d9b662d1..b7700e16 100644 --- a/src/app/components/permissions-management/permissions-management.component.ts +++ b/src/app/components/permissions-management/permissions-management.component.ts @@ -18,6 +18,8 @@ import {ProgressService} from "../../common/progress/progress.service"; import {Permission} from "@models/api/permission"; import {AddPermissionLineComponent} from "@components/permissions-management/add-permission-line/add-permission-line.component"; import {ServerService} from "@services/server.service"; +import {PageEvent} from "@angular/material/paginator"; +import {ApiInformationService, IFormatedList} from "@services/api-information.service"; @Component({ selector: 'app-permissions-management', @@ -29,6 +31,16 @@ export class PermissionsManagementComponent implements OnInit { permissions: Permission[]; addPermissionLineComp = AddPermissionLineComponent; newPermissionEdit = false; + searchPermissions: any; + pageEvent: PageEvent | undefined; + filteredOptions: IFormatedList[]; + options: string[] = []; + typeFilter: any; + typeValues = [ + {value: '{project_id}', view:'projects'}, + {value: '{image_path}', view:'images'}, + {value: '{template_id}', view:'templates'}, + {value: '{compute_id}', view:'computes'}] @ViewChild('dynamic', { read: ViewContainerRef @@ -39,11 +51,11 @@ export class PermissionsManagementComponent implements OnInit { private router: Router, private permissionService: PermissionsService, private progressService: ProgressService, - private serverService: ServerService) { } + private serverService: ServerService, + private apiInformationService: ApiInformationService) { } ngOnInit(): void { const serverId = this.route.parent.snapshot.paramMap.get('server_id'); - console.log(serverId); this.serverService.get(+serverId).then((server: Server) => { this.server = server; this.refresh(); @@ -62,15 +74,24 @@ export class PermissionsManagementComponent implements OnInit { ); } - addPermission() { - //const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.addPermissionLineComp); - //const component = this.viewContainerRef.createComponent(componentFactory); - //component.instance.server = this.server; - this.newPermissionEdit = true; + changeType(typeValue: any) { + if (typeValue.value.value.match(this.apiInformationService.bracketIdRegex)) { + this.apiInformationService.getListByObjectId(this.server, typeValue.value.value) + .subscribe((data) => { + this.filteredOptions = data; + }); + } else { + this.filteredOptions = this.apiInformationService.getIdByObjNameFromCache(''); + } } - updateList($event: any) { - this.newPermissionEdit = false; + displayFn(value): string { + return value && value.name ? value.name : ''; } + + changeAutocomplete(inputText) { + this.filteredOptions = this.apiInformationService.getIdByObjNameFromCache(inputText); + } + } diff --git a/src/app/components/permissions-management/permissions-type-filter.pipe.spec.ts b/src/app/components/permissions-management/permissions-type-filter.pipe.spec.ts new file mode 100644 index 00000000..da55bd74 --- /dev/null +++ b/src/app/components/permissions-management/permissions-type-filter.pipe.spec.ts @@ -0,0 +1,8 @@ +import { PermissionsTypeFilterPipe } from './permissions-type-filter.pipe'; + +describe('PermissionsTypeFilterPipe', () => { + it('create an instance', () => { + const pipe = new PermissionsTypeFilterPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src/app/components/permissions-management/permissions-type-filter.pipe.ts b/src/app/components/permissions-management/permissions-type-filter.pipe.ts new file mode 100644 index 00000000..a5ce9fe0 --- /dev/null +++ b/src/app/components/permissions-management/permissions-type-filter.pipe.ts @@ -0,0 +1,32 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ +import { Pipe, PipeTransform } from '@angular/core'; +import {Permission} from "@models/api/permission"; + +@Pipe({ + name: 'permissionsTypeFilter' +}) +export class PermissionsTypeFilterPipe implements PipeTransform { + + transform(permissions: Permission[], filterTypeText: string): Permission[] { + if (!permissions) { + return []; + } + if (filterTypeText === undefined || filterTypeText === null || filterTypeText === '') { + return permissions; + } + + return permissions.filter((permissions: Permission) => permissions.path.toLowerCase().includes(filterTypeText.toLowerCase())); + } + +} diff --git a/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.html b/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.html index 74499215..a6c53755 100644 --- a/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.html +++ b/src/app/components/role-management/role-detail/permission-editor/permission-editor.component.html @@ -36,7 +36,7 @@
-
available
+
Available
{ - console.log("Done ", user) this.toasterService.success(`User ${user.username} updated`); }, (error) => { diff --git a/src/app/resolvers/user-detail.resolver.ts b/src/app/resolvers/user-detail.resolver.ts index e464c28b..5ea8b6dc 100644 --- a/src/app/resolvers/user-detail.resolver.ts +++ b/src/app/resolvers/user-detail.resolver.ts @@ -1,3 +1,15 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ import { Injectable } from '@angular/core'; import { Router, Resolve, diff --git a/src/app/resolvers/user-groups.resolver.ts b/src/app/resolvers/user-groups.resolver.ts index 2aa66dcb..9a03ce64 100644 --- a/src/app/resolvers/user-groups.resolver.ts +++ b/src/app/resolvers/user-groups.resolver.ts @@ -1,3 +1,15 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ import { Injectable } from '@angular/core'; import { Router, Resolve, diff --git a/src/app/resolvers/user-permissions.resolver.ts b/src/app/resolvers/user-permissions.resolver.ts index 4626af4b..5fd0000f 100644 --- a/src/app/resolvers/user-permissions.resolver.ts +++ b/src/app/resolvers/user-permissions.resolver.ts @@ -1,3 +1,15 @@ +/* +* Software Name : GNS3 Web UI +* Version: 3 +* SPDX-FileCopyrightText: Copyright (c) 2022 Orange Business Services +* SPDX-License-Identifier: GPL-3.0-or-later +* +* This software is distributed under the GPL-3.0 or any later version, +* the text of which is available at https://www.gnu.org/licenses/gpl-3.0.txt +* or see the "LICENSE" file for more details. +* +* Author: Sylvain MATHIEU, Elise LEBEAU +*/ import { Injectable } from '@angular/core'; import { Router, Resolve, diff --git a/src/app/services/api-information.service.ts b/src/app/services/api-information.service.ts index 47e232f5..24dc9096 100644 --- a/src/app/services/api-information.service.ts +++ b/src/app/services/api-information.service.ts @@ -12,8 +12,8 @@ */ import {Injectable} from '@angular/core'; import {HttpClient} from "@angular/common/http"; -import {Observable, ReplaySubject} from "rxjs"; -import {map, switchMap} from "rxjs/operators"; +import {Observable, of, ReplaySubject} from "rxjs"; +import {map, switchMap, take} from "rxjs/operators"; import {Methods} from "@models/api/permission"; import {HttpServer} from "@services/http-server.service"; import {Server} from "@models/server"; @@ -40,19 +40,22 @@ export interface IFormatedList { name?: string; } + @Injectable({ providedIn: 'root' }) export class ApiInformationService { + private cache_permissions: { [key: string]: IFormatedList; } = {}; private allowed = ['projects', 'images', 'templates', 'computes', 'symbols', 'notifications']; private data: ReplaySubject = new ReplaySubject(1); private objs: ReplaySubject = new ReplaySubject(1); - public readonly bracketIdRegex = new RegExp("\{(.*?)\}"); + public readonly bracketIdRegex = new RegExp("\{(.*?)\}", 'g'); + public readonly uuidRegex = new RegExp("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"); public readonly finalBracketIdRegex = new RegExp("\{(.*?)\}$"); - constructor(private httpClient: HttpClient, - private httpServer: HttpServer) { + + constructor(private httpClient: HttpClient) { this.loadLocalInformation(); this.data.subscribe((data) => { @@ -143,7 +146,6 @@ export class ApiInformationService { const splinted = path .split('/') .filter(elem => !(elem === '' || elem === 'v3')); - let remains = data; splinted.forEach((value, index) => { if (value === '*') { @@ -154,9 +156,7 @@ export class ApiInformationService { if (matchUrl.length === 0) { matchUrl = remains.filter(val => val.subPaths[index]?.match(this.bracketIdRegex)); } - remains = matchUrl; - }); return remains; }) @@ -189,10 +189,25 @@ export class ApiInformationService { })); } - getListByObjectId(server: Server, value: string) { + getKeysForPath(path: string): Observable<{ key: string; value: string }[]> { + return this.getPath(path) + .pipe(map((paths: IPathDict[]) => { + const splinted = path + .split('/') + .filter(elem => !(elem === '' || elem === 'v3')); + return paths[0].subPaths.map((elem, index) => { + if (elem.match(this.bracketIdRegex)) { + return {key: elem, value: splinted[index]}; + } + }); + }), map((values) => { + return values.filter((v) => v !== undefined); + })); + } + getListByObjectId(server: Server, key: string, value?: string) { function findElement(data: IApiObject[]): IApiObject { - const elem = data.find(d => d.name === value); + const elem = data.find(d => d.name === key); if (!elem) { throw new Error('entry not found'); } @@ -202,28 +217,53 @@ export class ApiInformationService { return this.objs.pipe( map(findElement), switchMap(elem => { - const url = `${server.protocol}//${server.host}:${server.port}${elem.path}`; + let url = `${server.protocol}//${server.host}:${server.port}${elem.path}`; + if (value) { + url = `${url}/${value}`; + } return this.httpClient.get(url, {headers: {Authorization: `Bearer ${server.authToken}`}}); } ), - map(response => { + switchMap(response => { - if (response.length === 0) { - return []; + if (response instanceof Array) { + if (response.length === 0) { + return of([]); + } + const keys = Object.keys(response[0]); + const idKey = keys.find(k => k.match(/_id$|filename/)); + const nameKey = keys.find(k => k.match(/name/)); + response = response.map(o => { + return { + id: o[idKey], + name: o[nameKey] + }; + }); + response.forEach(elt => { + this.cache_permissions[elt.id] = elt; + }) + console.log('b', this.cache_permissions) + + return of(response); + } else { + const keys = Object.keys(response); + const idKey = keys.find(k => k.match(/_id$|filename/)); + const nameKey = keys.find(k => k.match(/name/)); + const ret = {id: response[idKey], name: response[nameKey]}; + this.cache_permissions[ret.id] = ret; + return of([ret]); } + }), take(1)); + } - const keys = Object.keys(response[0]); - const idKey = keys.find(k => k.match(/_id$|filename/)); - const nameKey = keys.find(k => k.match(/name/)); - - return response.map(o => { - return { - id: o[idKey], - name: o[nameKey] - }; - }); - })); - + getIdByObjNameFromCache(name: string): IFormatedList[] { + const ret: IFormatedList[] = []; + for (let [key, value] of Object.entries(this.cache_permissions)) { + if (value.name.includes(name)) { + ret.push(value); + } + } + return ret; } }
- - + - + Name{{element.name}} {{element.name}} last update Last update {{element.updated_at}}