From f016c66d559c2b0b8b821cef6fa8e1da57f8c93a Mon Sep 17 00:00:00 2001 From: Lucas Lara Date: Wed, 23 Apr 2025 14:22:12 +0200 Subject: [PATCH] refs #1931 Refactor ClientMainViewComponent and related files: remove component and styles, update routing, and adjust dialog dimensions for improved client detail display --- ogWebconsole/src/app/app-routing.module.ts | 3 - ogWebconsole/src/app/app.module.ts | 2 - .../client-main-view.component.css | 351 ------------------ .../client-main-view.component.html | 71 ---- .../client-main-view.component.ts | 313 ---------------- .../app/components/groups/groups.component.ts | 2 +- .../client-details.component.css | 26 +- .../client-details.component.html | 3 +- ogWebconsole/src/locale/en.json | 2 +- ogWebconsole/src/locale/es.json | 2 +- 10 files changed, 22 insertions(+), 753 deletions(-) delete mode 100644 ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.css delete mode 100644 ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.html delete mode 100644 ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.ts diff --git a/ogWebconsole/src/app/app-routing.module.ts b/ogWebconsole/src/app/app-routing.module.ts index cbd353a..3a0ca83 100644 --- a/ogWebconsole/src/app/app-routing.module.ts +++ b/ogWebconsole/src/app/app-routing.module.ts @@ -18,8 +18,6 @@ import { CommandsComponent } from './components/commands/main-commands/commands. import { CommandsGroupsComponent } from './components/commands/commands-groups/commands-groups.component'; import { CommandsTaskComponent } from './components/commands/commands-task/commands-task.component'; import { TaskLogsComponent } from './components/commands/commands-task/task-logs/task-logs.component'; -import { ClientMainViewComponent } from './components/groups/components/client-main-view/client-main-view.component'; -import { ImagesComponent } from './components/images/images.component'; import {SoftwareComponent} from "./components/software/software.component"; import {SoftwareProfileComponent} from "./components/software-profile/software-profile.component"; import {OperativeSystemComponent} from "./components/operative-system/operative-system.component"; @@ -67,7 +65,6 @@ const routes: Routes = [ { path: 'clients/deploy-image', component: DeployImageComponent }, { path: 'clients/partition-assistant', component: PartitionAssistantComponent }, { path: 'clients/run-script', component: RunScriptAssistantComponent }, - { path: 'clients/:id', component: ClientMainViewComponent }, { path: 'clients/:id/create-image', component: CreateClientImageComponent }, { path: 'repositories', component: RepositoriesComponent }, { path: 'repository/:id', component: MainRepositoryViewComponent }, diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts index 2b1fa14..a356d2e 100644 --- a/ogWebconsole/src/app/app.module.ts +++ b/ogWebconsole/src/app/app.module.ts @@ -89,7 +89,6 @@ import { CreateTaskComponent } from './components/commands/commands-task/create- import { DetailTaskComponent } from './components/commands/commands-task/detail-task/detail-task.component'; import { TaskLogsComponent } from './components/commands/commands-task/task-logs/task-logs.component'; import { MatSliderModule } from '@angular/material/slider'; -import { ClientMainViewComponent } from './components/groups/components/client-main-view/client-main-view.component'; import { ImagesComponent } from './components/images/images.component'; import { CreateImageComponent } from './components/images/create-image/create-image.component'; import { CreateClientImageComponent } from './components/groups/components/client-main-view/create-image/create-image.component'; @@ -205,7 +204,6 @@ registerLocaleData(localeEs, 'es-ES'); TaskLogsComponent, ServerInfoDialogComponent, StatusComponent, - ClientMainViewComponent, ImagesComponent, CreateImageComponent, PartitionAssistantComponent, diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.css b/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.css deleted file mode 100644 index 664c4d0..0000000 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.css +++ /dev/null @@ -1,351 +0,0 @@ -.header-container { - display: flex; - justify-content: space-between; - align-items: center; - padding: 10px; -} - -.client-container { - flex-grow: 1; - box-sizing: border-box; - overflow: hidden; - display: flex; - flex-direction: column; - padding: 0rem 1rem 0rem 0.5rem; -} - -.client-icon { - flex-shrink: 0; - margin-right: 20px; - display: flex; - align-items: center; - justify-content: center; - min-width: 120px; - min-height: 120px; -} - -.row-container { - justify-content: space-between; - width: 100%; -} - -.table-container { - padding-right: 10px; -} - -.charts-wrapper { - width: 100%; - margin-top: 20px; -} - -.charts-row { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - gap: 20px; -} - -.disk-usage { - text-align: center; - flex: 1; - min-width: 200px; -} - -.circular-chart { - max-width: 150px; - max-height: 150px; - margin: 0 auto; -} - -.chart { - display: flex; - justify-content: center; -} - -.icon-pc { - font-size: 25px; - color: #3b82f6; -} - -.client-title h1 { - font-size: 2rem; - margin-bottom: 10px; -} - -.client-title p { - margin: 2px 0; - font-size: 1rem; - color: #666; -} - -.client-info { - margin: 20px 0; - border-radius: 12px; - background-color: #f5f7fa; - padding: 20px; - border: 2px solid #d1d9e6; - box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1); -} - -.info-section { - background-color: #fff; - border-radius: 12px; -} - -.two-column-table { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 10px; - margin-top: 15px; -} - -.mat-elevation-z8 { - box-shadow: 0px 0px 0px rgba(0, 0, 0, 0.2); -} - -.table-row { - display: flex; - justify-content: space-between; - padding: 10px; - border-bottom: 1px solid #e0e0e0; -} - -.column.property { - font-weight: bold; - text-align: left; - width: 45%; -} - -.column.value { - text-align: right; - width: 45%; -} - -.mat-tab-group { - min-height: 400px; -} - -.mat-tab-body-wrapper { - min-height: inherit; -} - -.info-section h2 { - font-size: 1.4rem; - margin-bottom: 10px; - color: #0056b3; -} - -.info-section p { - font-size: 1rem; - margin: 5px 0; -} - -.second-section { - display: grid; - gap: 20px; -} - -.client-button-row { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - gap: 20px; -} - -.buttons-row { - display: flex; - flex-direction: column; - background-color: #fff; - padding: 20px; - border-radius: 12px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); - justify-content: flex-start; -} - -.buttons-row button { - margin-bottom: 10px; - width: 100%; -} - -.circular-chart { - display: block; - margin: 0 auto; - max-width: 100%; - max-height: 150px; -} - -.circle-bg { - fill: none; - stroke: #f0f0f0; - stroke-width: 3.8; -} - -.circle { - fill: none; - stroke-width: 3.8; - stroke: #00bfa5; - stroke-linecap: round; - animation: progress 1s ease-out forwards; -} - -.percentage { - fill: #333; - font-size: 0.7rem; - text-anchor: middle; -} - -.disk-usage h3 { - margin: 0 0 10px 0; - font-size: 1.2rem; - color: #333; -} - -@keyframes progress { - 0% { - stroke-dasharray: 0, 100; - } -} - -.assistants-container { - background-color: #fff; - margin-top: 10px; - padding: 20px; - border-radius: 12px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); -} - -.circular-chart { - display: block; - margin: 0 auto; - max-width: 100%; - max-height: 150px; -} - -.circle-bg { - fill: none; - stroke: #f0f0f0; - stroke-width: 3.8; -} - -.circle { - fill: none; - stroke-width: 3.8; - stroke-linecap: round; - animation: progress 1s ease-out forwards; -} - -.partition-0 { - stroke: #00bfa5; -} - -.partition-1 { - stroke: #ff6f61; -} - -.partition-2 { - stroke: #ffb400; -} - -.partition-3 { - stroke: #3498db; -} - -.percentage { - fill: #333; - font-size: 0.7rem; - text-anchor: middle; -} - -.disk-container { - display: flex; - flex-direction: row; - gap: 20px; - background-color: #f5f7fa; - border: 2px solid #d1d9e6; - border-radius: 10px; - padding: 20px; - margin-top: 20px; - box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1); - flex-wrap: wrap; - justify-content: center; - align-items: stretch; - margin-bottom: 20px; -} - -.table-container { - flex: 3; - display: flex; - justify-content: center; - align-items: center; -} - -table.mat-elevation-z8 { - width: 100%; - max-width: 800px; - background-color: white; - border-radius: 8px; - overflow: hidden; -} - -.mat-header-cell { - background-color: #d1d9e6 !important; - color: #333; - font-weight: bold; - text-align: center; -} - -.mat-cell { - text-align: center; -} - -.mat-chip { - font-weight: bold; - color: white; -} - -.charts-container { - flex: 2; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} - -.disk-usage { - background-color: white; - padding: 15px; - border-radius: 8px; - justify-self: center; - box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1); - text-align: center; -} - -.chart { - display: flex; - justify-content: center; -} - -.back-button { - display: flex; - align-items: center; - gap: 5px; - margin-left: 0.5em; - background-color: #3f51b5; - color: white; - padding: 8px 18px 8px 8px; - border: none; - border-radius: 4px; - cursor: pointer; - font-size: 16px; - transition: transform 0.3s ease; - font-family: Roboto, "Helvetica Neue", sans-serif; -} - -.back-button:hover:not(:disabled) { - background-color: #485ac0d7; -} - -.back-button:disabled { - background-color: #ced0df; - cursor: not-allowed; -} diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.html b/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.html deleted file mode 100644 index f0c7970..0000000 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.html +++ /dev/null @@ -1,71 +0,0 @@ - - -
-
-

{{ 'clientDetailsTitle' | translate }} {{ clientData.name }}

-
- -
-
- - - -
-
-
-
-
{{ clientData?.property }}
-
{{ clientData?.value }}
-
-
-
-
-
{{ clientData?.property }}
-
{{ clientData?.value }}
-
-
-
-
-
-

Discos/Particiones

-
- -
-
- - - - - - - -
{{ column.header }} - - {{ column.cell(image) }} - - - - {{ (image.size / 1024).toFixed(2) }} GB - - -
-
- -
- -
- - - -

Disco {{ disk.diskNumber }}

-

Usado: {{ (disk.used).toFixed(2) }} GB ({{ disk.percentage }}%)

-

Total: {{ disk.total }} GB

-
-
-
-
-
- diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.ts b/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.ts deleted file mode 100644 index bf77392..0000000 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.ts +++ /dev/null @@ -1,313 +0,0 @@ -import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { DatePipe } from "@angular/common"; -import { MatTableDataSource } from "@angular/material/table"; -import { MatDialog } from "@angular/material/dialog"; -import { Router } from "@angular/router"; -import { ToastrService } from "ngx-toastr"; -import { ManageClientComponent } from "../../shared/clients/manage-client/manage-client.component"; -import { ConfigService } from '@services/config.service'; - -interface ClientInfo { - property: string; - value: any; -} - -@Component({ - selector: 'app-client-main-view', - templateUrl: './client-main-view.component.html', - styleUrl: './client-main-view.component.css' -}) -export class ClientMainViewComponent implements OnInit { - baseUrl: string; - @ViewChild('assistantContainer') assistantContainer!: ElementRef; - clientUuid: string; - clientData: any = {}; - isPartitionAssistantVisible: boolean = false; - isBootImageVisible: boolean = false; - isDiskUsageVisible: boolean = true; - dataSource = new MatTableDataSource(); - generalData: ClientInfo[] = []; - networkData: ClientInfo[] = []; - classroomData: ClientInfo[] = []; - diskUsageData: any[] = []; - partitions: any[] = []; - commands: any[] = []; - chartDisk: any[] = []; - view: [number, number] = [300, 200]; - showLegend: boolean = true; - - arrayCommands: any[] = [ - { name: 'Enceder', slug: 'power-on' }, - { name: 'Apagar', slug: 'power-off' }, - { name: 'Reiniciar', slug: 'reboot' }, - { name: 'Iniciar Sesión', slug: 'login' }, - { name: 'Crear imagen', slug: 'create-image' }, - { name: 'Clonar/desplegar imagen', slug: 'deploy-image' }, - { name: 'Eliminar Imagen Cache', slug: 'delete-image-cache' }, - { name: 'Particionar y Formatear', slug: 'partition' }, - { name: 'Inventario Software', slug: 'software-inventory' }, - { name: 'Inventario Hardware', slug: 'hardware-inventory' }, - { name: 'Ejecutar comando', slug: 'run-script' }, - ]; - - datePipe: DatePipe = new DatePipe('es-ES'); - columns = [ - { - columnDef: 'diskNumber', - header: 'Disco', - cell: (partition: any) => `${partition.diskNumber}`, - }, - { - columnDef: 'partitionNumber', - header: 'Particion', - cell: (partition: any) => `${partition.partitionNumber}` - }, - { - columnDef: 'description', - header: 'Sistema de ficheros', - cell: (partition: any) => `${partition.filesystem}` - }, - { - columnDef: 'size', - header: 'Tamaño', - cell: (partition: any) => `${(partition.size / 1024).toFixed(2)} GB` - }, - { - columnDef: 'memoryUsage', - header: 'Uso', - cell: (partition: any) => `${partition.memoryUsage} %` - }, - { - columnDef: 'operativeSystem', - header: 'SO', - cell: (partition: any) => `${partition.operativeSystem?.name}` - }, - ]; - displayedColumns = [...this.columns.map(column => column.columnDef)]; - isDiskUsageEmpty: boolean = true; - loading: boolean = true; - - constructor( - private http: HttpClient, - private dialog: MatDialog, - private configService: ConfigService, - private router: Router, - private toastService: ToastrService - ) { - this.baseUrl = this.configService.apiUrl; - const url = window.location.href; - const segments = url.split('/'); - this.clientUuid = segments[segments.length - 1]; - } - - ngOnInit() { - this.clientData = history.state.clientData['@id']; - this.loadClient(this.clientData) - this.loadCommands() - this.calculateDiskUsage(); - this.loading = false; - } - - - loadClient = (uuid: string) => { - this.http.get(`${this.baseUrl}${uuid}`).subscribe({ - next: data => { - this.clientData = data; - this.updateGeneralData(); - this.updateNetworkData(); - this.loadPartitions() - this.loading = false; - }, - error: error => { - console.error('Error al obtener el cliente:', error); - } - }); - } - - navigateToGroups() { - this.router.navigate(['/groups']); - } - - updateGeneralData() { - this.generalData = [ - { property: 'Nombre', value: this.clientData?.name || '' }, - { property: 'IP', value: this.clientData?.ip || '' }, - { property: 'MAC', value: this.clientData?.mac || '' }, - { property: 'Nº de serie', value: this.clientData?.serialNumber || '' }, - { property: 'Netiface', value: this.clientData?.netiface || this.clientData?.organizationalUnit?.networkSettings?.netiface || '' }, - { property: 'Perfil hardware', value: this.clientData?.hardwareProfile?.description || '' }, - ]; - } - - updateNetworkData() { - this.networkData = [ - { property: 'Padre', value: this.clientData?.organizationalUnit?.name || '' }, - { property: 'Pxe', value: this.clientData?.template?.name || '' }, - { property: 'Remote Pc', value: this.clientData.remotePc || '' }, - { property: 'Subred', value: this.clientData?.subnet || '' }, - { property: 'OGlive', value: this.clientData?.ogLive?.name || '' }, - { property: 'Repositorio', value: this.clientData?.repository?.name || '' }, - ]; - } - - calculateDiskUsage() { - const diskUsageMap = new Map(); - - this.partitions.forEach((partition: any) => { - const diskNumber = partition.diskNumber; - - if (!diskUsageMap.has(diskNumber)) { - diskUsageMap.set(diskNumber, { total: 0, used: 0, partitions: [] }); - } - - const diskData = diskUsageMap.get(diskNumber); - - if (partition.partitionNumber === 0) { - diskData!.total = Number((partition.size / 1024).toFixed(2)); - } else { - diskData!.used += Number((partition.size / 1024).toFixed(2)); - diskData!.partitions.push(partition); - } - }); - - this.chartDisk = Array.from(diskUsageMap.entries()).map(([diskNumber, { total, used, partitions }]) => { - const partitionData = partitions.map(partition => ({ - name: `Partición ${partition.partitionNumber}`, - value: Number((partition.size / 1024).toFixed(2)) - })); - - const freeSpace = total - used; - if (freeSpace > 0) { - partitionData.push({ - name: 'Espacio libre', - value: Number(freeSpace.toFixed(2)) - }); - } - - return { - diskNumber, - chartData: partitionData, - total, - used, - percentage: total > 0 ? Math.round((used / total) * 100) : 0 - }; - }); - - this.diskUsageData = this.chartDisk; - this.isDiskUsageEmpty = this.diskUsageData.length === 0; - } - - onEditClick(event: MouseEvent, uuid: string): void { - event.stopPropagation(); - const dialogRef = this.dialog.open(ManageClientComponent, { data: { uuid }, width: '900px' }); - dialogRef.afterClosed().subscribe(); - } - - loadPartitions(): void { - this.http.get(`${this.baseUrl}/partitions?client.id=${this.clientData?.id}&order[diskNumber, partitionNumber]=ASC`).subscribe({ - next: data => { - const filteredPartitions = data['hydra:member'].filter((partition: any) => partition.partitionNumber !== 0); - this.dataSource = filteredPartitions; - this.partitions = filteredPartitions; - this.calculateDiskUsage(); - }, - error: error => { - console.error('Error al obtener las particiones:', error); - } - }); - } - - - loadCommands(): void { - this.http.get(`${this.baseUrl}/commands?`).subscribe({ - next: data => { - this.commands = data['hydra:member']; - }, - error: error => { - console.error('Error al obtener las particiones:', error); - } - }); - } - - onCommandSelect(action: any): void { - if (action === 'partition') { - this.openPartitionAssistant(); - } - - if (action === 'create-image') { - this.openCreateImageAssistant(); - } - - if (action === 'deploy-image') { - this.openDeployImageAssistant(); - } - - if (action === 'reboot') { - this.rebootClient(); - } - - if (action === 'power-off') { - this.powerOffClient(); - } - - if (action === 'power-on') { - this.powerOnClient(); - } - } - - rebootClient(): void { - this.http.post(`${this.baseUrl}/clients/server/${this.clientData.uuid}/reboot`, {}).subscribe( - response => { - this.toastService.success('Cliente actualizado correctamente'); - }, - error => { - this.toastService.error('Error de conexión con el cliente'); - } - ); - } - - powerOnClient(): void { - const payload = { - client: this.clientData['@id'] - } - - this.http.post(`${this.baseUrl}${this.clientData.repository['@id']}/wol`, payload).subscribe( - response => { - this.toastService.success('Cliente actualizado correctamente'); - }, - error => { - this.toastService.error('Error de conexión con el cliente'); - } - ); - } - - powerOffClient(): void { - this.http.post(`${this.baseUrl}/clients/server/${this.clientData.uuid}/power-off`, {}).subscribe( - response => { - this.toastService.success('Cliente actualizado correctamente'); - }, - error => { - this.toastService.error('Error de conexión con el cliente'); - } - ); - } - - openPartitionAssistant(): void { - this.router.navigate([`/clients/${this.clientData.uuid}/partition-assistant`]).then(r => { - console.log('navigated', r); - }); - } - - openCreateImageAssistant(): void { - this.router.navigate([`/clients/${this.clientData.uuid}/create-image`]).then(r => { - console.log('navigated', r); - }); - } - - openDeployImageAssistant(): void { - this.router.navigate([`/clients/deploy-image`]).then(r => { - console.log('navigated', r); - }); - } -} diff --git a/ogWebconsole/src/app/components/groups/groups.component.ts b/ogWebconsole/src/app/components/groups/groups.component.ts index 0c537b1..875c02f 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.ts +++ b/ogWebconsole/src/app/components/groups/groups.component.ts @@ -611,7 +611,7 @@ export class GroupsComponent implements OnInit, OnDestroy { onShowClientDetail(event: MouseEvent, client: Client): void { event.stopPropagation(); this.dialog.open(ClientDetailsComponent, { - width: '600px', + width: '900px', data: { clientData: client }, }) } diff --git a/ogWebconsole/src/app/components/groups/shared/client-details/client-details.component.css b/ogWebconsole/src/app/components/groups/shared/client-details/client-details.component.css index b408c18..3e0ba22 100644 --- a/ogWebconsole/src/app/components/groups/shared/client-details/client-details.component.css +++ b/ogWebconsole/src/app/components/groups/shared/client-details/client-details.component.css @@ -4,19 +4,19 @@ background-color: #fff; display: flex; flex-direction: column; + padding: 1em 4em 2em 4em; } -.section-header { - margin-bottom: 8px; +.title { + margin-bottom: 1.5em; } .client-info-card { - background-color: #e4e4e4; + background-color: #f1f1f1; padding: 24px; border-radius: 12px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05); - margin-bottom: 2em; - margin-top: 1.5em; + margin-bottom: 60px; } .info-columns { @@ -58,8 +58,7 @@ overflow-x: auto; border-radius: 8px; background: #fff; - padding: 16px; - box-shadow: 0 2px 6px rgba(0,0,0,0.05); + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05); } .mat-elevation-z8 { @@ -73,16 +72,25 @@ gap: 24px; } +.charts-container.single-disk { + justify-content: center; +} + +.charts-container.single-disk .disk-usage { + max-width: 400px; + flex: 0 1 auto; +} + .disk-usage { flex: 1 1 300px; padding: 16px; background: #f9f9f9; border-radius: 12px; - box-shadow: 0 2px 6px rgba(0,0,0,0.05); + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05); } .chart { width: 100%; height: 200px; margin-bottom: 12px; -} +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/client-details/client-details.component.html b/ogWebconsole/src/app/components/groups/shared/client-details/client-details.component.html index 1238980..4e1e5e0 100644 --- a/ogWebconsole/src/app/components/groups/shared/client-details/client-details.component.html +++ b/ogWebconsole/src/app/components/groups/shared/client-details/client-details.component.html @@ -48,7 +48,7 @@ -
+
@@ -59,6 +59,7 @@
+
\ No newline at end of file diff --git a/ogWebconsole/src/locale/en.json b/ogWebconsole/src/locale/en.json index 6bc649a..daaae76 100644 --- a/ogWebconsole/src/locale/en.json +++ b/ogWebconsole/src/locale/en.json @@ -272,7 +272,7 @@ "classroomOption": "Classroom", "clientsGroupOption": "PC Groups", "roomMapOption": "Classroom map", - "clientDetailsTitle": "Client details", + "clientDetailsTitle": "Details of", "commandsButton": "Commands", "networkPropertiesTab": "Network properties", "disksPartitionsTitle": "Disks/Partitions", diff --git a/ogWebconsole/src/locale/es.json b/ogWebconsole/src/locale/es.json index fb6d793..d02bddb 100644 --- a/ogWebconsole/src/locale/es.json +++ b/ogWebconsole/src/locale/es.json @@ -276,7 +276,7 @@ "classroomOption": "Aula", "clientsGroupOption": "Grupos de PCs", "roomMapOption": "Plano de aula", - "clientDetailsTitle": "Datos de cliente", + "clientDetailsTitle": "Datos de", "commandsButton": "Comandos", "excludeParentChanges": "Excluir cambios de las unidades organizativas superiores", "networkPropertiesTab": "Propiedades de red",