refs #435. UX improvements

pull/4/head
Manuel Aranda Rosales 2024-07-15 08:22:31 +02:00
parent 8239aa0d53
commit 604327f453
11 changed files with 170 additions and 73 deletions

View File

@ -57,3 +57,22 @@ mat-card-title {
margin: 0;
}
.loading-spinner {
display: block;
margin: 0 auto;
}
.mat-dialog-content.loading {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.client-form {
width: 100%;
}
.form-field {
width: 100%;
}

View File

@ -20,7 +20,7 @@ interface GroupedClients {
})
export class ClassroomViewComponent implements OnInit {
@Input() clients: any[] = [];
@Input() pcInTable: number = 3;
@Input() pcInTable: number = 5;
groupedClients: GroupedClients[] = [];
constructor(public dialog: MatDialog) {}
@ -43,6 +43,7 @@ export class ClassroomViewComponent implements OnInit {
return acc;
}, {});
console.log(grouped)
this.groupedClients = Object.keys(grouped).map(ouName => ({
organizationalUnitName: ouName,
clientRows: this.chunkArray(grouped[ouName], this.pcInTable)

View File

@ -17,12 +17,14 @@ export class ClientViewComponent {
{property: 'MAC', value: this.data.client.mac},
{property: 'Nº de serie', value: this.data.client.serialNumber},
{property: 'Netiface', value: this.data.client.netiface},
{property: 'Perfil hardware', value: this.data.client.hardwareProfile ? this.data.client.hardwareProfile.description : ''},
{property: 'Menú', value: this.data.client.menu ? this.data.client.menu.description : ''},
{property: 'Fecha de creación', value: this.data.client.createdAt},
{property: 'Creado por', value: this.data.client.createdBy}
];
networkData = [
{property: 'Menu', value: this.data.client.menu},
{property: 'Menú', value: this.data.client.menu ? this.data.client.menu.description : ''},
{property: 'Perfil hardware', value: this.data.client.hardwareProfile ? this.data.client.hardwareProfile.description : ''},
{property: 'OGlive', value: ''},
{property: 'Autoexec', value: ''},
@ -35,19 +37,19 @@ export class ClientViewComponent {
];
classroomData = [
{property: 'Url servidor proxy', value: this.data.client.networkSettings ? this.data.client.networkSettings.proxy : ''},
{property: 'IP DNS', value: this.data.client.networkSettings ? this.data.client.networkSettings.dns : ''},
{property: 'Máscara de red', value: this.data.client.networkSettings ? this.data.client.networkSettings.mask : ''},
{property: 'Router', value: this.data.client.networkSettings ? this.data.client.networkSettings.router : ''},
{property: 'NTP', value: this.data.client.networkSettings ? this.data.client.networkSettings.ntp : ''},
{property: 'Modo p2p', value: this.data.client.networkSettings ? this.data.client.networkSettings.p2pMode : ''},
{property: 'Tiempo p2p', value: this.data.client.networkSettings ? this.data.client.networkSettings.p2pTime : ''},
{property: 'IP multicast', value: this.data.client.networkSettings ? this.data.client.networkSettings.mcastIp : ''},
{property: 'Modo multicast', value: this.data.client.networkSettings ? this.data.client.networkSettings.mcastMode : ''},
{property: 'Puerto multicast', value: this.data.client.networkSettings ? this.data.client.networkSettings.mcastPort : ''},
{property: 'Velocidad multicast', value: this.data.client.networkSettings ? this.data.client.networkSettings.mcastSpeed : ''},
{property: 'Perfil hardware', value: this.data.client.networkSettings && this.data.client.networkSettings.hardwareProfile ? this.data.client.networkSettings.hardwareProfile.description : ''},
{property: 'Menú', value: this.data.client.networkSettings && this.data.client.networkSettings.menu ? this.data.client.networkSettings.menu.description : ''}
{property: 'Url servidor proxy', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.proxy : ''},
{property: 'IP DNS', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.dns : ''},
{property: 'Máscara de red', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.netmask : ''},
{property: 'Router', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.router : ''},
{property: 'NTP', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.ntp : ''},
{property: 'Modo p2p', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.p2pMode : ''},
{property: 'Tiempo p2p', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.p2pTime : ''},
{property: 'IP multicast', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.mcastIp : ''},
{property: 'Modo multicast', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.mcastMode : ''},
{property: 'Puerto multicast', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.mcastPort : ''},
{property: 'Velocidad multicast', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.mcastSpeed : ''},
{property: 'Perfil hardware', value: this.data.client.organizationalUnit.networkSettings && this.data.client.organizationalUnit.networkSettings.hardwareProfile ? this.data.client.organizationalUnit.networkSettings.hardwareProfile.description : ''},
{property: 'Menú', value: this.data.client.organizationalUnit.networkSettings && this.data.client.organizationalUnit.networkSettings.menu ? this.data.client.organizationalUnit.networkSettings.menu.description : ''}
];
constructor(

View File

@ -1,6 +1,7 @@
<h1 mat-dialog-title>Añadir Cliente</h1>
<div class="mat-dialog-content">
<form [formGroup]="clientForm" class="client-form">
<div class="mat-dialog-content" [ngClass]="{'loading': loading}">
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
<form [formGroup]="clientForm" class="client-form" *ngIf="!loading">
<mat-form-field class="form-field">
<mat-label>Padre</mat-label>
<mat-select formControlName="organizationalUnit">

View File

@ -24,6 +24,7 @@ export class CreateClientComponent implements OnInit {
protected netDriverTypes = [
{"name": 'Generic', "value": "generic"},
];
loading:boolean = false
constructor(
private fb: FormBuilder,
@ -47,8 +48,8 @@ export class CreateClientComponent implements OnInit {
netDriver: null,
mac: ['', Validators.required],
ip: ['', Validators.required],
menu: [this.data.organizationalUnit && this.data.organizationalUnit.menu ? this.data.organizationalUnit.menu['@id'] : null],
hardwareProfile: [this.data.organizationalUnit && this.data.organizationalUnit.hardwareProfile ? this.data.organizationalUnit.hardwareProfile['@id'] : null],
menu: [this.data.organizationalUnit && this.data.organizationalUnit.networkSettings.menu ? this.data.organizationalUnit.menu['@id'] : null],
hardwareProfile: [this.data.organizationalUnit && this.data.organizationalUnit.networkSettings.hardwareProfile ? this.data.organizationalUnit.networkSettings.hardwareProfile['@id'] : null],
});
}
@ -64,14 +65,17 @@ export class CreateClientComponent implements OnInit {
}
loadParentUnits() {
this.loading = true
const url = 'http://127.0.0.1:8080/organizational-units?page=1&itemsPerPage=10000';
this.http.get<any>(url).subscribe(
response => {
this.parentUnits = response['hydra:member'];
this.loading = false
},
error => {
console.error('Error fetching parent units:', error);
this.loading = false
}
);
}

View File

@ -36,3 +36,23 @@ button {
.mat-slide-toggle {
margin-top: 20px;
}
.loading-spinner {
display: block;
margin: 0 auto;
}
.mat-dialog-content.loading {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.client-form {
width: 100%;
}
.form-field {
width: 100%;
}

View File

@ -1,6 +1,7 @@
<h1 mat-dialog-title>Editar Cliente</h1>
<div class="mat-dialog-content">
<form [formGroup]="clientForm" class="client-form">
<div class="mat-dialog-content" [ngClass]="{'loading': loading}">
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
<form [formGroup]="clientForm" class="client-form" *ngIf="!loading">
<mat-form-field class="form-field">
<mat-label>Padre</mat-label>
<mat-select formControlName="organizationalUnit">
@ -9,31 +10,31 @@
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>Nombre</mat-label>
<input matInput formControlName="name" >
<input matInput formControlName="name">
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>Número de Serie</mat-label>
<input matInput formControlName="serialNumber" >
<input matInput formControlName="serialNumber">
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>Interfaz de red</mat-label>
<mat-select formControlName="netiface" >
<mat-option *ngFor="let type of netifaceTypes" value="{{ type.value }}">
<mat-select formControlName="netiface">
<mat-option *ngFor="let type of netifaceTypes" [value]="type.value">
{{ type.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>Controlador de red</mat-label>
<mat-select formControlName="netDriver" >
<mat-option *ngFor="let type of netDriverTypes" value="{{ type.value }}">
<mat-select formControlName="netDriver">
<mat-option *ngFor="let type of netDriverTypes" [value]="type.value">
{{ type.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>MAC</mat-label>
<input matInput formControlName="mac" >
<input matInput formControlName="mac">
<mat-error>Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55</mat-error>
</mat-form-field>
<mat-form-field class="form-field">

View File

@ -24,6 +24,7 @@ export class EditClientComponent {
protected netDriverTypes = [
{"name": 'Generic', "value": "generic"},
];
loading:boolean = false
constructor(
private fb: FormBuilder,
@ -80,6 +81,7 @@ export class EditClientComponent {
}
loadData(uuid: string) {
this.loading = true
const url = `http://127.0.0.1:8080/clients/${uuid}`;
this.http.get<any>(url).subscribe(
@ -94,7 +96,9 @@ export class EditClientComponent {
hardwareProfile: data.hardwareProfile ? data.hardwareProfile['@id'] : null,
organizationalUnit: data.organizationalUnit ? data.organizationalUnit['@id'] : null
});
});
this.loading = false
}
);
}
onSubmit() {

View File

@ -16,50 +16,73 @@
</div>
<div class="groupLists-container">
<mat-card class="card unidad-card">
<mat-card-title >Unidad organizativa</mat-card-title>
<mat-card-title>Unidad organizativa</mat-card-title>
<mat-card-content>
<mat-spinner *ngIf="loading"></mat-spinner>
<mat-list *ngIf="!loading">
<mat-list-item *ngFor="let unidad of organizationalUnits"
[ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}" (click)="onSelectUnidad(unidad)">
[ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}" (click)="onSelectUnidad(unidad)">
<div class="item-content">
<mat-icon>apartment</mat-icon>
{{ unidad.name }}
<span class="actions">
<mat-icon
class="edit-icon"
(click)="onTreeClick($event, unidad)"
#tooltip="matTooltip"
matTooltip="Visualizar en forma de arbol"
matTooltipHideDelay="0">account_tree
</mat-icon>
<mat-icon
class="edit-icon"
(click)="onEditClick($event, unidad.type, unidad.uuid)"
#tooltip="matTooltip"
matTooltip="Editar unidad organizativa"
matTooltipHideDelay="0">edit
</mat-icon>
<mat-icon
class="edit-icon"
(click)="onShowClick($event, unidad)"
#tooltip="matTooltip"
matTooltip="Visualizar unidad organizativa"
matTooltipHideDelay="0">visibility
</mat-icon>
<mat-icon
class="edit-icon"
(click)="addOU($event, unidad)"
#tooltip="matTooltip"
matTooltip="Crear unidad organizativa interna"
matTooltipHideDelay="0">add_home_work
</mat-icon>
<mat-icon
class="edit-icon" (click)="addClient($event, unidad)"
#tooltip="matTooltip"
matTooltip="Crear cliente en esta unidad organizativa"
matTooltipHideDelay="0">devices
</mat-icon>
<mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">menu</mat-icon>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="onTreeClick($event, unidad)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Visualizar en forma de arbol"
matTooltipHideDelay="0">account_tree
</mat-icon>
Ver organigrama
</button>
<button mat-menu-item (click)="onEditClick($event, unidad.type, unidad.uuid)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Editar unidad organizativa"
matTooltipHideDelay="0">edit
</mat-icon>
Editar
</button>
<button mat-menu-item (click)="onDeleteClick($event, unidad.uuid, unidad.name, unidad.type)">
<mat-icon
class="delete-icon"
#tooltip="matTooltip"
matTooltip="Borrar unidad organizativa"
matTooltipHideDelay="0">delete
</mat-icon>
Borrar unidad organizativa
</button>
<button mat-menu-item (click)="onShowClick($event, unidad)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Visualizar unidad organizativa"
matTooltipHideDelay="0">visibility
</mat-icon>
Visualizar datos
</button>
<button mat-menu-item (click)="addOU($event, unidad)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Crear unidad organizativa interna"
matTooltipHideDelay="0">add_home_work
</mat-icon>
Añadir unidad organizativa
</button>
<button mat-menu-item (click)="addClient($event, unidad)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Crear cliente en esta unidad organizativa"
matTooltipHideDelay="0">devices
</mat-icon>
Crear cliente
</button>
</mat-menu>
</span>
</div>
</mat-list-item>
@ -98,11 +121,29 @@
</mat-icon>
{{child.name}}
<span class="actions">
<mat-icon class="edit-icon" (click)="onEditClick($event, child.type, child.uuid)">edit</mat-icon>
<mat-icon *ngIf="child.type !== 'client'" class="edit-icon" (click)="onShowClick($event, child)" #tooltip="matTooltip" matTooltip="Visualizar unidad organizativa" matTooltipHideDelay="0">visibility</mat-icon>
<mat-icon *ngIf="child.type !== 'client'" class="edit-icon" (click)="addOU($event, child)" #tooltip="matTooltip" matTooltip="Crear unidad organizativa interna" matTooltipHideDelay="0">add_home_work</mat-icon>
<mat-icon *ngIf="child.type !== 'client'" class="edit-icon" (click)="addClient($event, child)" #tooltip="matTooltip" matTooltip="Crear cliente en esta unidad organizativa" matTooltipHideDelay="0">devices</mat-icon>
<mat-icon class="delete-icon" (click)="onDeleteClick($event, child.uuid, child.name, child.type)" #tooltip="matTooltip" matTooltip="Borrar elemento" matTooltipHideDelay="0">delete</mat-icon>
<mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">menu</mat-icon>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="onEditClick($event, child.type, child.uuid)">
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Editar elemento" matTooltipHideDelay="0">edit</mat-icon>
Editar
</button>
<button *ngIf="child.type !== 'client'" mat-menu-item (click)="onShowClick($event, child)">
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Visualizar unidad organizativa" matTooltipHideDelay="0">visibility</mat-icon>
Visualizar datos
</button>
<button *ngIf="child.type !== 'client'" mat-menu-item (click)="addOU($event, child)">
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Crear unidad organizativa interna" matTooltipHideDelay="0">add_home_work</mat-icon>
Añadir unidad organizativa
</button>
<button *ngIf="child.type !== 'client'" mat-menu-item (click)="addClient($event, child)">
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Crear cliente en esta unidad organizativa" matTooltipHideDelay="0">devices</mat-icon>
Crear cliente
</button>
<button mat-menu-item (click)="onDeleteClick($event, child.uuid, child.name, child.type)">
<mat-icon class="delete-icon" #tooltip="matTooltip" matTooltip="Borrar elemento" matTooltipHideDelay="0">delete</mat-icon>
Borrar elemento
</button>
</mat-menu>
</span>
</div>
</mat-list-item>

View File

@ -160,14 +160,16 @@ constructor(
this.dataService.deleteElement(uuid, type).subscribe(
() => {
this.loadChildrenAndClients(this.selectedUnidad?.id || '');
this.dataService.getOrganizationalUnits().subscribe(
data => this.organizationalUnits = data,
error => console.error('Error fetching unidades organizativas', error)
);
this.openSnackBar(false, 'Entidad eliminada exitosamente')
},
error => console.error('Error deleting element', error)
error => {
console.error('Error deleting element', error)
this.openSnackBar(true, error.error['hydra:description'])
}
);
}
});
@ -201,6 +203,7 @@ constructor(
data => this.organizationalUnits = data,
error => console.error('Error fetching unidades organizativas', error)
);
this.openSnackBar(false, 'Entidad eliminada exitosamente')
},
error => {
console.error('Error deleting element', error)

View File

@ -13,6 +13,7 @@ export class ShowOrganizationalUnitComponent {
generalData = [
{ property: 'Nombre', value: this.data.data.name },
{ property: 'Uuid', value: this.data.data.uuid },
{ property: 'Descripción', value: this.data.data.description },
{ property: 'Comentarios', value: this.data.data.comments },
{ property: 'Tipo', value: this.data.data.type },
{ property: 'Unidad organizativa superior', value: this.data.data.parent ? this.data.data.parent.name : '-' },
@ -27,7 +28,7 @@ export class ShowOrganizationalUnitComponent {
{ property: 'Aforo', value: this.data.data.capacity },
{ property: 'Url servidor proxy', value: this.data.data.networkSettings ? this.data.data.networkSettings.proxy : '' },
{ property: 'IP DNS', value: this.data.data.networkSettings ? this.data.data.networkSettings.dns : '' },
{ property: 'Máscara de red', value: this.data.data.networkSettings ? this.data.data.networkSettings.mask : '' },
{ property: 'Máscara de red', value: this.data.data.networkSettings ? this.data.data.networkSettings.netmask : '' },
{ property: 'Router', value: this.data.data.networkSettings ? this.data.data.networkSettings.router : '' },
{ property: 'NTP', value: this.data.data.networkSettings ? this.data.data.networkSettings.ntp : '' },
{ property: 'Modo p2p', value: this.data.data.networkSettings ? this.data.data.networkSettings.p2pMode : '' },