From 299ced8b27febcfad80cc3594cfa6304521f946c Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 20 Apr 2026 18:00:33 +0200 Subject: [PATCH 1/2] refs #2972. Integration remove leases ogDhcp --- .../execute-command.component.ts | 30 ++++++++++++++++++- .../ogdhcp/og-dhcp-subnets.component.html | 2 ++ .../ogdhcp/og-dhcp-subnets.component.ts | 20 +++++++++++++ .../show-clients/show-clients.component.html | 4 +++ .../show-clients/show-clients.component.ts | 20 +++++++++++++ ogWebconsole/src/locale/en.json | 3 +- ogWebconsole/src/locale/es.json | 3 +- 7 files changed, 79 insertions(+), 3 deletions(-) diff --git a/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.ts b/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.ts index 11505fd..98c76d3 100644 --- a/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.ts +++ b/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.ts @@ -38,6 +38,7 @@ export class ExecuteCommandComponent implements OnInit { { translationKey: 'executeCommands.hardwareInventory', slug: 'hardware-inventory', disabled: false }, { translationKey: 'executeCommands.runScript', slug: 'run-script', disabled: false }, { translationKey: 'executeCommands.refresh', slug: 'refresh', disabled: false }, + { translationKey: 'executeCommands.deleteLease', slug: 'delete-lease', disabled: false }, ]; client: any = {}; @@ -81,7 +82,8 @@ export class ExecuteCommandComponent implements OnInit { 'hardware-inventory', 'remove-cache-image', 'partition', - 'refresh' + 'refresh', + 'delete-lease' ], 'ou-minimal': [ 'power-on', @@ -184,6 +186,10 @@ export class ExecuteCommandComponent implements OnInit { if (action === 'refresh') { this.refreshClient(); } + + if (action === 'delete-lease') { + this.deleteClientLease(); + } } rebootClient(): void { @@ -395,4 +401,26 @@ export class ExecuteCommandComponent implements OnInit { } }) } + + deleteClientLease(): void { + if (this.clientData.length === 0) { + this.toastService.error('No hay clientes seleccionados'); + return; + } + + const requests = this.clientData.map((client: any) => + this.http.delete(`${this.baseUrl}/clients/${client.uuid}/delete-lease`).toPromise() + ); + + Promise.allSettled(requests).then(results => { + const errors = results.filter(r => r.status === 'rejected'); + if (errors.length === 0) { + this.toastService.success('Lease(s) DHCP eliminada(s) correctamente'); + } else if (errors.length < results.length) { + this.toastService.warning(`${results.length - errors.length} lease(s) eliminada(s), ${errors.length} con error`); + } else { + this.toastService.error('Error al eliminar las leases DHCP'); + } + }); + } } diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.html b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.html index 6cfe1b4..2e836ed 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.html @@ -76,6 +76,8 @@ + diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts index eb2c18c..8c7162a 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts @@ -296,6 +296,26 @@ export class OgDhcpSubnetsComponent implements OnInit { }); } + deleteSubnetLeases(subnet: Subnet) { + const dialogRef = this.dialog.open(DeleteModalComponent, { + width: '300px', + data: { name: `leases de ${subnet.name}` } + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + this.http.delete(`${this.baseUrl}/og-dhcp/server/${subnet.uuid}/delete-leases`, {}).subscribe({ + next: () => { + this.toastService.success('Leases de la subred eliminadas correctamente'); + }, + error: (error) => { + this.toastService.error(error.error?.['hydra:description'] || 'Error al eliminar leases de la subred'); + } + }); + } + }); + } + addClientsToSubnet(subnet: Subnet) { const dialogRef = this.dialog.open(AddClientsToSubnetComponent, { width: '800px', diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html index 0267d11..cc83db3 100644 --- a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html @@ -78,6 +78,10 @@ Acciones + diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts index 322c90a..82640b8 100644 --- a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts @@ -75,6 +75,26 @@ export class ShowClientsComponent implements OnInit { ); } + deleteClientLease(client: any): void { + const dialogRef = this.dialog.open(DeleteModalComponent, { + width: '300px', + data: { name: `lease de ${client.name}` } + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + this.http.delete(`${this.baseUrl}/og-dhcp/server/${this.data.subnetUuid}/delete-lease/${client.uuid}`, {}).subscribe({ + next: () => { + this.toastService.success('Lease del cliente eliminada correctamente'); + }, + error: (error) => { + this.toastService.error(error.error?.['hydra:description'] || 'Error al eliminar lease del cliente'); + } + }); + } + }); + } + deleteClient(client: any): void { const dialogRef = this.dialog.open(DeleteModalComponent, { width: '300px', diff --git a/ogWebconsole/src/locale/en.json b/ogWebconsole/src/locale/en.json index ce89125..5c69b33 100644 --- a/ogWebconsole/src/locale/en.json +++ b/ogWebconsole/src/locale/en.json @@ -592,7 +592,8 @@ "softwareInventory": "Software Inventory", "hardwareInventory": "Hardware Inventory", "runScript": "Run Script", - "refresh": "Refresh" + "refresh": "Refresh", + "deleteLease": "Delete DHCP Lease" }, "changeOU": "Change Organizational Unit", "moveClientsTooltip": "Move clients to another organizational unit", diff --git a/ogWebconsole/src/locale/es.json b/ogWebconsole/src/locale/es.json index 689f3f3..57a7015 100644 --- a/ogWebconsole/src/locale/es.json +++ b/ogWebconsole/src/locale/es.json @@ -593,7 +593,8 @@ "softwareInventory": "Inventario Software", "hardwareInventory": "Inventario Hardware", "runScript": "Ejecutar script", - "refresh": "Refrescar" + "refresh": "Refrescar", + "deleteLease": "Borrar lease DHCP" }, "changeOU": "Mover", "moveClientsTooltip": "Mover clientes a otra unidad organizativa", From dd02d673bc9ec394adf2aa6f2673def44a51869d Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 20 Apr 2026 18:39:59 +0200 Subject: [PATCH 2/2] refs #2973. Refactor classroom status --- .../app/components/groups/groups.component.ts | 50 +++++++++++++------ .../src/app/components/groups/model/model.ts | 1 + 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/ogWebconsole/src/app/components/groups/groups.component.ts b/ogWebconsole/src/app/components/groups/groups.component.ts index 5334c38..53f8144 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.ts +++ b/ogWebconsole/src/app/components/groups/groups.component.ts @@ -76,6 +76,7 @@ export class GroupsComponent implements OnInit, OnDestroy { savedFilterNames: [string, string][] = []; selectedTreeFilter = ''; syncingClientIds = new Set(); + isCheckingNodeStatus = false; private originalTreeData: TreeNode[] = []; arrayClients: any[] = []; filters: { [key: string]: string } = {}; @@ -243,6 +244,7 @@ export class GroupsComponent implements OnInit, OnDestroy { private transformer = (node: TreeNode, level: number): FlatNode => ({ id: node.id, + uuid: node.uuid, name: node.name, type: node.type, level, @@ -463,6 +465,10 @@ export class GroupsComponent implements OnInit, OnDestroy { } }); + if (this.isCheckingNodeStatus) { + members.forEach((c: Client) => c.uuid && this.syncingClientIds.add(c.uuid)); + } + // Calcular estadísticas después de cargar los clientes this.calculateLocalStats(); }, @@ -843,23 +849,35 @@ export class GroupsComponent implements OnInit, OnDestroy { getStatusForAllClientsInNode(node: any): void { - this.http.get(`${this.baseUrl}/clients?organizationalUnit.id=${node.id}&itemsPerPage=1000`).subscribe({ - next: (response: any) => { - const clients: Client[] = response['hydra:member']; - const validClients = clients.filter(client => client.uuid && client['@id']); - if (validClients.length === 0) return; + if (!node.uuid) return; - validClients.forEach(client => { - this.syncingClientIds.add(client.uuid); - this.subscriptions.add( - this.http.post(`${this.baseUrl}${client['@id']}/agent/status`, {}).subscribe({ - next: () => this.syncingClientIds.delete(client.uuid), - error: () => this.syncingClientIds.delete(client.uuid), - }) - ); - }); - } - }); + this.isCheckingNodeStatus = true; + this.selectedClients.data.forEach(c => c.uuid && this.syncingClientIds.add(c.uuid)); + + this.subscriptions.add( + this.http.post<{ results: Array<{ uuid: string; ip: string; status: string; success: boolean }> }>( + `${this.baseUrl}/organizational-units/${node.uuid}/agent/status`, + {} + ).subscribe({ + next: (response) => { + this.isCheckingNodeStatus = false; + const statusMap = new Map(response.results.map(r => [r.uuid, r.status])); + response.results.forEach(r => this.syncingClientIds.delete(r.uuid)); + this.selectedClients.data = this.selectedClients.data.map(client => { + const newStatus = statusMap.get(client.uuid); + return newStatus ? { ...client, status: newStatus } : client; + }); + this.arrayClients = this.selectedClients.data; + this.calculateLocalStats(); + this.toastr.success('Estado del aula actualizado'); + }, + error: () => { + this.isCheckingNodeStatus = false; + this.selectedClients.data.forEach(c => c.uuid && this.syncingClientIds.delete(c.uuid)); + this.toastr.error('Error al comprobar el estado del aula'); + }, + }) + ); } diff --git a/ogWebconsole/src/app/components/groups/model/model.ts b/ogWebconsole/src/app/components/groups/model/model.ts index f85cc05..d12df49 100644 --- a/ogWebconsole/src/app/components/groups/model/model.ts +++ b/ogWebconsole/src/app/components/groups/model/model.ts @@ -77,6 +77,7 @@ export interface TreeNode { export interface FlatNode { id?: string; + uuid?: string; name: string; type: string; level: number;