refs #1639. Enhance user modal for add/edit functionality and improve password change dialog
testing/ogGui-multibranch/pipeline/head This commit looks good Details

pull/13/head
Lucas Lara García 2025-03-05 13:25:22 +01:00
parent 9b67d6ef43
commit 5907404f77
13 changed files with 48 additions and 26 deletions

View File

@ -1,6 +1,6 @@
<app-loading [isLoading]="loading"></app-loading>
<h1 mat-dialog-title>{{ 'dialogTitleAddUser' | translate }}</h1>
<h1 mat-dialog-title>{{ isEditMode ? ('dialogTitleEditUser' | translate) : ('dialogTitleAddUser' | translate) }}</h1>
<mat-dialog-content class="form-container">
<form [formGroup]="userForm" class="user-form">
<mat-form-field appearance="fill" class="full-width">
@ -29,10 +29,11 @@
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill" class="full-width">
<mat-label>Vista tarjetas</mat-label>
<mat-select formControlName="groupsView" required>
<mat-option *ngFor="let option of views" [value]="option.value" >
<mat-option *ngFor="let option of views" [value]="option.value">
{{ option.name }}
</mat-option>
</mat-select>
@ -41,5 +42,5 @@
</mat-dialog-content>
<mat-dialog-actions class="action-container">
<button class="ordinary-button" (click)="onNoClick()">{{ 'buttonCancel' | translate }}</button>
<button class="submit-button" (click)="onSubmit()">{{ 'buttonAdd' | translate }}</button>
</mat-dialog-actions>
<button class="submit-button" (click)="onSubmit()" [disabled]="userForm.invalid">{{ isEditMode ? ('buttonEdit' | translate) : ('buttonAdd' | translate) }}</button>
</mat-dialog-actions>

View File

@ -1,9 +1,9 @@
import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import {ToastrService} from "ngx-toastr";
import {HttpClient} from "@angular/common/http";
import {DataService} from "../data.service";
import { ToastrService } from "ngx-toastr";
import { HttpClient } from "@angular/common/http";
import { DataService } from "../data.service";
interface UserGroup {
'@id': string;
@ -19,15 +19,17 @@ interface UserGroup {
export class AddUserModalComponent implements OnInit {
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
@Output() userAdded = new EventEmitter<void>();
@Output() userEdited = new EventEmitter<void>();
userForm: FormGroup<any>;
userGroups: UserGroup[] = [];
organizationalUnits: any[] = [];
userId: string | null = null;
loading: boolean = false;
isEditMode: boolean = false;
protected views = [
{value: 'card', name: 'Tarjetas'},
{value: 'list', name: 'Listado'},
{ value: 'card', name: 'Tarjetas' },
{ value: 'list', name: 'Listado' },
];
constructor(
@ -45,6 +47,10 @@ export class AddUserModalComponent implements OnInit {
groupsView: ['card', Validators.required],
organizationalUnits: [[]]
});
if (data) {
this.isEditMode = true;
}
}
ngOnInit(): void {
@ -114,6 +120,7 @@ export class AddUserModalComponent implements OnInit {
this.http.put(`${this.baseUrl}${this.userId}`, payload).subscribe(
(response) => {
this.toastService.success('Usuario editado correctamente');
this.userEdited.emit();
this.dialogRef.close();
this.loading = false;
},
@ -126,6 +133,7 @@ export class AddUserModalComponent implements OnInit {
this.http.post(`${this.baseUrl}/users`, payload).subscribe(
(response) => {
this.toastService.success('Usuario añadido correctamente');
this.userAdded.emit();
this.dialogRef.close();
this.loading = false;
},
@ -137,4 +145,4 @@ export class AddUserModalComponent implements OnInit {
}
}
}
}
}

View File

@ -1,6 +1,5 @@
.user-form .form-field {
display: block;
margin-bottom: 10px;
}
.checkbox-group label {
@ -23,4 +22,8 @@ mat-spinner {
justify-content: flex-end;
gap: 1em;
padding: 1.5em;
}
.form-container {
margin-top: 2em;
}

View File

@ -1,4 +1,4 @@
<h1 mat-dialog-title>{{ 'dialogTitleEditUser' | translate }}</h1>
<h1 mat-dialog-title>{{ 'dialogTitleChangePassword' | translate }}</h1>
<mat-dialog-content class="form-container">
<form [formGroup]="userForm" class="user-form">
<mat-form-field class="form-field">

View File

@ -9,7 +9,6 @@
</div>
</div>
<div class="search-container">
<mat-form-field appearance="fill" class="search-string">
<mat-label>{{ 'searchLabel' | translate }}</mat-label>
@ -32,10 +31,10 @@
{{ user[column.columnDef] === 'card' ? 'Vista tarjetas' : 'Listado' }}
</mat-chip>
</ng-container>
<ng-container *ngIf="column.columnDef !== 'groupsView'" >
<ng-container *ngIf="column.columnDef !== 'groupsView'">
{{ column.cell(user) }}
</ng-container>
</td>
</ng-container>
</td>
</ng-container>
<ng-container matColumnDef="actions">
@ -58,4 +57,4 @@
<mat-paginator [length]="length" [pageSize]="itemsPerPage" [pageIndex]="page" [pageSizeOptions]="pageSizeOptions"
(page)="onPageChange($event)">
</mat-paginator>
</div>
</div>

View File

@ -92,6 +92,10 @@ export class UsersComponent implements OnInit {
data: user['@id']
});
dialogRef.componentInstance.userEdited.subscribe(() => {
this.search();
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
this.search();
@ -129,4 +133,4 @@ export class UsersComponent implements OnInit {
this.length = event.length;
this.search();
}
}
}

View File

@ -61,11 +61,11 @@
</mat-form-field>
<mat-form-field class="form-field search-select" appearance="outline">
<mat-select placeholder="Buscar por estado..." #clientSearchStatusInput (selectionChange)="onClientFilterStatusInput($event.value)">
<mat-option *ngFor="let option of status" [value]="option.value" >
<mat-option *ngFor="let option of status" [value]="option.value">
{{ option.name }}
</mat-option>
</mat-select>
<button mat-icon-button matSuffix aria-label="Clear tree search" (click)="clearStatusFilter($event)">
<button *ngIf="clientSearchStatusInput.value" mat-icon-button matSuffix aria-label="Clear tree search" (click)="clearStatusFilter($event, clientSearchStatusInput)">
<mat-icon>close</mat-icon>
</button>
</mat-form-field>

View File

@ -123,6 +123,9 @@ describe('GroupsComponent', () => {
spyOn(component['http'], 'get').and.callThrough();
component.fetchClientsForNode(node);
expect(component.isLoadingClients).toBeTrue();
expect(component['http'].get).toHaveBeenCalledWith(`${component.baseUrl}/clients?organizationalUnit.id=${node.id}&page=1&itemsPerPage=20`);
expect(component['http'].get).toHaveBeenCalledWith(
`${component.baseUrl}/clients?organizationalUnit.id=${node.id}&page=1&itemsPerPage=20`,
{ params: jasmine.any(Object) }
);
});
});

View File

@ -758,9 +758,10 @@ export class GroupsComponent implements OnInit, OnDestroy {
this.filterClients('');
}
clearStatusFilter(event: Event): void {
clearStatusFilter(event: Event, clientSearchStatusInput: any): void {
event.stopPropagation();
delete this.filters['status'];
clientSearchStatusInput.value = null;
this.fetchClientsForNode(this.selectedNode);
}
}

View File

@ -21,7 +21,7 @@
<button class="ordinary-button" *ngIf="!isSuperAdmin" (click)="editUser()" i18n="@@editUser"
matTooltip="Editar tu información de usuario" matTooltipShowDelay="1000">
Editar usuario
Cambiar contraseña
</button>
<button class="logout-button" routerLink="/auth/login" i18n="@@logout"

View File

@ -21,7 +21,8 @@
"buttonAdd": "Add",
"addButton": "Add",
"addClientDialogTitle": "Add Client",
"dialogTitleEditUser": "Edit User",
"dialogTitleEditUser": "Editar usuario",
"dialogTitleChangePassword": "Change password",
"labelCurrentPassword": "Current password",
"labelNewPassword": "New password",
"labelRepeatPassword": "Repeat password",

View File

@ -21,7 +21,8 @@
"buttonAdd": "Add",
"addButton": "Add",
"addClientDialogTitle": "Add Client",
"dialogTitleEditUser": "Edit User",
"dialogTitleEditUser": "Editar usuario",
"dialogTitleChangePassword": "Change password",
"labelCurrentPassword": "Current password",
"labelNewPassword": "New password",
"labelRepeatPassword": "Repeat password",

View File

@ -21,7 +21,8 @@
"buttonAdd": "Añadir",
"addButton": "Añadir",
"addClientDialogTitle": "Añadir Cliente",
"dialogTitleEditUser": "Editar Usuario",
"dialogTitleEditUser": "Editar usuario",
"dialogTitleChangePassword": "Change password",
"labelCurrentPassword": "Contraseña actual",
"labelNewPassword": "Nueva contraseña",
"labelRepeatPassword": "Repite la contraseña",