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 index 897d6e4..0dad576 100644 --- 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 @@ -1,3 +1,10 @@ +.header-container { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px; +} + .client-header { display: flex; align-items: center; @@ -14,10 +21,49 @@ display: flex; align-items: center; justify-content: center; - min-width: 120px; + 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; /* Distribuye el espacio entre los gráficos */ + gap: 20px; /* Añade espacio entre los gráficos */ +} + +.disk-usage { + text-align: center; + flex: 1; + min-width: 200px; /* Ajusta este valor según el tamaño mínimo deseado para cada gráfico */ +} + +.circular-chart { + max-width: 150px; + max-height: 150px; + margin: 0 auto; /* Centra el gráfico dentro del contenedor */ +} + +.chart { + display: flex; + justify-content: center; +} + + .icon-pc { font-size: 25px; color: #3b82f6; @@ -43,7 +89,6 @@ background-color: #fff; padding: 20px; border-radius: 12px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } .two-column-table { @@ -53,6 +98,10 @@ 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; @@ -72,11 +121,11 @@ } .mat-tab-group { - min-height: 400px; + min-height: 400px; } .mat-tab-body-wrapper { - min-height: inherit; + min-height: inherit; } .info-section h2 { @@ -92,7 +141,6 @@ .second-section { display: grid; - grid-template-columns: 1fr 3fr; gap: 20px; } @@ -111,24 +159,6 @@ width: 100%; } -.disk-usage { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - margin-bottom: 20px; - background-color: #fff; - padding: 20px; - border-radius: 12px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); -} - -.chart-container { - width: 150px; - height: 150px; - margin-bottom: 15px; -} - .circular-chart { display: block; margin: 0 auto; 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 index 0f1d858..b501a14 100644 --- 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 @@ -1,3 +1,14 @@ +
+

Datos de cliente

+
+ +
+ + + +
@@ -17,54 +28,56 @@
- -
-
-
{{ clientData?.property }}
-
{{ clientData?.value }}
-
-
-
-
-
- - -
+
+

Discos/Particiones

+
-
-

Disco

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

Disco {{ disk.diskNumber }}

-
+
+ d="M18 2.0845 + a 15.9155 15.9155 0 0 1 0 31.831 + a 15.9155 15.9155 0 0 1 0 -31.831" /> + [attr.stroke-dasharray]="disk.percentage + ', 100'" + d="M18 2.0845 + a 15.9155 15.9155 0 0 1 0 31.831 + a 15.9155 15.9155 0 0 1 0 -31.831" /> {{ disk.percentage }}%

Usado: {{ disk.used }} 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 index 4f00d86..35c2741 100644 --- 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 @@ -1,5 +1,9 @@ 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 {PartitionAssistantComponent} from "./partition-assistant/partition-assistant.component"; +import {MatDialog} from "@angular/material/dialog"; interface ClientInfo { property: string; value: any; @@ -18,13 +22,44 @@ export class ClientMainViewComponent implements OnInit { isPartitionAssistantVisible: boolean = false; isBootImageVisible: boolean = false; isDiskUsageVisible: boolean = true; - + dataSource = new MatTableDataSource(); generalData: ClientInfo[] = []; networkData: ClientInfo[] = []; classroomData: ClientInfo[] = []; diskUsageData: any[] = []; + partitions: any[] = []; + commands: any[] = []; + 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} %` + }, + ]; + displayedColumns = [...this.columns.map(column => column.columnDef)]; - constructor(private http: HttpClient) { + constructor(private http: HttpClient, private dialog: MatDialog) { const url = window.location.href; const segments = url.split('/'); this.clientUuid = segments[segments.length - 1]; @@ -32,10 +67,10 @@ export class ClientMainViewComponent implements OnInit { ngOnInit() { this.clientData = history.state.clientData; + this.loadPartitions() this.updateGeneralData(); this.updateNetworkData(); - this.updateClassroomData(); - this.calculateDiskUsage(); + this.loadCommands() } updateGeneralData() { @@ -48,54 +83,36 @@ export class ClientMainViewComponent implements OnInit { { property: 'Netiface', value: this.clientData?.netiface || '' }, { property: 'Perfil hardware', value: this.clientData?.hardwareProfile?.description || '' }, { property: 'Menú', value: this.clientData?.menu?.description || '' }, - { property: 'Fecha de creación', value: this.clientData?.createdAt || '' }, - { property: 'Creado por', value: this.clientData?.createdBy || '' } ]; } updateNetworkData() { this.networkData = [ - { property: 'Perfil hardware', value: this.clientData?.hardwareProfile?.description || '' }, + { property: 'Remote Pc', value: this.clientData.remotePc || '' }, { property: 'Subred', value: this.clientData?.subnet || '' }, { property: 'OGlive', value: '' }, { property: 'Autoexec', value: '' }, { property: 'Repositorio', value: '' }, { property: 'Validación', value: this.clientData?.organizationalUnit?.networkSettings?.validation || '' }, - { property: 'Fecha de creación', value: this.clientData?.createdAt || '' }, + { property: 'Pxe', value: this.clientData?.template.name || '' }, { property: 'Creado por', value: this.clientData?.createdBy || '' } ]; } - updateClassroomData() { - this.classroomData = [ - { property: 'Url servidor proxy', value: this.clientData?.organizationalUnit?.networkSettings?.proxy || '' }, - { property: 'IP DNS', value: this.clientData?.organizationalUnit?.networkSettings?.dns || '' }, - { property: 'Máscara de red', value: this.clientData?.organizationalUnit?.networkSettings?.netmask || '' }, - { property: 'Router', value: this.clientData?.organizationalUnit?.networkSettings?.router || '' }, - { property: 'NTP', value: this.clientData?.organizationalUnit?.networkSettings?.ntp || '' }, - { property: 'Modo p2p', value: this.clientData?.organizationalUnit?.networkSettings?.p2pMode || '' }, - { property: 'Tiempo p2p', value: this.clientData?.organizationalUnit?.networkSettings?.p2pTime || '' }, - { property: 'IP multicast', value: this.clientData?.organizationalUnit?.networkSettings?.mcastIp || '' }, - { property: 'Modo multicast', value: this.clientData?.organizationalUnit?.networkSettings?.mcastMode || '' }, - { property: 'Puerto multicast', value: this.clientData?.organizationalUnit?.networkSettings?.mcastPort || '' }, - { property: 'Velocidad multicast', value: this.clientData?.organizationalUnit?.networkSettings?.mcastSpeed || '' }, - { property: 'Perfil hardware', value: this.clientData?.organizationalUnit?.networkSettings?.hardwareProfile?.description || '' } - ]; - } - calculateDiskUsage() { const diskUsageMap = new Map(); - this.clientData.partitions.forEach((partition: any) => { + this.partitions.forEach((partition: any) => { const diskNumber = partition.diskNumber; if (!diskUsageMap.has(diskNumber)) { diskUsageMap.set(diskNumber, { total: 0, used: 0 }); } const diskData = diskUsageMap.get(diskNumber); + if (partition.partitionNumber === 0) { - diskData!.total = partition.size / (1024 * 1024); + diskData!.total = Number((partition.size / 1024).toFixed(2)); } else { - diskData!.used += partition.size / (1024 * 1024); + diskData!.used += Number(((partition.size * (partition.memoryUsage / 100))/ 1024).toFixed(2)); } }); @@ -105,23 +122,44 @@ export class ClientMainViewComponent implements OnInit { }); } - togglePartitionAssistant() { - this.isPartitionAssistantVisible = !this.isPartitionAssistantVisible; - this.isBootImageVisible = false - if (this.isPartitionAssistantVisible) { - setTimeout(() => { - this.assistantContainer.nativeElement.scrollIntoView({ behavior: 'smooth' }); - }, 0); + loadPartitions(): void { + this.http.get(`${this.baseUrl}/partitions?client.id=${this.clientData?.id}`).subscribe({ + next: data => { + this.dataSource = data['hydra:member']; + this.partitions = data['hydra:member']; + 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(command: any): void { + if (command.name === 'Particionar y Formatear') { + this.openPartitionDialog(); } } - showBootImage() { - this.isBootImageVisible = !this.isBootImageVisible; - this.isPartitionAssistantVisible = false; - if (this.isBootImageVisible) { - setTimeout(() => { - this.assistantContainer.nativeElement.scrollIntoView({ behavior: 'smooth' }); - }, 0); - } + openPartitionDialog(): void { + const dialogRef = this.dialog.open(PartitionAssistantComponent, { + width: '1000px', + data: this.clientData['@id'] + }); + + dialogRef.afterClosed().subscribe((result: any) => { + console.log('El diálogo se cerró', result); + }); } } diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.css b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.css index fce857e..1615bc2 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.css +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.css @@ -2,8 +2,6 @@ font-family: 'Roboto', sans-serif; background-color: #f9f9f9; padding: 20px; - border-radius: 10px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); margin: 20px auto; } @@ -13,7 +11,7 @@ justify-content: space-between; margin-bottom: 15px; padding: 10px; - background-color: #fff; + background-color: #cecbcb; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } @@ -52,8 +50,6 @@ width: 100%; border-collapse: collapse; background-color: #fff; - border-radius: 8px; - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); overflow: hidden; margin-bottom: 20px; } @@ -68,15 +64,12 @@ .partition-table td { padding: 10px; text-align: center; - border-bottom: 1px solid #eee; } .partition-table select, .partition-table input[type="number"], .partition-table input[type="checkbox"] { padding: 5px; - border-radius: 4px; - border: 1px solid #ccc; width: 100%; } diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.html b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.html index 96bec8a..4b24a0d 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.html +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.html @@ -1,62 +1,73 @@ -
-

Asistente a particionado

-
- - Tamaño: {{ disk.totalDiskSize }} GB -
+

Asistente de particionado

-
-
- {{ partition.type }} ({{ partition.size }} GB) + + +
+
+ + Tamaño: {{ (disk.totalDiskSize / 1024).toFixed(2) }} GB
+ +
+
+ {{ partition.type }} ({{ (partition.size / 1024).toFixed(2) }} GB) +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
ParticiónTipo particiónTamaño (MB)Uso (%)FormatearEliminar
{{ partition.partitionNumber }} + + + + + + + + + +
- - - - - - - - - - - - - - - - - - - - - - -
ParticiónTipo particiónTamaño (GB)FormatearEliminar
{{ partition.partitionNumber }} - - - - - - - -
-
+
{{ errorMessage }}
-
- -
+ + + diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.ts b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.ts index 4e066b9..472f7e6 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.ts +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.ts @@ -1,6 +1,7 @@ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import {Component, EventEmitter, Inject, Input, OnInit, Output} from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { ToastrService } from 'ngx-toastr'; +import {MAT_DIALOG_DATA} from "@angular/material/dialog"; interface Partition { uuid?: string; @@ -8,6 +9,7 @@ interface Partition { size: number; type: string; sizeBytes: number; + memoryUsage: number; format: boolean; color: string; percentage: number; @@ -20,8 +22,6 @@ interface Partition { }) export class PartitionAssistantComponent implements OnInit { baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; - @Input() data: any; - @Input() clientUuid: string | undefined; @Output() dataChange = new EventEmitter(); errorMessage = ''; @@ -30,14 +30,18 @@ export class PartitionAssistantComponent implements OnInit { private apiUrl: string = this.baseUrl + '/partitions'; - constructor(private http: HttpClient, private toastService: ToastrService) {} + constructor( + private http: HttpClient, + private toastService: ToastrService, + @Inject(MAT_DIALOG_DATA) public data: any + ) {} ngOnInit() { - this.loadClientData(); + this.loadPartitions(); } - loadClientData() { - const url = `${this.baseUrl}/clients/${this.clientUuid}`; + loadPartitions() { + const url = `${this.baseUrl}${this.data}`; this.http.get(url).subscribe( (response) => { this.data = response; @@ -68,6 +72,7 @@ export class PartitionAssistantComponent implements OnInit { uuid: partition.uuid, partitionNumber: partition.partitionNumber, size: this.convertBytesToGB(partition.size), + memoryUsage: partition.memoryUsage, type: partition.type || partition.filesystem || 'NTFS', sizeBytes: partition.size, format: false, @@ -88,12 +93,12 @@ export class PartitionAssistantComponent implements OnInit { } convertBytesToGB(bytes: number): number { - return bytes / 1024; + return bytes } updatePartitionPercentages(partitions: Partition[], totalDiskSize: number) { partitions.forEach((partition) => { - partition.percentage = (partition.size / totalDiskSize) * 100; + partition.percentage = (partition.size / totalDiskSize) * 100 }); } @@ -102,6 +107,7 @@ export class PartitionAssistantComponent implements OnInit { if (disk) { const remainingGB = this.getRemainingGB(disk.partitions, disk.totalDiskSize); + console.log(remainingGB) if (remainingGB > 0) { const maxPartitionNumber = disk.partitions.length > 0 ? Math.max(...disk.partitions.map((p) => p.partitionNumber)) : 0; @@ -111,6 +117,7 @@ export class PartitionAssistantComponent implements OnInit { partitionNumber: newPartitionNumber, size: 0, type: 'NTFS', + memoryUsage: 0, sizeBytes: 0, format: false, color: '#' + Math.floor(Math.random() * 16777215).toString(16), @@ -136,13 +143,14 @@ export class PartitionAssistantComponent implements OnInit { } else { this.errorMessage = ''; partition.size = size; - partition.sizeBytes = size * 1024; + partition.sizeBytes = size; this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize); } } } getRemainingGB(partitions: Partition[], totalDiskSize: number): number { + console.log(totalDiskSize) const totalUsedGB = partitions.reduce((acc, partition) => acc + partition.size, 0); return Math.max(0, totalDiskSize - totalUsedGB); } @@ -182,6 +190,18 @@ export class PartitionAssistantComponent implements OnInit { } save() { + const invalidDisks = this.disks.filter(disk => { + const totalPartitionSize = disk.partitions.reduce((sum, partition) => sum + partition.size, 0); + return totalPartitionSize > disk.totalDiskSize; + }); + + if (invalidDisks.length > 0) { + this.errorMessage = 'El tamaño total de las particiones en uno o más discos excede el tamaño total del disco.'; + return; + } else { + this.errorMessage = ''; + } + const modifiedPartitions = this.getModifiedOrNewPartitions(); if (modifiedPartitions.length === 0) { @@ -193,32 +213,40 @@ export class PartitionAssistantComponent implements OnInit { const payload = { diskNumber: diskNumber, partitionNumber: partitionNumber, + memoryUsage: partition.memoryUsage, size: partition.size, filesystem: partition.type, - client: `/clients/${this.clientUuid}` + client: this.data['@id'] }; if (isNew) { this.http.post(this.apiUrl, payload).subscribe( (response) => { this.toastService.success('Partición creada exitosamente'); - this.loadClientData(); + this.loadPartitions(); }, - (error) => {} + (error) => { + console.error('Error al crear la partición:', error); + this.toastService.error('Error al crear la partición'); + } ); } else if (partition.uuid) { const patchUrl = `${this.apiUrl}/${partition.uuid}`; this.http.patch(patchUrl, payload).subscribe( (response) => { this.toastService.success('Partición actualizada exitosamente'); - this.loadClientData(); + this.loadPartitions(); }, - (error) => {} + (error) => { + console.error('Error al actualizar la partición:', error); + this.toastService.error('Error al actualizar la partición'); + } ); } }); } + removePartition(diskNumber: number, partition: Partition) { const disk = this.disks.find((d) => d.diskNumber === diskNumber); @@ -233,7 +261,7 @@ export class PartitionAssistantComponent implements OnInit { this.http.delete(deleteUrl).subscribe( (response) => { this.toastService.success('Partición eliminada exitosamente'); - this.loadClientData(); + this.loadPartitions(); }, (error) => {} ); diff --git a/ogWebconsole/src/app/components/groups/components/client-tab-view/client-tab-view.component.ts b/ogWebconsole/src/app/components/groups/components/client-tab-view/client-tab-view.component.ts index 0c34fad..7619310 100644 --- a/ogWebconsole/src/app/components/groups/components/client-tab-view/client-tab-view.component.ts +++ b/ogWebconsole/src/app/components/groups/components/client-tab-view/client-tab-view.component.ts @@ -151,8 +151,6 @@ export class ClientTabViewComponent { handleClientClick(event: MouseEvent, client: any): void { event.stopPropagation(); - /* const dialogRef = this.dialog.open(ClientViewComponent, { data: { client }, width: '800px', height:'700px' }); */ - this.router.navigate(['client', client.uuid], { state: { clientData: client } }); }