From d0b6da56164a03e267fabeee3a37b1a4debdb504 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 14 Oct 2024 13:17:47 +0200 Subject: [PATCH] refs #614. Integration DHCP --- ogWebconsole/Dockerfile | 14 ++ ogWebconsole/src/app/app-routing.module.ts | 4 +- ogWebconsole/src/app/app.module.ts | 6 +- .../client-view/client-view.component.html | 2 +- .../client-view/client-view.component.ts | 2 +- .../ogboot/images/images.component.html | 5 +- .../ogboot/images/images.component.ts | 10 +- .../ogboot-status/ogboot-status.component.css | 34 ++-- .../add-clients-to-subnet.component.html | 30 ++-- .../add-clients-to-subnet.component.ts | 75 +++++++-- .../create-subnet/create-subnet.component.css | 40 ++++- .../create-subnet.component.html | 73 ++++++--- .../create-subnet/create-subnet.component.ts | 83 ++++++++-- .../og-dhcp-subnets.component.html | 50 ++++-- .../og-dhcp-subnets.component.ts | 151 ++++++++++++------ .../server-info-dialog.component.css | 0 .../server-info-dialog.component.html | 7 + .../server-info-dialog.component.spec.ts | 23 +++ .../server-info-dialog.component.ts | 12 ++ .../status/status.component.css | 93 +++++++++++ .../status/status.component.html | 61 +++++++ .../status/status.component.spec.ts | 23 +++ .../status/status.component.ts | 58 +++++++ .../app/layout/sidebar/sidebar.component.html | 10 +- .../app/layout/sidebar/sidebar.component.ts | 2 - 25 files changed, 703 insertions(+), 165 deletions(-) create mode 100644 ogWebconsole/Dockerfile create mode 100644 ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.css create mode 100644 ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.html create mode 100644 ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.spec.ts create mode 100644 ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.ts create mode 100644 ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.css create mode 100644 ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.html create mode 100644 ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.spec.ts create mode 100644 ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.ts diff --git a/ogWebconsole/Dockerfile b/ogWebconsole/Dockerfile new file mode 100644 index 0000000..84d613f --- /dev/null +++ b/ogWebconsole/Dockerfile @@ -0,0 +1,14 @@ +FROM node:22.1.0 + +WORKDIR /app + +RUN npm install -g npm@latest + +RUN npm install -g @angular/cli@^12.0.0 + +COPY . /app +RUN npm install + +EXPOSE 4200 + +CMD ["ng", "serve", "--host", "0.0.0.0", "--disable-host-check"] diff --git a/ogWebconsole/src/app/app-routing.module.ts b/ogWebconsole/src/app/app-routing.module.ts index 5665fc6..160dd61 100644 --- a/ogWebconsole/src/app/app-routing.module.ts +++ b/ogWebconsole/src/app/app-routing.module.ts @@ -20,6 +20,7 @@ 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 { StatusComponent } from "./components/ogdhcp/og-dhcp-subnets/status/status.component"; const routes: Routes = [ { path: '', redirectTo: 'auth/login', pathMatch: 'full' }, { @@ -36,7 +37,8 @@ const routes: Routes = [ { path: 'pxe-boot-file', component: PxeBootFilesComponent }, { path: 'ogboot-status', component: OgbootStatusComponent }, { path: 'dhcp', component: OgdhcpComponent }, - { path: 'dhcp-subnets', component: OgDhcpSubnetsComponent }, + { path: 'subnets', component: OgDhcpSubnetsComponent }, + { path: 'ogdhcp-status', component: StatusComponent }, { path: 'commands', component: CommandsComponent }, { path: 'commands-groups', component: CommandsGroupsComponent }, { path: 'commands-task', component: CommandsTaskComponent }, diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts index 9b60f72..4353e27 100644 --- a/ogWebconsole/src/app/app.module.ts +++ b/ogWebconsole/src/app/app.module.ts @@ -100,6 +100,8 @@ import { ClientTabViewComponent } from './components/groups/components/client-ta import { AdvancedSearchComponent } from './components/groups/components/advanced-search/advanced-search.component'; import { TaskLogsComponent } from './components/commands/commands-task/task-logs/task-logs.component'; import { OrganizationalUnitTabViewComponent } from './components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component'; +import { ServerInfoDialogComponent } from './components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component'; +import { StatusComponent } from './components/ogdhcp/og-dhcp-subnets/status/status.component'; @NgModule({ declarations: [ AppComponent, @@ -156,7 +158,9 @@ import { OrganizationalUnitTabViewComponent } from './components/groups/componen ClientTabViewComponent, AdvancedSearchComponent, TaskLogsComponent, - OrganizationalUnitTabViewComponent + OrganizationalUnitTabViewComponent, + ServerInfoDialogComponent, + StatusComponent ], bootstrap: [AppComponent], imports: [BrowserModule, diff --git a/ogWebconsole/src/app/components/groups/shared/client-view/client-view.component.html b/ogWebconsole/src/app/components/groups/shared/client-view/client-view.component.html index 7cbdd4d..884f09c 100644 --- a/ogWebconsole/src/app/components/groups/shared/client-view/client-view.component.html +++ b/ogWebconsole/src/app/components/groups/shared/client-view/client-view.component.html @@ -58,6 +58,6 @@ - + diff --git a/ogWebconsole/src/app/components/groups/shared/client-view/client-view.component.ts b/ogWebconsole/src/app/components/groups/shared/client-view/client-view.component.ts index 63ccb03..b2fa4d0 100644 --- a/ogWebconsole/src/app/components/groups/shared/client-view/client-view.component.ts +++ b/ogWebconsole/src/app/components/groups/shared/client-view/client-view.component.ts @@ -26,12 +26,12 @@ export class ClientViewComponent { networkData = [ {property: 'Menú', value: this.data.client.menu ? this.data.client.menu.description : ''}, {property: 'Perfil hardware', value: this.data.client.hardwareProfile ? this.data.client.hardwareProfile.description : ''}, + {property: 'Subred', value: this.data.client.subnet}, {property: 'OGlive', value: ''}, {property: 'Autoexec', value: ''}, {property: 'Repositorio', value: ''}, {property: 'Validacion', value: ''}, {property: 'Página login', value: ''}, - {property: 'Página validacion', value: ''}, {property: 'Fecha de creación', value: this.data.client.createdAt}, {property: 'Creado por', value: this.data.client.createdBy} ]; diff --git a/ogWebconsole/src/app/components/ogboot/images/images.component.html b/ogWebconsole/src/app/components/ogboot/images/images.component.html index 675387d..a82efb4 100644 --- a/ogWebconsole/src/app/components/ogboot/images/images.component.html +++ b/ogWebconsole/src/app/components/ogboot/images/images.component.html @@ -2,15 +2,12 @@ Sincronización ogBoot - - {{ getIcon().name }} -

Oglives creados en servidor ogBoot: {{ alertMessage }}

Oglives creados en servidor ogCore (base de datos): {{ length }}

- +
diff --git a/ogWebconsole/src/app/components/ogboot/images/images.component.ts b/ogWebconsole/src/app/components/ogboot/images/images.component.ts index 8b3980f..a54dad1 100644 --- a/ogWebconsole/src/app/components/ogboot/images/images.component.ts +++ b/ogWebconsole/src/app/components/ogboot/images/images.component.ts @@ -199,15 +199,7 @@ export class ImagesComponent implements OnInit { }); } - getIcon(): { name: string, color: string } { - if (this.alertMessage) { - return { name: 'check_circle', color: 'green' }; - } else { - return { name: 'cancel', color: 'red' }; - } - } - - syncOgCore(): void { + syncOgBoot(): void { this.http.post(`${this.apiUrl}/sync`, {}) .subscribe(response => { this.toastService.success('Sincronización completada'); diff --git a/ogWebconsole/src/app/components/ogboot/ogboot-status/ogboot-status.component.css b/ogWebconsole/src/app/components/ogboot/ogboot-status/ogboot-status.component.css index 080a023..29859f4 100644 --- a/ogWebconsole/src/app/components/ogboot/ogboot-status/ogboot-status.component.css +++ b/ogWebconsole/src/app/components/ogboot/ogboot-status/ogboot-status.component.css @@ -10,33 +10,33 @@ }.dashboard { padding: 20px; } - + .disk-usage-container { display: flex; align-items: flex-start; margin-bottom: 20px; } - + .disk-usage { flex: 2; margin-right: 20px; } - + .services-status { flex: 1; } - + .services-status ul { list-style-type: none; padding: 0; } - + .services-status li { margin: 5px 0; display: flex; align-items: center; } - + .status-led { width: 10px; height: 10px; @@ -44,29 +44,29 @@ display: inline-block; margin-right: 10px; } - + .status-led.active { background-color: green; } - + .status-led.inactive { background-color: red; } - + .installed-oglives { margin-top: 20px; } - + table { width: 100%; border-collapse: collapse; } - + th, td { border: 1px solid #ddd; padding: 8px; } - + th { background-color: #f4f4f4; } @@ -77,13 +77,13 @@ gap: 10px; /* Espacio entre botones */ margin-top: 50px; } - - - + + + .btn:first-child { margin-left: 0; } - + .btn:last-child { margin-right: 0; - } \ No newline at end of file + } diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.html b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.html index 8a49cfc..3588c5a 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.html @@ -1,18 +1,26 @@ -

Añade clientes a a {{data.subnetName}}

+

Añade clientes a {{data.subnetName}}

-
- -

Cargando clientes...

-
- - Añadir clientes - - - {{ client.name }} (IP: {{ client.ip }}, MAC: {{ client.mac }}) + + + + + {{ client.name }} - + + +
+

Clientes seleccionados:

+
    +
  • + {{ client.name }} + +
  • +
+
diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.ts index 6b4190a..8efab27 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.ts @@ -1,6 +1,10 @@ import { Component, OnInit, Inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import {Observable, startWith} from "rxjs"; +import {map} from "rxjs/operators"; +import {FormControl} from "@angular/forms"; +import {ToastrService} from "ngx-toastr"; @Component({ selector: 'app-add-clients-to-subnet', @@ -12,46 +16,87 @@ export class AddClientsToSubnetComponent implements OnInit { clients: any[] = []; selectedClients: any[] = []; loading: boolean = true; + filters: { [key: string]: string } = {}; + filteredClients!: Observable; + clientControl = new FormControl(); constructor( private http: HttpClient, public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: { subnetUuid: string, subnetName: string } + private toastService: ToastrService, + @Inject(MAT_DIALOG_DATA) public data: { subnetUuid: string, subnetName: string } ) {} ngOnInit(): void { console.log('Selected subnet UUID:', this.data); this.loading = true; - this.http.get(`${this.baseUrl}/clients?page=1&itemsPerPage=30`).subscribe( + this.loadClients(); + + this.filteredClients = this.clientControl.valueChanges.pipe( + startWith(''), + map(value => (typeof value === 'string' ? value : value?.name)), + map(name => (name ? this._filterClients(name) : this.clients.slice())) + ); + } + + loadClients() { + this.http.get( `${this.baseUrl}/clients?&page=1&itemsPerPage=10000&exists[subnet]=false`).subscribe( response => { this.clients = response['hydra:member']; this.loading = false; }, error => { - console.error('Error fetching clients:', error); + console.error('Error fetching parent units:', error); this.loading = false; } ); } save() { - const postData = { - clients: JSON.stringify(this.selectedClients.map(client => client.uuid)) - }; + this.selectedClients.forEach(client => { + const postData = { + client: client['@id'] + }; - this.http.post(`${this.baseUrl}/og-dhcp/server/${this.data.subnetUuid}/post-host`, postData).subscribe( - response => { - console.log('Clients assigned successfully:', response); - this.dialogRef.close(this.selectedClients); - }, - error => { - console.error('Error assigning clients:', error); - } - ); + this.http.post(`${this.baseUrl}/og-dhcp/server/${this.data.subnetUuid}/post-host`, postData).subscribe( + response => { + this.toastService.success(`Cliente ${client.name} asignado correctamente`); + }, + error => { + console.error(`Error al asignar el cliente ${client.name}:`, error); + this.toastService.error(`Error al asignar el cliente ${client.name}: ${error.error['hydra:description']}`); + } + ); + }); + + this.dialogRef.close(this.selectedClients); } close() { this.dialogRef.close(); } + + removeClient(client: any) { + const index = this.selectedClients.indexOf(client); + if (index >= 0) { + this.selectedClients.splice(index, 1); + } + } + + private _filterClients(name: string): any[] { + const filterValue = name.toLowerCase(); + return this.clients.filter(client => client.name.toLowerCase().includes(filterValue)); + } + + displayFnClient(client: any): string { + return client && client.name ? client.name : ''; + } + + onOptionClientSelected(client: any) { + if (!this.selectedClients.includes(client)) { + this.selectedClients.push(client); + } + this.clientControl.setValue(''); + } } diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.css b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.css index 6be2509..6f0fb98 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.css +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.css @@ -1,8 +1,36 @@ .full-width { - width: 100%; - } - - form{ + width: 100%; +} + +form{ + padding: 20px; +} + +.spacing-container { + margin-top: 20px; + margin-bottom: 16px; +} + +.list-item-content { + display: flex; + align-items: flex-start; /* Alinea el contenido al inicio */ + justify-content: space-between; /* Espacio entre los textos y los íconos */ + width: 100%; /* Asegúrate de que el contenido ocupe todo el ancho */ +} + +.text-content { + flex-grow: 1; + margin-right: 16px; + margin-left: 10px; +} + +.icon-container { + display: flex; + align-items: center; +} + +.right-icon { + margin-left: 8px; + cursor: pointer; +} - padding: 20px; - } \ No newline at end of file diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.html b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.html index dc06c5b..f7b64f5 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.html @@ -1,27 +1,56 @@ -

Añadir configuración de red

+

{{ isEditMode ? 'Editar' : 'Añadir' }} subred

+ - - Nombre - - - - Netmask - - - - Dirección IP - - - - Next Server - - - - Boot File Name - - + + +
+ + Nombre + + + + Netmask + + + + Dirección IP + + + + Next Server + + + + Boot File Name + + +
+
+ + + + + +
+ computer +
+
{{ client.name }}
+
{{ client.mac }}
+
+
+ +
+
+
+
+
+
+
+ - + diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.ts index 205381a..7cb8a79 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.ts @@ -1,7 +1,8 @@ import { HttpClient } from '@angular/common/http'; import { Component, Inject, OnInit } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; import { ToastrService } from 'ngx-toastr'; +import {DeleteModalComponent} from "../../../../shared/delete_modal/delete-modal/delete-modal.component"; @Component({ selector: 'app-create-subnet', @@ -10,21 +11,42 @@ import { ToastrService } from 'ngx-toastr'; }) export class CreateSubnetComponent implements OnInit { baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; + subnetId: string | null = null; name: string = ''; netmask: string = ''; ipAddress: string = ''; nextServer: string = ''; bootFileName: string = ''; + syncronized: boolean = false; + serverId: number = 0; + clients: any[] = []; + isEditMode: boolean = false; constructor( private toastService: ToastrService, private http: HttpClient, public dialogRef: MatDialogRef, + public dialog: MatDialog, @Inject(MAT_DIALOG_DATA) public data: any ) { } ngOnInit(): void { + if (this.data) { + this.loadData(); + this.isEditMode = true; + } + } + loadData() { + this.subnetId = this.data.uuid; + this.name = this.data.name; + this.netmask = this.data.netmask; + this.ipAddress = this.data.ipAddress; + this.nextServer = this.data.nextServer; + this.bootFileName = this.data.bootFileName; + this.syncronized = this.data.syncronized; + this.serverId = this.data.serverId; + this.clients = this.data.clients } onNoClick(): void { @@ -40,17 +62,52 @@ export class CreateSubnetComponent implements OnInit { bootFileName: this.bootFileName }; - this.http.post(`${this.baseUrl}/subnets`, payload) - .subscribe({ - next: (response) => { - console.log('Success:', response); - this.toastService.success('Configuración de red añadida exitosamente'); - this.dialogRef.close(); - }, - error: (error) => { - console.error('Error:', error); - this.toastService.error(error.error['hydra:description']); - } - }); + if (!this.data){ + this.http.post(`${this.baseUrl}/subnets`, payload) + .subscribe({ + next: (response) => { + console.log('Success:', response); + this.toastService.success('Configuración de red añadida exitosamente'); + this.dialogRef.close(); + }, + error: (error) => { + console.error('Error:', error); + this.toastService.error(error.error['hydra:description']); + } + }); + } else { + this.http.patch(`${this.baseUrl}/subnets/${this.subnetId}`, payload) + .subscribe({ + next: (response) => { + console.log('Success:', response); + this.toastService.success('Configuración de red actualizada exitosamente'); + this.dialogRef.close(); + }, + error: (error) => { + console.error('Error:', error); + this.toastService.error(error.error['hydra:description']); + } + }); + } + } + + deleteClient(client: any): void { + const dialogRef = this.dialog.open(DeleteModalComponent, { + width: '300px', + data: { name: client.name } + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + this.http.delete(`${this.baseUrl}/og-dhcp/server/${this.subnetId}/delete-host/${client.uuid}`, {}).subscribe({ + next: () => { + this.toastService.success('Cliente eliminado exitosamente'); + this.dialogRef.close(); + }, + error: (error) => { + this.toastService.error(error.error['hydra:description']); + } + }); + }}) } } diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html index 23ffbad..5b85999 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html @@ -1,16 +1,13 @@ - Información de Subnets - - {{ getIcon().name }} - + Información en servidor ogDHCP -

Subnets sincronizadas: {{ alertMessage }}

-

Número de subnets en base de datos: {{ length }}

-
- + +
+
+
@@ -25,7 +22,7 @@
- Buscar nombre de imagen + Buscar nombre de la subred search Pulsar 'enter' para buscar @@ -42,13 +39,35 @@ search Pulsar 'enter' para buscar + + Buscar Boot file name + + search + Pulsar 'enter' para buscar +
@@ -59,10 +78,15 @@ diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.ts index 9832467..e6a2bcf 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.ts @@ -7,6 +7,7 @@ import { HttpClient } from '@angular/common/http'; import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component'; import { ToastrService } from 'ngx-toastr'; import { AddClientsToSubnetComponent } from './add-clients-to-subnet/add-clients-to-subnet.component'; +import {ServerInfoDialogComponent} from "./server-info-dialog/server-info-dialog.component"; export interface Subnet { '@id': string; @@ -16,6 +17,9 @@ export interface Subnet { ipAddress: string; nextServer: string; bootFileName: string; + synchronized: boolean; + serverId: number; + clients: []; createdAt: string; createdBy: string; uuid: string; @@ -29,7 +33,7 @@ export interface Subnet { }) export class OgDhcpSubnetsComponent { baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; - displayedColumns: string[] = ['id', 'name', 'netmask', 'ipAddress', 'nextServer', 'bootFileName', 'actions']; + displayedColumns: string[] = ['id', 'name', 'netmask', 'ipAddress', 'nextServer', 'bootFileName', 'synchronized', 'serverId', 'clients', 'actions']; dataSource = new MatTableDataSource([]); length = 0; itemsPerPage: number = 10; @@ -47,16 +51,22 @@ export class OgDhcpSubnetsComponent { { columnDef: 'ipAddress', header: 'IP Address', cell: (subnet: Subnet) => subnet.ipAddress }, { columnDef: 'nextServer', header: 'Next Server', cell: (subnet: Subnet) => subnet.nextServer }, { columnDef: 'bootFileName', header: 'Boot File Name', cell: (subnet: Subnet) => subnet.bootFileName }, + { columnDef: 'synchronized', header: 'Sincronizado', cell: (subnet: Subnet) => `${subnet.synchronized}`}, + { columnDef: 'serverId', header: 'IP Servidor DHCP', cell: (subnet: Subnet) => subnet.serverId }, + { columnDef: 'clients', header: 'Lista de clientes', cell: (subnet: Subnet) => `${subnet.clients}`}, ]; + private apiUrl = `${this.baseUrl}/subnets`; + constructor(public dialog: MatDialog, private http: HttpClient, private toastService: ToastrService) {} ngOnInit() { this.loadSubnets(); + this.loadAlert() } loadSubnets() { - this.http.get(`${this.baseUrl}/subnets?page=1&itemsPerPage=${this.itemsPerPage}`).subscribe({ + this.http.get(`${this.baseUrl}/subnets?page=${this.page + 1}&itemsPerPage=${this.itemsPerPage}`).subscribe({ next: (response) => { this.dataSource.data = response['hydra:member']; this.length = response['hydra:totalItems']; @@ -72,75 +82,129 @@ export class OgDhcpSubnetsComponent { } syncSubnets() { - console.log('Sincronizando subnets...'); + this.http.post(`${this.apiUrl}/sync`, {}) + .subscribe(response => { + this.toastService.success('Sincronización completada'); + this.loadSubnets() + }, error => { + console.error('Error al sincronizar', error); + this.toastService.error('Error al sincronizar'); + }); + } + + toggleAction(subnet: any, action:string): void { + switch (action) { + case 'get': + this.http.post(`${this.baseUrl}/og-dhcp/server/${subnet.uuid}/get`, {}).subscribe({ + next: () => { + this.toastService.success('Subred sincronizada con servidor'); + this.loadSubnets() + }, + error: (error) => { + console.error('Error al crear subred en servidor', error); + this.toastService.error(error.error['hydra:description']); + } + }); + break; + case 'post': + this.http.post(`${this.baseUrl}/og-dhcp/server/${subnet.uuid}/post`, {}).subscribe({ + next: () => { + this.toastService.success('Petición de instalación enviada'); + this.loadSubnets() + }, + error: (error) => { + console.error('Error al crear subred en servidor', error); + this.toastService.error(error.error['hydra:description']); + } + }); + break; + case 'put': + this.http.put(`${this.baseUrl}/og-dhcp/server/${subnet.uuid}/put`, {}).subscribe({ + next: () => { + this.toastService.success('Petición de actualizacion enviada'); + this.loadSubnets(); + }, + error: (error) => { + console.error('Error al actualizar la subred en el servidor', error); + this.toastService.error(error.error['hydra:description']); + } + }); + break; + case 'delete': + const dialogRef = this.dialog.open(DeleteModalComponent, { + width: '300px', + data: { name: subnet.name } + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + this.http.delete(`${this.baseUrl}/og-dhcp/server/${subnet.uuid}/delete`, {}).subscribe({ + next: () => { + this.toastService.success('Subred eliminada exitosamente'); + this.loadSubnets(); + }, + error: (error) => { + console.error('Error al eliminar la subred', error); + this.toastService.error(error.error['hydra:description']); + } + }); + }}) + break; + default: + console.error('Acción no soportada:', action); + break; + } } addSubnet() { - console.log('Añadiendo nueva subnet...'); const dialogRef = this.dialog.open(CreateSubnetComponent, { - width: '400px' + width: '600px' }); dialogRef.afterClosed().subscribe(result => { - console.log('The dialog was closed'); this.loadSubnets() }); } editSubnet(subnet: Subnet) { - console.log('Editando subnet:', subnet); const dialogRef = this.dialog.open(CreateSubnetComponent, { - width: '400px', - data: { subnet } + width: '600px', + data: subnet }); dialogRef.afterClosed().subscribe(result => { - console.log('The dialog was closed'); this.loadSubnets() }); } - deleteSubnet(subnet: Subnet): void { - console.log(subnet); - const dialogRef = this.dialog.open(DeleteModalComponent, { - width: '300px', - data: { name: subnet.name } - }); + loadAlert() { + this.http.get(`${this.baseUrl}/og-dhcp/server/get-collection`) + .subscribe(response => { + // @ts-ignore + this.alertMessage = response.message + }, error => { + console.error('Error al cargar la información del alert', error); + }); + } - dialogRef.afterClosed().subscribe(result => { - if (result) { - const apiUrl = `${this.baseUrl}${subnet['@id']}`; - - this.http.delete(apiUrl).subscribe({ - next: () => { - console.log('Subnet deleted successfully'); - this.dataSource.data = this.dataSource.data.filter(s => s !== subnet); - this.length = this.dataSource.data.length; - this.toastService.success('Subnet deleted successfully'); - }, - error: (error) => { - console.error('Error deleting subnet:', error); - } - }); - } else { - console.log('Subnet deletion cancelled'); + openSubnetInfoDialog() { + this.loadAlert() + this.dialog.open(ServerInfoDialogComponent, { + width: '600px', + data: { + alertMessage: this.alertMessage, + length: this.length } }); } - updateSubnet() { - console.log('Update Subnet action selected'); - } - addClientsToSubnet(subnet: Subnet) { - const dialogRef = this.dialog.open(AddClientsToSubnetComponent, { width: '600px', data: { subnetUuid: subnet.uuid, subnetName: subnet.name } }); dialogRef.afterClosed().subscribe(result => { - console.log('The dialog was closed'); this.loadSubnets(); }); } @@ -148,13 +212,6 @@ export class OgDhcpSubnetsComponent { onPageChange(event: any) { this.page = event.pageIndex; this.itemsPerPage = event.pageSize; - } - - getIcon(): { name: string, color: string } { - if (this.alertMessage) { - return { name: 'check_circle', color: 'green' }; - } else { - return { name: 'cancel', color: 'red' }; - } + this.loadSubnets(); } } diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.css b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.css new file mode 100644 index 0000000..e69de29 diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.html b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.html new file mode 100644 index 0000000..d8044f8 --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.html @@ -0,0 +1,7 @@ +

Información de Subnets

+ +
{{ data | json }}
+
+ + + diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.spec.ts new file mode 100644 index 0000000..38894cb --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ServerInfoDialogComponent } from './server-info-dialog.component'; + +describe('ServerInfoDialogComponent', () => { + let component: ServerInfoDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ServerInfoDialogComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ServerInfoDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.ts new file mode 100644 index 0000000..dff187f --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.ts @@ -0,0 +1,12 @@ +import {Component, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA} from "@angular/material/dialog"; + +@Component({ + selector: 'app-server-info-dialog', + templateUrl: './server-info-dialog.component.html', + styleUrl: './server-info-dialog.component.css' +}) +export class ServerInfoDialogComponent { + constructor(@Inject(MAT_DIALOG_DATA) public data: any) {} + +} diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.css b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.css new file mode 100644 index 0000000..d0cc96f --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.css @@ -0,0 +1,93 @@ + +.disk-usage-info{ + display: flex; + justify-content: start; + margin-top: 10px; +} + +p { + margin-left: 15px; +}.dashboard { + padding: 20px; + } + +.disk-usage-container { + display: flex; + align-items: flex-start; + margin-bottom: 20px; +} + +.disk-usage { + flex: 2; + margin-right: 20px; +} + +.services-status { + flex: 1; +} + +.services-status ul { + display: flex; + flex-direction: column; + justify-content: center; + list-style-type: none; + padding: 0; +} + +.services-status li { + justify-content: left; + margin: 5px 0; + display: flex; + align-items: center; +} + +.status-led { + width: 10px; + height: 10px; + border-radius: 50%; + display: inline-block; + margin-right: 10px; +} + +.status-led.active { + background-color: green; +} + +.status-led.inactive { + background-color: red; +} + +.installed-oglives { + margin-top: 20px; +} + +table { + width: 100%; + border-collapse: collapse; +} + +th, td { + border: 1px solid #ddd; + padding: 8px; +} + +th { + background-color: #f4f4f4; +} + +.button-container { + display: flex; + flex-direction: column; + gap: 10px; /* Espacio entre botones */ + margin-top: 50px; +} + + + +.btn:first-child { + margin-left: 0; +} + +.btn:last-child { + margin-right: 0; +} diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.html b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.html new file mode 100644 index 0000000..917bed9 --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.html @@ -0,0 +1,61 @@ +
+

OgBoot server Status

+ +
+
+

Uso de disco

+ + +
+

Total: {{ diskUsage.total }}

+

Ocupado: {{ diskUsage.used }}

+

Disponible: {{ diskUsage.available }}

+

Libre: {{ diskUsage.percentage }}

+
+
+ +
+

Servicios

+
    +
  • + + {{ service.name }}: {{ service.status }} +
  • +
+
+
+ +
+

Subredes

+
{{ column.header }} - + + + + {{ subnet[column.columnDef] ? 'check_circle' : 'cancel' }} + + + + + + + + + + + {{ column.cell(subnet) }} - - + + + + + +
+ + + + + + + + + + + + + + + + + + +
IDBoot file nameNext serverIpOrdenadores
{{ subnet.id }}{{ subnet['boot-file-name'] }}{{ subnet['next-server'] }}{{ subnet.subnet }}{{ subnet.reservations.length }}
+ + diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.spec.ts new file mode 100644 index 0000000..cb3c1eb --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StatusComponent } from './status.component'; + +describe('StatusComponent', () => { + let component: StatusComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [StatusComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(StatusComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.ts new file mode 100644 index 0000000..44885b3 --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.ts @@ -0,0 +1,58 @@ +import { Component } from '@angular/core'; +import {HttpClient} from "@angular/common/http"; + +@Component({ + selector: 'app-status', + templateUrl: './status.component.html', + styleUrl: './status.component.css' +}) +export class StatusComponent { + baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; + diskUsage: any = {}; + servicesStatus: any = {}; + subnets: any[] = []; + diskUsageChartData: any[] = []; + + view: [number, number] = [1100, 500]; + + gradient: boolean = true; + showLegend: boolean = true; + showLabels: boolean = true; + isDoughnut: boolean = true; + colorScheme: any = { + domain: ['#FF6384', '#3f51b5'] + }; + + constructor(private http: HttpClient) {} + + ngOnInit(): void { + this.loadStatus(); + } + loadStatus(): void { + this.http.get(`${this.baseUrl}/og-dhcp/status`).subscribe(data => { + this.diskUsage = data.message.disk_usage; + this.servicesStatus = data.message.services_status; + this.subnets = data.message.subnets; + + this.diskUsageChartData = [ + { + name: 'Usado', + value: parseFloat(this.diskUsage.used) + }, + { + name: 'Disponible', + value: parseFloat(this.diskUsage.available) + } + ]; + }, error => { + console.error('Error fetching status', error); + }); + } + + getServices(): { name: string, status: string }[] { + return Object.keys(this.servicesStatus).map(key => ({ + name: key, + status: this.servicesStatus[key] + })); + } +} diff --git a/ogWebconsole/src/app/layout/sidebar/sidebar.component.html b/ogWebconsole/src/app/layout/sidebar/sidebar.component.html index ace6206..c64f683 100644 --- a/ogWebconsole/src/app/layout/sidebar/sidebar.component.html +++ b/ogWebconsole/src/app/layout/sidebar/sidebar.component.html @@ -60,7 +60,13 @@ - + + + analytics + Estado + + + lan Subnets @@ -141,5 +147,5 @@ - + diff --git a/ogWebconsole/src/app/layout/sidebar/sidebar.component.ts b/ogWebconsole/src/app/layout/sidebar/sidebar.component.ts index 8212934..963703f 100644 --- a/ogWebconsole/src/app/layout/sidebar/sidebar.component.ts +++ b/ogWebconsole/src/app/layout/sidebar/sidebar.component.ts @@ -16,11 +16,9 @@ export class SidebarComponent { showCommandSub: boolean = false; toggleOgBootSub() { - alert('El correcto funcionamiento de este componente está sujeto a la disponibilidad de la API de ogBoot'); this.showOgBootSub = !this.showOgBootSub; } toggleOgDhcpSub() { - alert('El correcto funcionamiento de este componente está sujeto a la disponibilidad de la API de ogDHCP'); this.showOgDhcpSub = !this.showOgDhcpSub; } toggleCommandSub() {