diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 9b2b3650..48cd5074 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -76,6 +76,12 @@ const routes: Routes = [
{ path: 'help', component: HelpComponent },
{ path: 'settings', component: SettingsComponent },
{ path: 'settings/console', component: ConsoleComponent },
+ {
+ path: 'server/:server_id/user_management',
+ component: UserManagementComponent,
+ canActivate: [LoginGuard],
+ resolve: { server: ServerResolve },
+ },
{ path: 'installed-software', component: InstalledSoftwareComponent },
{ path: 'server/:server_id/systemstatus', component: SystemStatusComponent, canActivate: [LoginGuard] },
@@ -208,15 +214,11 @@ const routes: Routes = [
component: WebConsoleFullWindowComponent,
canActivate: [LoginGuard]
},
- {
- path: 'user_management',
- component: UserManagementComponent
- },
{
path: '**',
component: PageNotFoundComponent,
}
-
+
];
@NgModule({
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index caa42a53..b96c4095 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -272,6 +272,7 @@ import { HttpRequestsInterceptor } from './interceptors/http.interceptor';
import { UserManagementComponent } from './components/user-management/user-management.component'
import { UserService } from './services/user.service';
import { LoggedUserComponent } from './components/users/logged-user/logged-user.component';
+import { AddUserDialogComponent } from './components/user-management/add-user-dialog/add-user-dialog.component';
@NgModule({
declarations: [
@@ -459,7 +460,8 @@ import { LoggedUserComponent } from './components/users/logged-user/logged-user.
ConfigureCustomAdaptersDialogComponent,
EditNetworkConfigurationDialogComponent,
UserManagementComponent,
- ProjectReadmeComponent
+ ProjectReadmeComponent,
+ AddUserDialogComponent,
],
imports: [
BrowserModule,
diff --git a/src/app/components/user-management/add-user-dialog/add-user-dialog.component.html b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.html
new file mode 100644
index 00000000..c9ce0f5b
--- /dev/null
+++ b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.html
@@ -0,0 +1,26 @@
+
Create new user
+
diff --git a/src/app/components/user-management/add-user-dialog/add-user-dialog.component.scss b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.scss
new file mode 100644
index 00000000..0907b1ef
--- /dev/null
+++ b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.scss
@@ -0,0 +1,12 @@
+.input-field {
+ width: 100%;
+}
+
+.checkbox-field {
+ display: block;
+ margin-bottom: 5px;
+}
+
+.button-div {
+ float: right;
+}
diff --git a/src/app/components/user-management/add-user-dialog/add-user-dialog.component.spec.ts b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.spec.ts
new file mode 100644
index 00000000..2b92fda2
--- /dev/null
+++ b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AddUserDialogComponent } from './add-user-dialog.component';
+
+describe('AddUserDialogComponent', () => {
+ let component: AddUserDialogComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ AddUserDialogComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AddUserDialogComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/components/user-management/add-user-dialog/add-user-dialog.component.ts b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.ts
new file mode 100644
index 00000000..771c84a1
--- /dev/null
+++ b/src/app/components/user-management/add-user-dialog/add-user-dialog.component.ts
@@ -0,0 +1,68 @@
+/*
+* 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, OnInit } from '@angular/core';
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {MatDialogRef} from "@angular/material/dialog";
+import {UserService} from "@services/user.service";
+import {Server} from "@models/server";
+import {User} from "@models/users/user";
+import {ToasterService} from "@services/toaster.service";
+
+@Component({
+ selector: 'app-add-user-dialog',
+ templateUrl: './add-user-dialog.component.html',
+ styleUrls: ['./add-user-dialog.component.scss']
+})
+export class AddUserDialogComponent implements OnInit {
+ addUserForm: FormGroup;
+ server: Server;
+
+ constructor(public dialogRef: MatDialogRef,
+ public userService: UserService,
+ private toasterService: ToasterService) { }
+
+ ngOnInit(): void {
+ this.addUserForm = new FormGroup({
+ username: new FormControl(null, [
+ Validators.required,
+ Validators.minLength(3),
+ Validators.pattern("[a-zA-Z0-9_-]+$")]),
+ full_name: new FormControl(),
+ email: new FormControl(null, [Validators.email, Validators.required]),
+ password: new FormControl(null,
+ [Validators.required, Validators.minLength(6), Validators.maxLength(100)]),
+ is_active: new FormControl(true),
+ is_superadmin: new FormControl(false)
+ });
+ }
+
+ onCancelClick() {
+ this.dialogRef.close();
+ }
+
+ onAddClick() {
+ if (!this.addUserForm.valid) {
+ return;
+ }
+ const newUser = this.addUserForm.value;
+ this.userService.add(this.server, newUser)
+ .subscribe((user: User) => {
+ console.log("Done ", user)
+ this.toasterService.success(`User ${user.username} added`);
+ this.dialogRef.close();
+ },
+ (error) => {
+ this.toasterService.error('Cannot create user : ' + error);
+ })
+ }
+}
diff --git a/src/app/components/user-management/user-management.component.html b/src/app/components/user-management/user-management.component.html
index e453d528..4a7d8f47 100644
--- a/src/app/components/user-management/user-management.component.html
+++ b/src/app/components/user-management/user-management.component.html
@@ -1,3 +1,42 @@
-
- user-management works!
-
+
+
+
+
+
+
+
+ Name
+
+ {{ row.username }}
+
+
+
+ Mail
+ {{ row.email }}
+
+
+ Active
+ {{row.is_active}}
+
+
+ Admin
+ {{row.is_superadmin}}
+
+
+ Last Update
+ {{row.updated_at ? row.updated_at : row.created_at}}
+
+
+
+
+
+
+
+
diff --git a/src/app/components/user-management/user-management.component.scss b/src/app/components/user-management/user-management.component.scss
index e69de29b..5819f4a2 100644
--- a/src/app/components/user-management/user-management.component.scss
+++ b/src/app/components/user-management/user-management.component.scss
@@ -0,0 +1,5 @@
+.add-button {
+ height: 40px;
+ width: 160px;
+ margin: 20px;
+}
diff --git a/src/app/components/user-management/user-management.component.ts b/src/app/components/user-management/user-management.component.ts
index a374bb28..c06bd280 100644
--- a/src/app/components/user-management/user-management.component.ts
+++ b/src/app/components/user-management/user-management.component.ts
@@ -1,4 +1,28 @@
-import { Component, OnInit } from '@angular/core';
+/*
+* 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, OnInit, ViewChild} from '@angular/core';
+import {ActivatedRoute, Router} from "@angular/router";
+import {Server} from "@models/server";
+import {MatSort, MatSortable} from "@angular/material/sort";
+import {UserService} from "@services/user.service";
+import {ProgressService} from "../../common/progress/progress.service";
+import {User} from "@models/users/user";
+import {BehaviorSubject, merge, Observable} from "rxjs";
+import {DataSource} from "@angular/cdk/collections";
+import {map} from "rxjs/operators";
+import {AddBlankProjectDialogComponent} from "@components/projects/add-blank-project-dialog/add-blank-project-dialog.component";
+import {AddUserDialogComponent} from "@components/user-management/add-user-dialog/add-user-dialog.component";
+import {MatDialog} from "@angular/material/dialog";
@Component({
selector: 'app-user-management',
@@ -6,10 +30,101 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./user-management.component.scss']
})
export class UserManagementComponent implements OnInit {
+ server: Server;
+ dataSource: UserDataSource;
+ userDatabase = new UserDatabase();
+ displayedColumns = ['name', 'email', 'is_active', 'is_superadmin', 'last'];
- constructor() { }
+ @ViewChild(MatSort, { static: true }) sort: MatSort;
+
+ constructor(
+ private route: ActivatedRoute,
+ private router: Router,
+ private userService: UserService,
+ private progressService: ProgressService,
+ public dialog: MatDialog) { }
ngOnInit() {
+ this.server = this.route.snapshot.data['server'];
+ if (!this.server) this.router.navigate(['/servers']);
+
+ this.refresh();
+ this.sort.sort({
+ id: 'name',
+ start: 'asc',
+ });
+ this.dataSource = new UserDataSource(this.userDatabase, this.sort);
}
+ refresh() {
+ this.userService.list(this.server).subscribe(
+ (users: User[]) => {
+ this.userDatabase.addUsers(users);
+ },
+ (error) => {
+ this.progressService.setError(error);
+ }
+ );
+ }
+
+ addUser() {
+ const dialogRef = this.dialog.open(AddUserDialogComponent, {
+ width: '400px',
+ autoFocus: false,
+ disableClose: true,
+ });
+ let instance = dialogRef.componentInstance;
+ instance.server = this.server;
+ dialogRef.afterClosed().subscribe(() => this.refresh());
+ }
+}
+
+export class UserDatabase {
+ dataChange: BehaviorSubject = new BehaviorSubject([]);
+
+ get data(): User[] {
+ return this.dataChange.value;
+ }
+
+ public addUsers(users: User[]) {
+ this.dataChange.next(users);
+ }
+
+ public remove(user: User) {
+ const index = this.data.indexOf(user);
+ if (index >= 0) {
+ this.data.splice(index, 1);
+ this.dataChange.next(this.data.slice());
+ }
+ }
+}
+
+export class UserDataSource extends DataSource {
+ constructor(public userDatabase: UserDatabase, private sort: MatSort) {
+ super();
+ }
+
+ connect(): Observable {
+ const displayDataChanges = [this.userDatabase.dataChange, this.sort.sortChange];
+
+ return merge(...displayDataChanges).pipe(
+ map(() => {
+ if (!this.sort.active || this.sort.direction === '') {
+ return this.userDatabase.data;
+ }
+
+ return this.userDatabase.data.sort((a, b) => {
+ const propertyA = a[this.sort.active];
+ const propertyB = b[this.sort.active];
+
+ const valueA = isNaN(+propertyA) ? propertyA : +propertyA;
+ const valueB = isNaN(+propertyB) ? propertyB : +propertyB;
+
+ return (valueA < valueB ? -1 : 1) * (this.sort.direction === 'asc' ? 1 : -1);
+ });
+ })
+ );
+ }
+
+ disconnect() {}
}
diff --git a/src/app/layouts/default-layout/default-layout.component.html b/src/app/layouts/default-layout/default-layout.component.html
index 483f6310..ba883a12 100644
--- a/src/app/layouts/default-layout/default-layout.component.html
+++ b/src/app/layouts/default-layout/default-layout.component.html
@@ -23,7 +23,7 @@
settings
Settings
-