user management detail refactor

This commit is contained in:
Lebeau Elise 2021-12-16 14:10:28 +00:00 committed by Sylvain MATHIEU
parent cbeca9d0ca
commit c3f3fafbef
11 changed files with 222 additions and 72 deletions

View File

@ -57,6 +57,7 @@ import { ServerResolve } from './resolvers/server-resolve';
import { UserManagementComponent } from './components/user-management/user-management.component';
import { LoggedUserComponent } from './components/users/logged-user/logged-user.component';
import {GroupManagementComponent} from "./components/group-management/group-management.component";
import {UserDetailComponent} from "@components/user-management/user-detail/user-detail.component";
const routes: Routes = [
{
@ -83,6 +84,12 @@ const routes: Routes = [
canActivate: [LoginGuard],
resolve: { server: ServerResolve },
},
{
path: 'server/:server_id/user_management/:user_id',
component: UserDetailComponent,
canActivate: [LoginGuard],
resolve: { server: ServerResolve },
},
{ path: 'installed-software', component: InstalledSoftwareComponent },
{ path: 'server/:server_id/systemstatus', component: SystemStatusComponent, canActivate: [LoginGuard] },

View File

@ -280,6 +280,7 @@ import { GroupFilterPipe } from './filters/group-filter.pipe';
import { AddGroupDialogComponent } from './components/group-management/add-group-dialog/add-group-dialog.component';
import { DeleteGroupDialogComponent } from './components/group-management/delete-group-dialog/delete-group-dialog.component';
import { DeleteUserDialogComponent } from './components/user-management/delete-user-dialog/delete-user-dialog.component';
import { UserDetailComponent } from './components/user-management/user-detail/user-detail.component';
@NgModule({
declarations: [
@ -475,6 +476,7 @@ import { DeleteUserDialogComponent } from './components/user-management/delete-u
UserFilterPipe,
DeleteGroupDialogComponent,
DeleteUserDialogComponent,
UserDetailComponent
],
imports: [
BrowserModule,

View File

@ -1,42 +0,0 @@
<h1 mat-dialog-title>Update user</h1>
<form [formGroup]="editUserForm" class="input-field">
<mat-form-field class="input-field">
<input matInput type="text" formControlName="username" placeholder="Username" />
<mat-error *ngIf="form.username?.touched && form.username?.errors && form.username?.errors.required"
>Username is required</mat-error>
<mat-error *ngIf="form.username?.errors && form.username?.errors.pattern"
>Username is incorrect</mat-error>
<mat-error *ngIf="form.username?.errors && form.username?.errors.userExists"
>User with this username exists</mat-error>
</mat-form-field>
<mat-form-field class="input-field">
<input matInput type="text" formControlName="full_name" placeholder="Full name" />
</mat-form-field>
<mat-form-field class="input-field">
<input matInput type="text" formControlName="email" placeholder="Email" />
<mat-error *ngIf="form.email?.touched && form.email?.errors && form.email?.errors.required"
>Email is required</mat-error>
<mat-error *ngIf="form.email?.errors && form.email?.errors.email"
>Email is invalid</mat-error>
<mat-error *ngIf="form.email?.errors && form.email?.errors.emailExists"
>User with this email exists</mat-error>
</mat-form-field>
<mat-form-field class="input-field">
<input matInput type="password" formControlName="password" placeholder="Password" />
<mat-error *ngIf="form.password?.touched && form.password?.errors"
>Password must be between 6 and 100 characters</mat-error>
</mat-form-field>
<mat-checkbox formControlName="is_active">Is active</mat-checkbox>
<div mat-dialog-actions class="button-div">
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
<button mat-button (click)="onEditClick()" tabindex="2" mat-raised-button color="primary"
[disabled]="!editUserForm.valid">
Edit user
</button>
</div>
</form>

View File

@ -1,8 +0,0 @@
.input-field {
width: 100%;
}
.button-div {
float: right;
}

View File

@ -0,0 +1,74 @@
<div class="content">
<div class="default-header">
<div class="row align-items-center">
<button
mat-icon-button
matTooltip="Back to user management"
matTooltipClass="custom-tooltip"
[routerLink]="['/server', server.id, 'user_management']">
<mat-icon aria-label="Back to user management">keyboard_arrow_left</mat-icon>
</button>
<h1 class="col">User Details</h1>
</div>
</div>
<div class="default-content">
<div class="user-edit">
<h1 mat-dialog-title>Update user</h1>
<div *ngIf="user">
<form [formGroup]="editUserForm" class="input-field">
<mat-form-field class="input-field">
<input matInput type="text" formControlName="username" placeholder="Username" />
<mat-error *ngIf="form.username?.touched && form.username?.errors && form.username?.errors.required"
>Username is required</mat-error>
<mat-error *ngIf="form.username?.errors && form.username?.errors.pattern"
>Username is incorrect</mat-error>
<mat-error *ngIf="form.username?.errors && form.username?.errors.userExists"
>User with this username exists</mat-error>
</mat-form-field>
<mat-form-field class="input-field">
<input matInput type="text" formControlName="full_name" placeholder="Full name" />
</mat-form-field>
<mat-form-field class="input-field">
<input matInput type="text" formControlName="email" placeholder="Email" />
<mat-error *ngIf="form.email?.touched && form.email?.errors && form.email?.errors.required"
>Email is required</mat-error>
<mat-error *ngIf="form.email?.errors && form.email?.errors.email"
>Email is invalid</mat-error>
<mat-error *ngIf="form.email?.errors && form.email?.errors.emailExists"
>User with this email exists</mat-error>
</mat-form-field>
<mat-form-field class="input-field">
<input matInput type="password" formControlName="password" placeholder="Password" />
<mat-error *ngIf="form.password?.touched && form.password?.errors"
>Password must be between 6 and 100 characters</mat-error>
</mat-form-field>
<mat-checkbox formControlName="is_active">Is active</mat-checkbox>
<div mat-dialog-actions class="button-div">
<button mat-button (click)="onEditClick()" tabindex="2" mat-raised-button color="primary"
[disabled]="!editUserForm.valid">
Edit user
</button>
</div>
</form>
</div>
</div>
<div class="user-groups">
<h5>Groups</h5>
<ul>
<li *ngFor="let group of groups">
<a [routerLink]="['/server', server.id, 'group_management', group.user_group_id]"
class="table-link">{{ group.name }}</a>
</li>
</ul>
</div>
</div>
</div>

View File

@ -0,0 +1,16 @@
.input-field {
width: 100%;
}
.button-div {
float: right;
}
.user-edit ,
.user-groups {
flex: 1;
}
.default-content {
display: flex;
}

View File

@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EditUserDialogComponent } from './edit-user-dialog.component';
import { UserDetailComponent } from './user-detail.component';
describe('EditUserDialogComponent', () => {
let component: EditUserDialogComponent;
let fixture: ComponentFixture<EditUserDialogComponent>;
describe('UserDetailComponent', () => {
let component: UserDetailComponent;
let fixture: ComponentFixture<UserDetailComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ EditUserDialogComponent ]
declarations: [ UserDetailComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(EditUserDialogComponent);
fixture = TestBed.createComponent(UserDetailComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

View File

@ -0,0 +1,103 @@
import {Component, Inject, OnInit} from '@angular/core';
import {FormControl, FormGroup, Validators} from "@angular/forms";
import {Group} from "@models/groups/group";
import {UserService} from "@services/user.service";
import {ToasterService} from "@services/toaster.service";
import {User} from "@models/users/user";
import {Server} from "@models/server";
import {userNameAsyncValidator} from "@components/user-management/add-user-dialog/userNameAsyncValidator";
import {userEmailAsyncValidator} from "@components/user-management/add-user-dialog/userEmailAsyncValidator";
import {ActivatedRoute, Router} from "@angular/router";
@Component({
selector: 'app-user-detail',
templateUrl: './user-detail.component.html',
styleUrls: ['./user-detail.component.scss']
})
export class UserDetailComponent implements OnInit {
editUserForm: FormGroup;
groups: Group[];
user: User;
server: Server;
user_id: string;
constructor(public userService: UserService,
private toasterService: ToasterService,
private route: ActivatedRoute,
private router: Router) {
}
ngOnInit(): void {
this.server = this.route.snapshot.data['server'];
if (!this.server) this.router.navigate(['/servers']);
this.user_id = this.route.snapshot.paramMap.get('user_id');
this.userService.get(this.server, this.user_id).subscribe((user: User) => {
console.log(user)
this.user = user;
this.userService.getGroupsByUserId(this.server, this.user.user_id).subscribe(
(groups: Group[]) => {
this.groups = groups;
});
this.initForm();
})
}
initForm() {
this.editUserForm = new FormGroup({
username: new FormControl(this.user.username, [
Validators.required,
Validators.minLength(3),
Validators.pattern("[a-zA-Z0-9_-]+$")],
[userNameAsyncValidator(this.server, this.userService, this.user.username)]),
full_name: new FormControl(this.user.full_name),
email: new FormControl(this.user.email,
[Validators.email, Validators.required],
[userEmailAsyncValidator(this.server, this.userService, this.user.email)]),
password: new FormControl(null,
[Validators.minLength(6), Validators.maxLength(100)]),
is_active: new FormControl(this.user.is_active)
});
}
get form() {
return this.editUserForm.controls;
}
onEditClick() {
if (!this.editUserForm.valid) {
return;
}
const updatedUser = this.getUpdatedValues();
updatedUser['user_id'] = this.user.user_id;
this.userService.update(this.server, updatedUser)
.subscribe((user: User) => {
console.log("Done ", user)
this.toasterService.success(`User ${user.username} updated`);
},
(error) => {
this.toasterService.error('Cannot update user : ' + error);
})
}
getUpdatedValues() {
let dirtyValues = {};
Object.keys(this.editUserForm.controls)
.forEach(key => {
const currentControl = this.editUserForm.get(key);
if (currentControl.dirty && currentControl.value !== this.user[key] && currentControl.value !== '') {
dirtyValues[key] = currentControl.value;
}
});
return dirtyValues;
}
}

View File

@ -38,7 +38,8 @@
<ng-container matColumnDef="username">
<mat-header-cell *matHeaderCellDef mat-sort-header> Username </mat-header-cell>
<mat-cell *matCellDef="let row">
<a class="table-link" [matTooltip]="row.username" (click)="onEdit(row)">{{ row.username }}</a>
<a [routerLink]="['/server', server.id, 'user_management', row.user_id]"
class="table-link" [matTooltip]="row.username">{{ row.username }}</a>
</mat-cell>
</ng-container>
<ng-container matColumnDef="full_name">

View File

@ -13,20 +13,17 @@
import {Component, OnInit, ViewChild} from '@angular/core';
import {ActivatedRoute, Router} from "@angular/router";
import {Server} from "@models/server";
import {MatSort, MatSortable, Sort} from "@angular/material/sort";
import {MatSort} 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, SelectionModel} from "@angular/cdk/collections";
import {map} from "rxjs/operators";
import {SelectionModel} from "@angular/cdk/collections";
import {AddUserDialogComponent} from "@components/user-management/add-user-dialog/add-user-dialog.component";
import {MatDialog} from "@angular/material/dialog";
import {DeleteUserDialogComponent} from "@components/user-management/delete-user-dialog/delete-user-dialog.component";
import {ToasterService} from "@services/toaster.service";
import {MatPaginator} from "@angular/material/paginator";
import {MatTableDataSource} from "@angular/material/table";
import {EditUserDialogComponent} from "@components/user-management/edit-user-dialog/edit-user-dialog.component";
@Component({
selector: 'app-user-management',
@ -144,13 +141,4 @@ export class UserManagementComponent implements OnInit {
});
}
onEdit(user: User) {
this.dialog
.open(EditUserDialogComponent, {width: '500px', data: {user: user, server: this.server}})
.afterClosed()
.subscribe(() => {
this.refresh();
});
}
}

View File

@ -4,6 +4,7 @@ import { Server } from '../models/server';
import { HttpServer } from './http-server.service';
import { User } from '../models/users/user';
import {Project} from "@models/project";
import {Group} from "@models/groups/group";
@Injectable()
export class UserService {
@ -15,6 +16,10 @@ export class UserService {
return this.httpServer.get<User>(server, '/users/me/');
}
get(server:Server, user_id: string) {
return this.httpServer.get<User>(server, `/users/${user_id}`);
}
list(server: Server) {
return this.httpServer.get<User[]>(server, '/users');
}
@ -27,7 +32,11 @@ export class UserService {
return this.httpServer.delete(server, `/users/${user_id}`);
}
update(server: Server, user: User): Observable<User> {
update(server: Server, user: any): Observable<User> {
return this.httpServer.put<User>(server, `/users/${user.user_id}`, user);
}
getGroupsByUserId(server: Server, user_id: string) {
return this.httpServer.get<Group[]>(server, `/users/${user_id}/groups`);
}
}