refs #1922. Show new fields in clients table.
testing/ogGui-multibranch/pipeline/head There was a failure building this commit Details

pull/22/head
Manuel Aranda Rosales 2025-05-08 08:06:57 +02:00
parent 9ba8c1771d
commit ef3158a045
7 changed files with 51 additions and 111 deletions

View File

@ -17,7 +17,7 @@ import { CalendarComponent } from "./components/calendar/calendar.component";
import { CommandsComponent } from './components/commands/main-commands/commands.component'; import { CommandsComponent } from './components/commands/main-commands/commands.component';
import { CommandsGroupsComponent } from './components/commands/commands-groups/commands-groups.component'; import { CommandsGroupsComponent } from './components/commands/commands-groups/commands-groups.component';
import { CommandsTaskComponent } from './components/commands/commands-task/commands-task.component'; import { CommandsTaskComponent } from './components/commands/commands-task/commands-task.component';
import { TaskLogsComponent } from './components/commands/commands-task/task-logs/task-logs.component'; import { TaskLogsComponent } from './components/task-logs/task-logs.component';
import {SoftwareComponent} from "./components/software/software.component"; import {SoftwareComponent} from "./components/software/software.component";
import {SoftwareProfileComponent} from "./components/software-profile/software-profile.component"; import {SoftwareProfileComponent} from "./components/software-profile/software-profile.component";
import {OperativeSystemComponent} from "./components/operative-system/operative-system.component"; import {OperativeSystemComponent} from "./components/operative-system/operative-system.component";

View File

@ -67,7 +67,7 @@ import { PXEimagesComponent } from './components/ogboot/pxe-images/pxe-images.co
import { CreatePXEImageComponent } from './components/ogboot/pxe-images/create-image/create-image/create-image.component'; import { CreatePXEImageComponent } from './components/ogboot/pxe-images/create-image/create-image/create-image.component';
import { InfoImageComponent } from './components/ogboot/pxe-images/info-image/info-image/info-image.component'; import { InfoImageComponent } from './components/ogboot/pxe-images/info-image/info-image/info-image.component';
import { PxeComponent } from './components/ogboot/pxe/pxe.component'; import { PxeComponent } from './components/ogboot/pxe/pxe.component';
import { CreatePxeTemplateComponent } from './components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component'; import { CreatePxeTemplateComponent } from './components/ogboot/pxe/manage-pxeTemplate/create-pxe-template.component';
import { PxeBootFilesComponent } from './components/ogboot/pxe-boot-files/pxe-boot-files.component'; import { PxeBootFilesComponent } from './components/ogboot/pxe-boot-files/pxe-boot-files.component';
import { MatExpansionPanel, MatExpansionPanelDescription, MatExpansionPanelTitle } from "@angular/material/expansion"; import { MatExpansionPanel, MatExpansionPanelDescription, MatExpansionPanelTitle } from "@angular/material/expansion";
import { OgbootStatusComponent } from './components/ogboot/ogboot-status/ogboot-status.component'; import { OgbootStatusComponent } from './components/ogboot/ogboot-status/ogboot-status.component';
@ -87,7 +87,7 @@ import { CreateCommandGroupComponent } from './components/commands/commands-grou
import { DetailCommandGroupComponent } from './components/commands/commands-groups/detail-command-group/detail-command-group.component'; import { DetailCommandGroupComponent } from './components/commands/commands-groups/detail-command-group/detail-command-group.component';
import { CreateTaskComponent } from './components/commands/commands-task/create-task/create-task.component'; import { CreateTaskComponent } from './components/commands/commands-task/create-task/create-task.component';
import { DetailTaskComponent } from './components/commands/commands-task/detail-task/detail-task.component'; 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 { TaskLogsComponent } from './components/task-logs/task-logs.component';
import { MatSliderModule } from '@angular/material/slider'; import { MatSliderModule } from '@angular/material/slider';
import { ImagesComponent } from './components/images/images.component'; import { ImagesComponent } from './components/images/images.component';
import { CreateImageComponent } from './components/images/create-image/create-image.component'; import { CreateImageComponent } from './components/images/create-image/create-image.component';
@ -117,7 +117,7 @@ import { CreateMultipleClientComponent } from './components/groups/shared/client
import { ExportImageComponent } from './components/images/export-image/export-image.component'; import { ExportImageComponent } from './components/images/export-image/export-image.component';
import { ImportImageComponent } from "./components/repositories/import-image/import-image.component"; import { ImportImageComponent } from "./components/repositories/import-image/import-image.component";
import { LoadingComponent } from './shared/loading/loading.component'; import { LoadingComponent } from './shared/loading/loading.component';
import { InputDialogComponent } from './components/commands/commands-task/task-logs/input-dialog/input-dialog.component'; import { InputDialogComponent } from './components/task-logs/input-dialog/input-dialog.component';
import { ManageOrganizationalUnitComponent } from './components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component'; import { ManageOrganizationalUnitComponent } from './components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component';
import { BackupImageComponent } from './components/repositories/backup-image/backup-image.component'; import { BackupImageComponent } from './components/repositories/backup-image/backup-image.component';
import { ServerInfoDialogComponent } from "./components/ogdhcp/server-info-dialog/server-info-dialog.component"; import { ServerInfoDialogComponent } from "./components/ogdhcp/server-info-dialog/server-info-dialog.component";

View File

@ -13,6 +13,16 @@
<mat-divider></mat-divider> <mat-divider></mat-divider>
<div class="select-container"> <div class="select-container">
<div class="selector">
<mat-form-field appearance="fill" class="half-width">
<mat-label>Tipo de imagen</mat-label>
<mat-select formControlName="scope" class="full-width" >
<mat-option [value]="'monolitic'">Monolítica</mat-option>
<mat-option disabled [value]="'git'">Git</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="selector"> <div class="selector">
<mat-form-field appearance="fill" class="half-width"> <mat-form-field appearance="fill" class="half-width">
<mat-label>Nombre canónico</mat-label> <mat-label>Nombre canónico</mat-label>

View File

@ -252,6 +252,8 @@ export class PartitionAssistantComponent implements OnInit{
if (disk) { if (disk) {
const remainingGB = this.getRemainingGB(disk.partitions, disk.totalDiskSize); const remainingGB = this.getRemainingGB(disk.partitions, disk.totalDiskSize);
console.log('Remaining GB:', remainingGB);
console.log('Total Disk Size:', disk);
if (remainingGB > 0) { if (remainingGB > 0) {
const removedPartitions = disk.partitions.filter((p) => !p.removed); const removedPartitions = disk.partitions.filter((p) => !p.removed);
@ -259,7 +261,6 @@ export class PartitionAssistantComponent implements OnInit{
removedPartitions.length > 0 ? Math.max(...removedPartitions.map((p) => p.partitionNumber)) : 0; removedPartitions.length > 0 ? Math.max(...removedPartitions.map((p) => p.partitionNumber)) : 0;
const newPartitionNumber = maxPartitionNumber + 1; const newPartitionNumber = maxPartitionNumber + 1;
disk.partitions.push({ disk.partitions.push({
partitionNumber: newPartitionNumber, partitionNumber: newPartitionNumber,
size: 0, size: 0,
@ -303,10 +304,14 @@ export class PartitionAssistantComponent implements OnInit{
} }
getRemainingGB(partitions: Partition[], totalDiskSize: number): number { getRemainingGB(partitions: Partition[], totalDiskSize: number): number {
const totalUsedGB = partitions.reduce((acc, partition) => acc + partition.size, 0); const totalUsedGB = partitions
.filter(partition => !partition.removed)
.reduce((acc, partition) => acc + partition.size, 0);
return Math.max(0, totalDiskSize - totalUsedGB); return Math.max(0, totalDiskSize - totalUsedGB);
} }
save() { save() {
if (!this.selectedDisk) { if (!this.selectedDisk) {
this.toastService.error('No se ha seleccionado un disco.'); this.toastService.error('No se ha seleccionado un disco.');
@ -373,6 +378,10 @@ export class PartitionAssistantComponent implements OnInit{
if (partitionToRemove) { if (partitionToRemove) {
partitionToRemove.removed = true; partitionToRemove.removed = true;
} }
disk.used = this.calculateUsedSpace(disk.partitions);
disk.percentage = (disk.used / disk.totalDiskSize) * 100;
this.updateDiskChart(disk); this.updateDiskChart(disk);
this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize); this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize);
} }
@ -391,9 +400,12 @@ export class PartitionAssistantComponent implements OnInit{
} }
calculateUsedSpace(partitions: Partition[]): number { calculateUsedSpace(partitions: Partition[]): number {
return partitions.reduce((acc, partition) => acc + partition.size, 0); return partitions
.filter(partition => !partition.removed)
.reduce((acc, partition) => acc + partition.size, 0);
} }
generateChartData(partitions: Partition[]): any[] { generateChartData(partitions: Partition[]): any[] {
return partitions.map((partition) => ({ return partitions.map((partition) => ({
name: `Partición ${partition.partitionNumber}`, name: `Partición ${partition.partitionNumber}`,

View File

@ -371,15 +371,19 @@
<ng-container matColumnDef="firmwareType"> <ng-container matColumnDef="firmwareType">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'firmwareType' | translate }} </th> <th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'firmwareType' | translate }} </th>
<td mat-cell *matCellDef="let client"> <td mat-cell *matCellDef="let client">
<mat-chip s> <mat-chip *ngIf="client.firmwareType">
{{ client.firmwareType ? client.firmwareType : 'N/A' }} {{ client.firmwareType }}
</mat-chip> </mat-chip>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="oglive"> <ng-container matColumnDef="oglive">
<th mat-header-cell *matHeaderCellDef mat-sort-header> OG Live </th> <th mat-header-cell *matHeaderCellDef mat-sort-header> OG Live </th>
<td mat-cell *matCellDef="let client"> {{ client.ogLive?.date | date }} </td> <td mat-cell *matCellDef="let client">
<div style="display: flex; flex-direction: column;">
<span>{{ client.ogLive?.kernel }} </span>
<span style="font-size: 0.75rem; color: gray;"> {{ client.ogLive?.date | date }}</span>
</div>
</ng-container> </ng-container>
<ng-container matColumnDef="maintenace"> <ng-container matColumnDef="maintenace">
@ -457,4 +461,4 @@
</div> </div>
</ng-template> </ng-template>
</div> </div>

View File

@ -46,9 +46,14 @@
</ng-container> </ng-container>
</td> </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
<ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [hidden]="row.partitionNumber === 0"></tr>
</ng-container>
</table> </table>
</div> </div>
<div class="charts-container" [ngClass]="{'single-disk': chartDisk.length === 1}"> <div class="charts-container" [ngClass]="{'single-disk': chartDisk.length === 1}">

View File

@ -38,41 +38,27 @@ export class ClientDetailsComponent {
view: [number, number] = [260, 160]; view: [number, number] = [260, 160];
showLegend: boolean = true; 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'); datePipe: DatePipe = new DatePipe('es-ES');
columns = [ columns = [
{ {
columnDef: 'diskNumber', columnDef: 'diskNumber',
header: 'Disco', header: 'Disco',
cell: (partition: any) => `${partition.diskNumber}`, cell: (partition: any) => partition.diskNumber,
}, },
{ {
columnDef: 'partitionNumber', columnDef: 'partitionNumber',
header: 'Particion', header: 'Particion',
cell: (partition: any) => `${partition.partitionNumber}` cell: (partition: any) => partition.partitionNumber
}, },
{ {
columnDef: 'partitionCode', columnDef: 'partitionCode',
header: 'Tipo de partición', header: 'Tipo de partición',
cell: (partition: any) => `${partition.partitionCode}` cell: (partition: any) => partition.partitionCode
}, },
{ {
columnDef: 'description', columnDef: 'description',
header: 'Sistema de ficheros', header: 'Sistema de ficheros',
cell: (partition: any) => `${partition.filesystem}` cell: (partition: any) => partition.filesystem
}, },
{ {
columnDef: 'size', columnDef: 'size',
@ -82,12 +68,12 @@ export class ClientDetailsComponent {
{ {
columnDef: 'memoryUsage', columnDef: 'memoryUsage',
header: 'Uso', header: 'Uso',
cell: (partition: any) => `${partition.memoryUsage} %` cell: (partition: any) => `${partition.memoryUsage}%`
}, },
{ {
columnDef: 'operativeSystem', columnDef: 'operativeSystem',
header: 'SO', header: 'SO',
cell: (partition: any) => `${partition.operativeSystem?.name}` cell: (partition: any) => partition.operativeSystem?.name
}, },
]; ];
displayedColumns = [...this.columns.map(column => column.columnDef)]; displayedColumns = [...this.columns.map(column => column.columnDef)];
@ -121,21 +107,6 @@ export class ClientDetailsComponent {
} }
} }
loadClient = (uuid: string) => {
this.http.get<any>(`${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);
}
});
}
updateGeneralData() { updateGeneralData() {
this.generalData = [ this.generalData = [
{ property: 'Nombre', value: this.clientData?.name || '' }, { property: 'Nombre', value: this.clientData?.name || '' },
@ -150,7 +121,7 @@ export class ClientDetailsComponent {
updateNetworkData() { updateNetworkData() {
this.networkData = [ this.networkData = [
{ property: 'Padre', value: this.clientData?.organizationalUnit?.name || '' }, { property: 'Padre', value: this.clientData?.organizationalUnit?.name || '' },
{ property: 'Pxe', value: this.clientData?.template?.name || '' }, { property: 'Pxe', value: this.clientData?.pxeTemplate?.name || '' },
{ property: 'Remote Pc', value: this.clientData.remotePc || '' }, { property: 'Remote Pc', value: this.clientData.remotePc || '' },
{ property: 'Subred', value: this.clientData?.subnet || '' }, { property: 'Subred', value: this.clientData?.subnet || '' },
{ property: 'OGlive', value: this.clientData?.ogLive?.name || '' }, { property: 'OGlive', value: this.clientData?.ogLive?.name || '' },
@ -205,21 +176,14 @@ export class ClientDetailsComponent {
this.isDiskUsageEmpty = this.diskUsageData.length === 0; 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 { loadPartitions(): void {
if (!this.clientData?.id) { if (!this.clientData?.id) {
console.error('El ID del cliente no está disponible.');
return; return;
} }
this.http.get<any>(`${this.baseUrl}/partitions?client.id=${this.clientData.id}&order[diskNumber, partitionNumber]=ASC`).subscribe({ this.http.get<any>(`${this.baseUrl}/partitions?client.id=${this.clientData.id}&order[diskNumber, partitionNumber]=ASC`).subscribe({
next: data => { next: data => {
const filteredPartitions = data['hydra:member'].filter((partition: any) => partition.partitionNumber !== 0); const filteredPartitions = data['hydra:member'];
this.dataSource = filteredPartitions; this.dataSource = filteredPartitions;
this.partitions = filteredPartitions; this.partitions = filteredPartitions;
this.calculateDiskUsage(); this.calculateDiskUsage();
@ -233,59 +197,4 @@ export class ClientDetailsComponent {
onNoClick(): void { onNoClick(): void {
this.dialog.closeAll(); this.dialog.closeAll();
} }
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);
});
}
} }