Compare commits

...

2 Commits

Author SHA1 Message Date
Manuel Aranda Rosales 48636d0933 Solve conflics
testing/ogGui-multibranch/pipeline/head There was a failure building this commit Details
2024-10-25 10:50:58 +02:00
Manuel Aranda Rosales 60a96170e1 refs #1048. Updated client view and partition assistant 2024-10-25 10:42:08 +02:00
8 changed files with 293 additions and 237 deletions

View File

@ -54,57 +54,3 @@
(page)="onPageChange($event)">
</mat-paginator>
</div>
<div class="header-container">
<h2 class="title" i18n="@@adminCommandsTitle">Trazas de comandos y procedimientos</h2>
<div class="images-button-row">
<button mat-flat-button color="primary" (click)="resetFilters()">Reiniciar filtros</button>
</div>
</div>
<mat-divider class="divider"></mat-divider>
<div class="search-container">
<mat-form-field appearance="fill" class="search-select">
<input type="text" matInput [formControl]="clientControl" [matAutocomplete]="clientAuto" placeholder="Seleccione un cliente">
<mat-autocomplete #clientAuto="matAutocomplete" [displayWith]="displayFnClient" (optionSelected)="onOptionClientSelected($event.option.value)">
<mat-option *ngFor="let client of filteredClients | async" [value]="client">
{{ client.name }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field appearance="fill" class="search-select">
<input type="text" matInput [formControl]="commandControl" [matAutocomplete]="commandAuto" placeholder="Seleccione un comando">
<mat-autocomplete #commandAuto="matAutocomplete" [displayWith]="displayFnCommand" (optionSelected)="onOptionCommandSelected($event.option.value)">
<mat-option *ngFor="let command of filteredCommands | async" [value]="command">
{{ command.name }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
<div *ngIf="loading" class="loading-container">
<mat-spinner></mat-spinner>
</div>
<div *ngIf="!loading">
<table mat-table [dataSource]="traces" class="mat-elevation-z8">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
<td mat-cell *matCellDef="let trace">
{{ column.cell(trace) }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<div class="paginator-container">
<mat-paginator [length]="length"
[pageSize]="itemsPerPage"
[pageIndex]="page"
[pageSizeOptions]="pageSizeOptions"
(page)="onPageChange($event)">
</mat-paginator>
</div>

View File

@ -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;

View File

@ -1,7 +1,14 @@
<div class="header-container">
<h2 class="title">Administrar Cliente</h2>
<h2 class="title" i18n="@@adminImagesTitle">Datos de cliente</h2>
<div class="calendar-button-row">
<button mat-flat-button color="primary" [matMenuTriggerFor]="commandMenu">Comandos</button>
</div>
<mat-menu #commandMenu="matMenu">
<button mat-menu-item *ngFor="let command of commands" (click)="onCommandSelect(command)">
{{ command.name }}
</button>
</mat-menu>
</div>
<mat-divider class="divider"></mat-divider>
<div *ngIf="loading" class="loading-container">
@ -27,53 +34,56 @@
</div>
</div>
</mat-tab>
<mat-tab label="Propiedades del aula">
<div class="two-column-table">
<div class="table-row" *ngFor="let clientData of classroomData">
<div class="column property">{{ clientData?.property }}</div>
<div class="column value">{{ clientData?.value }}</div>
</div>
</div>
</mat-tab>
</mat-tab-group>
</div>
<div class="second-section">
<div class="buttons-row">
<button mat-flat-button color="primary" (click)="togglePartitionAssistant()" [disabled]="isDiskUsageEmpty">Asistente particionado</button>
<button mat-flat-button color="primary" (click)="showBootImage()" [disabled]="isDiskUsageEmpty">Restaurar imagen</button>
</div>
<div class="header-container">
<h2 class="title" i18n="@@adminImagesTitle">Discos/Particiones</h2>
</div>
<div class="info-section">
<h2 *ngIf="isDiskUsageVisible">Disco</h2>
<ng-container *ngIf="diskUsageData && diskUsageData.length > 0">
<div class="table-container">
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
<td mat-cell *matCellDef="let image" >
<ng-container *ngIf="column.columnDef !== 'size'">
{{ column.cell(image) }}
</ng-container>
<ng-container *ngIf="column.columnDef === 'size'">
<mat-chip color="primary" >
{{ (image.size / 1024).toFixed(2) }} GB
</mat-chip>
</ng-container>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<div class="charts-wrapper">
<ng-container *ngIf="diskUsageData && diskUsageData.length > 0">
<div class="charts-row">
<div *ngFor="let disk of diskUsageData" class="disk-usage">
<h3>Disco {{ disk.diskNumber }}</h3>
<div class="chart-container">
<div class="chart">
<svg viewBox="0 0 36 36" class="circular-chart green">
<path class="circle-bg"
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" />
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" />
<path class="circle"
[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" />
[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" />
<text x="18" y="20.35" class="percentage">{{ disk.percentage }}%</text>
</svg>
</div>
<p>Usado: {{ disk.used }} GB ({{ disk.percentage }}%)</p>
<p>Total: {{ disk.total }} GB</p>
</div>
</ng-container>
</div>
</div>
</ng-container>
</div>
</div>
<div class="assistants-container" *ngIf="isPartitionAssistantVisible" #assistantContainer>
<app-partition-assistant [data]="clientData" [clientUuid]="clientUuid"></app-partition-assistant>
</div>
<div *ngIf="isBootImageVisible" #assistantContainer>
<app-restore-image [data]="clientData"></app-restore-image>
</div>

View File

@ -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;
@ -19,14 +23,46 @@ export class ClientMainViewComponent implements OnInit {
isPartitionAssistantVisible: boolean = false;
isBootImageVisible: boolean = false;
isDiskUsageVisible: boolean = true;
dataSource = new MatTableDataSource<any>();
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)];
isDiskUsageEmpty: boolean = true;
loading: boolean = true; // Variable para controlar el estado de carga
loading: boolean = true;
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];
@ -34,11 +70,12 @@ export class ClientMainViewComponent implements OnInit {
ngOnInit() {
this.clientData = history.state.clientData;
this.loadPartitions()
this.updateGeneralData();
this.updateNetworkData();
this.updateClassroomData();
this.loadCommands()
this.calculateDiskUsage();
this.loading = false; // Desactivar el estado de carga cuando los datos se hayan procesado
this.loading = false;
}
updateGeneralData() {
@ -51,55 +88,37 @@ 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<number, { total: number, used: number }>();
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));
}
});
@ -110,23 +129,44 @@ export class ClientMainViewComponent implements OnInit {
this.isDiskUsageEmpty = this.diskUsageData.length === 0;
}
togglePartitionAssistant() {
this.isPartitionAssistantVisible = !this.isPartitionAssistantVisible;
this.isBootImageVisible = false;
if (this.isPartitionAssistantVisible) {
setTimeout(() => {
this.assistantContainer.nativeElement.scrollIntoView({ behavior: 'smooth' });
}, 200);
loadPartitions(): void {
this.http.get<any>(`${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<any>(`${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);
});
}
}

View File

@ -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%;
}

View File

@ -1,62 +1,73 @@
<div class="partition-assistant" *ngFor="let disk of disks; let i = index">
<h2>Asistente a particionado</h2>
<div class="header">
<label for="disk-number-{{i}}">Disco {{ disk.diskNumber }}:</label>
<span class="disk-size">Tamaño: {{ disk.totalDiskSize }} GB</span>
</div>
<h2 mat-dialog-title>Asistente de particionado</h2>
<div class="partition-bar">
<div
*ngFor="let partition of disk.partitions"
[ngStyle]="{'width': partition.percentage + '%', 'background-color': partition.color}"
class="partition-segment"
>
{{ partition.type }} ({{ partition.size }} GB)
<mat-dialog-content>
<div class="partition-assistant" *ngFor="let disk of disks; let i = index">
<div class="header">
<label for="disk-number-{{i}}">Disco {{ disk.diskNumber }}:</label>
<span class="disk-size">Tamaño: {{ (disk.totalDiskSize / 1024).toFixed(2) }} GB</span>
</div>
<div class="partition-bar">
<div
*ngFor="let partition of disk.partitions"
[ngStyle]="{'width': partition.percentage + '%', 'background-color': partition.color}"
class="partition-segment"
>
{{ partition.type }} ({{ (partition.size / 1024).toFixed(2) }} GB)
</div>
</div>
<button mat-flat-button color="primary" (click)="addPartition(disk.diskNumber)"> + </button>
<table class="partition-table">
<thead>
<tr>
<th>Partición</th>
<th>Tipo partición</th>
<th>Tamaño (MB)</th>
<th>Uso (%)</th>
<th>Formatear</th>
<th>Eliminar</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let partition of disk.partitions; let j = index">
<td>{{ partition.partitionNumber }}</td>
<td>
<select [(ngModel)]="partition.type">
<option value="NTFS">NTFS</option>
<option value="LINUX">LINUX</option>
<option value="CACHE">CACHE</option>
</select>
</td>
<td>
<input
type="number"
[(ngModel)]="partition.size"
(input)="updatePartitionSize(disk.diskNumber, j, partition.size)"
/>
</td>
<td>
<input
type="number"
[(ngModel)]="partition.memoryUsage"
/>
</td>
<td>
<input type="checkbox" [(ngModel)]="partition.format" />
</td>
<td>
<button (click)="removePartition(disk.diskNumber, partition)" class="remove-btn">X</button>
</td>
</tr>
</tbody>
</table>
</div>
<button mat-button (click)="addPartition(disk.diskNumber)">Añadir +</button>
<table class="partition-table">
<thead>
<tr>
<th>Partición</th>
<th>Tipo partición</th>
<th>Tamaño (GB)</th>
<th>Formatear</th>
<th>Eliminar</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let partition of disk.partitions; let j = index">
<td>{{ partition.partitionNumber }}</td>
<td>
<select [(ngModel)]="partition.type">
<option value="NTFS">NTFS</option>
<option value="LINUX">LINUX</option>
<option value="CACHE">CACHE</option>
</select>
</td>
<td>
<input
type="number"
[(ngModel)]="partition.size"
(input)="updatePartitionSize(disk.diskNumber, j, partition.size)"
/>
</td>
<td>
<input type="checkbox" [(ngModel)]="partition.format" />
</td>
<td>
<button (click)="removePartition(disk.diskNumber, partition)" class="remove-btn">X</button>
</td>
</tr>
</tbody>
</table>
</div>
</mat-dialog-content>
<div *ngIf="errorMessage" class="error-message">{{ errorMessage }}</div>
<div class="actions">
<button mat-flat-button color="primary" (click)="save()">Guardar</button>
</div>
<mat-dialog-actions align="end">
<button mat-button (click)="save()">Guardar</button>
</mat-dialog-actions>

View File

@ -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<any>();
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) => {}
);

View File

@ -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 } });
}