diff --git a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.html b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.html index 6c1fbc2..f1a1858 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.html +++ b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.html @@ -10,9 +10,6 @@ - - Clientes: {{ getClientesNames() }} -
diff --git a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.ts b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.ts index 89e90e6..68d46bd 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.ts +++ b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.ts @@ -12,7 +12,6 @@ export class CreatePxeBootFileComponent implements OnInit { baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; pxeTemplates: any[] = []; selectedPxeTemplate: string | undefined; - clientes: string[] = []; selectedElements: any; isEditMode: boolean = false; @@ -24,8 +23,7 @@ export class CreatePxeBootFileComponent implements OnInit { ) {} ngOnInit(): void { - this.selectedElements = this.data.clients; - this.clientes = this.selectedElements.map((client: { uuid: any }) => `/clients/${client.uuid}`); + this.selectedElements = this.data this.loadPxeTemplates(); if (this.data.bootFile) { this.isEditMode = true; @@ -33,10 +31,6 @@ export class CreatePxeBootFileComponent implements OnInit { } } - getClientesNames(): string { - return this.selectedElements.map((client: { name: any }) => client.name).join(', '); - } - loadPxeTemplates(): void { this.http.get(`${this.baseUrl}/pxe-templates?page=1&itemsPerPage=30`) .subscribe((response: any) => { @@ -54,7 +48,7 @@ export class CreatePxeBootFileComponent implements OnInit { if (this.selectedPxeTemplate) { const payload = { template: `/pxe-templates/${this.selectedPxeTemplate}`, - clients: this.clientes + clients: this.selectedElements }; if (this.isEditMode && this.data.bootFile) { diff --git a/ogWebconsole/src/app/components/ogboot/pxe-images/info-image/info-image/info-image.component.html b/ogWebconsole/src/app/components/ogboot/pxe-images/info-image/info-image/info-image.component.html index 3620677..87d5a9e 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-images/info-image/info-image/info-image.component.html +++ b/ogWebconsole/src/app/components/ogboot/pxe-images/info-image/info-image/info-image.component.html @@ -1,9 +1,6 @@

Imagen ogLive

-

Nombre

-

{{name}}

-

URL

-

{{downloadUrl}}

+
{{ data | json }}
diff --git a/ogWebconsole/src/app/components/ogboot/pxe-images/info-image/info-image/info-image.component.ts b/ogWebconsole/src/app/components/ogboot/pxe-images/info-image/info-image/info-image.component.ts index 1f4e282..0d424e0 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-images/info-image/info-image/info-image.component.ts +++ b/ogWebconsole/src/app/components/ogboot/pxe-images/info-image/info-image/info-image.component.ts @@ -9,17 +9,14 @@ import { ToastrService } from 'ngx-toastr'; styleUrls: ['./info-image.component.css'] }) export class InfoImageComponent { - name: string; - downloadUrl: string; + constructor( private toastService: ToastrService, private http: HttpClient, public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: { name: string, downloadUrl: string, uuid: string } + @Inject(MAT_DIALOG_DATA) public data: any ) { - this.name = data.name; - this.downloadUrl = data.downloadUrl; } onNoClick(): void { diff --git a/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.css b/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.css index d744f99..449d540 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.css +++ b/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.css @@ -12,35 +12,6 @@ margin: 20px 0; } -.lists-container { - padding: 16px; -} - -.imagesLists-container { - flex: 1; -} - -.card.unidad-card { - height: 100%; - box-sizing: border-box; -} - -.image-container { - display: flex; - align-items: center; - margin-bottom: 16px; - border-bottom: 1px solid rgba(122, 122, 122, 0.555); -} - -.image-container h4 { - margin: 0; - flex: 1; -} - -.image-name{ - cursor: pointer; -} - table { width: 100%; margin-top: 50px; diff --git a/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.html b/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.html index 25ad249..96e0993 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.html +++ b/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.html @@ -47,8 +47,7 @@ - diff --git a/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.ts b/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.ts index c1c739d..1509226 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.ts +++ b/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.ts @@ -10,6 +10,8 @@ import { DatePipe } from "@angular/common"; import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component'; import {DataService} from "./data.service"; import {ServerInfoDialogComponent} from "../../ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component"; +import {ShowTemplateContentComponent} from "../pxe/show-template-content/show-template-content.component"; +import {Observable} from "rxjs"; @Component({ selector: 'app-pxe-images', @@ -56,6 +58,11 @@ export class PXEimagesComponent implements OnInit { header: 'Imagen instalada en ogBoot', cell: (user: any) => `${user.installed}` }, + { + columnDef: 'status', + header: 'Estado', + cell: (image: any) => `${image.status}` + }, { columnDef: 'createdAt', header: 'Fecha de creación', @@ -115,40 +122,36 @@ export class PXEimagesComponent implements OnInit { case 'set-default': this.http.post(`${this.apiUrl}/server/${image.uuid}/set-default`, {}).subscribe({ next: () => { - console.log('Imagen cambiada'); this.toastService.success('Petición de cambio de imagen enviada'); this.search(); }, error: (error) => { - console.error('Error al cambiar la imagen:', error); - this.toastService.error('Error al instalar la imagen por defecto'); + console.error(error.error['hydra:description']); + this.toastService.error('Error:' + error.error['hydra:description']); } }); break; case 'install': this.http.post(`${this.apiUrl}/server/${image.uuid}/install`, {}).subscribe({ next: () => { - console.log('Imagen cambiada'); this.toastService.success('Petición de instalación enviada'); this.search(); }, error: (error) => { - console.error('Error al instalar la imagen:', error); - this.toastService.error('Error al instalar la imagen'); + console.error(error.error['hydra:description']); + this.toastService.error('Error:' + error.error['hydra:description']); } }); break; case 'uninstall': this.http.post(`${this.apiUrl}/server/${image.uuid}/uninstall`, {}).subscribe({ next: () => { - console.log('Imagen cambiada'); this.toastService.success('Petición de desinstalación enviada'); - /* this.deleteImage(image); */ this.search(); }, error: (error) => { - console.error('Error al desinstalar la imagen:', error); - this.toastService.error('Error al desinstalar la imagen'); + console.error(error.error['hydra:description']); + this.toastService.error('Error:' + error.error['hydra:description']); } }); break; @@ -171,6 +174,35 @@ export class PXEimagesComponent implements OnInit { }); } + deleteImage(image: any): void { + const dialogRef = this.dialog.open(DeleteModalComponent, { + width: '400px', + data: { name: image.name } + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + const apiUrl = `${this.baseUrl}${image['@id']}`; + + this.http.delete(apiUrl).subscribe({ + next: () => { + this.search(); + this.toastService.success('oG Live deleted successfully'); + }, + error: (error) => { + this.toastService.error(error.error['hydra:description']); + } + }); + } else { + console.log('ogLive deletion cancelled'); + } + }); + } + + showOgLive(event: MouseEvent, data: any): void { + event.stopPropagation(); + const dialogRef = this.dialog.open(InfoImageComponent, { data: { data }, width: '700px'}); + } applyFilter() { this.http.get(`${this.apiUrl}?page=${this.page}&itemsPerPage=${this.itemsPerPage}`).subscribe({ @@ -190,25 +222,26 @@ export class PXEimagesComponent implements OnInit { this.applyFilter(); } - loadAlert() { - this.http.get(`${this.apiUrl}/server/get-collection`) - .subscribe(response => { - // @ts-ignore - this.alertMessage = response.message - }, error => { - console.error('Error al cargar la información del alert', error); - }); + loadAlert(): Observable { + return this.http.get(`${this.apiUrl}/server/get-collection`); } openSubnetInfoDialog() { - this.loadAlert() - this.dialog.open(ServerInfoDialogComponent, { - width: '600px', - data: { - alertMessage: this.alertMessage, - length: this.length + this.loadAlert().subscribe( + response => { + this.alertMessage = response.message; + + this.dialog.open(ServerInfoDialogComponent, { + width: '600px', + data: { + message: this.alertMessage + } + }); + }, + error => { + console.error('Error al cargar la información del alert', error); } - }); + ); } syncOgBoot(): void { diff --git a/ogWebconsole/src/app/components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component.css b/ogWebconsole/src/app/components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component.css new file mode 100644 index 0000000..f994fc3 --- /dev/null +++ b/ogWebconsole/src/app/components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component.css @@ -0,0 +1,17 @@ +.loading-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100px; +} + +mat-form-field { + width: 100%; +} + +mat-dialog-actions { + display: flex; + justify-content: flex-end; +} + diff --git a/ogWebconsole/src/app/components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component.html b/ogWebconsole/src/app/components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component.html new file mode 100644 index 0000000..3588c5a --- /dev/null +++ b/ogWebconsole/src/app/components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component.html @@ -0,0 +1,29 @@ +

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

+ + + + + + + {{ client.name }} + + + + +
+

Clientes seleccionados:

+
    +
  • + {{ client.name }} + +
  • +
+
+
+ + + + + diff --git a/ogWebconsole/src/app/components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component.spec.ts b/ogWebconsole/src/app/components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component.spec.ts new file mode 100644 index 0000000..5aefd4b --- /dev/null +++ b/ogWebconsole/src/app/components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AddClientsToPxeComponent } from './add-clients-to-pxe.component'; + +describe('AddClientsToPxeComponent', () => { + let component: AddClientsToPxeComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AddClientsToPxeComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(AddClientsToPxeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ogWebconsole/src/app/components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component.ts b/ogWebconsole/src/app/components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component.ts new file mode 100644 index 0000000..f2aeb53 --- /dev/null +++ b/ogWebconsole/src/app/components/ogboot/pxe/add-clients-to-pxe/add-clients-to-pxe.component.ts @@ -0,0 +1,99 @@ +import {Component, Inject} from '@angular/core'; +import {Observable, startWith} from "rxjs"; +import {FormControl} from "@angular/forms"; +import {HttpClient} from "@angular/common/http"; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {ToastrService} from "ngx-toastr"; +import {map} from "rxjs/operators"; + +@Component({ + selector: 'app-add-clients-to-pxe', + templateUrl: './add-clients-to-pxe.component.html', + styleUrl: './add-clients-to-pxe.component.css' +}) +export class AddClientsToPxeComponent { + baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; + clients: any[] = []; + selectedClients: any[] = []; + loading: boolean = true; + filters: { [key: string]: string } = {}; + filteredClients!: Observable; + clientControl = new FormControl(); + + constructor( + private http: HttpClient, + public dialogRef: MatDialogRef, + 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.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[template]=false`).subscribe( + response => { + this.clients = response['hydra:member']; + this.loading = false; + }, + error => { + console.error('Error fetching parent units:', error); + this.loading = false; + } + ); + } + + save() { + const postData = { + clients: this.selectedClients.map(client => client['@id']) + }; + + this.http.post(`${this.baseUrl}/pxe-templates/${this.data.subnetUuid}/add-clients`, postData).subscribe( + response => { + this.toastService.success('Clientes asignados correctamente'); + }, + error => { + this.toastService.error(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/ogboot/pxe/clients/clients.component.css b/ogWebconsole/src/app/components/ogboot/pxe/clients/clients.component.css new file mode 100644 index 0000000..4e5aff4 --- /dev/null +++ b/ogWebconsole/src/app/components/ogboot/pxe/clients/clients.component.css @@ -0,0 +1,47 @@ + +mat-dialog-actions { + margin-top: 20px; + display: flex; + justify-content: flex-end; +} + +button { + margin-left: 10px; +} + +.green-icon { + color: green; +} + +.red-icon { + color: red; +} + + +.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; +} diff --git a/ogWebconsole/src/app/components/ogboot/pxe/clients/clients.component.html b/ogWebconsole/src/app/components/ogboot/pxe/clients/clients.component.html new file mode 100644 index 0000000..ced1090 --- /dev/null +++ b/ogWebconsole/src/app/components/ogboot/pxe/clients/clients.component.html @@ -0,0 +1,25 @@ +

Gestionar clientes

+ + + + +
+ computer +
+
{{ client.name }}
+
{{ client.mac }}
+
+
+ + +
+
+
+
+
+
+ + + diff --git a/ogWebconsole/src/app/components/ogboot/pxe/clients/clients.component.spec.ts b/ogWebconsole/src/app/components/ogboot/pxe/clients/clients.component.spec.ts new file mode 100644 index 0000000..fb60007 --- /dev/null +++ b/ogWebconsole/src/app/components/ogboot/pxe/clients/clients.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ClientsComponent } from './clients.component'; + +describe('ClientsComponent', () => { + let component: ClientsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ClientsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ClientsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ogWebconsole/src/app/components/ogboot/pxe/clients/clients.component.ts b/ogWebconsole/src/app/components/ogboot/pxe/clients/clients.component.ts new file mode 100644 index 0000000..4d08008 --- /dev/null +++ b/ogWebconsole/src/app/components/ogboot/pxe/clients/clients.component.ts @@ -0,0 +1,81 @@ +import {Component, Inject} from '@angular/core'; +import {FormBuilder, FormGroup, Validators} from "@angular/forms"; +import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from "@angular/material/dialog"; +import {HttpClient} from "@angular/common/http"; +import {ToastrService} from "ngx-toastr"; +import {DeleteModalComponent} from "../../../../shared/delete_modal/delete-modal/delete-modal.component"; + +@Component({ + selector: 'app-clients', + templateUrl: './clients.component.html', + styleUrl: './clients.component.css' +}) +export class ClientsComponent { + baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; + templateForm!: FormGroup; + clients: any[] = []; + + constructor( + public dialogRef: MatDialogRef, + public dialog: MatDialog, + private http: HttpClient, + private toastService: ToastrService, + @Inject(MAT_DIALOG_DATA) public data: any + ) {} + + ngOnInit() { + this.getPxeClients() + } + + getPxeClients(): void { + this.http.get(`${this.baseUrl}/clients?template.id=${this.data.data.id}`).subscribe({ + next: data => { + console.log(data['hydra:member']) + this.clients = data['hydra:member'] + }, + error: error => { + console.error('Error al obtener los clientes PXE:', error); + } + }); + } + + addClientToTemplate(client: any): void { + const postData = { + client: client['@id'] + }; + + this.http.post(`${this.baseUrl}/pxe-templates/${this.data.data.uuid}/sync-client`, postData).subscribe( + response => { + this.toastService.success('Clientes asignados correctamente'); + this.getPxeClients() + }, + 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.post(`${this.baseUrl}/pxe-templates/${this.data.uuid}/delete-client`, { client: client['@id'] }).subscribe({ + next: () => { + this.toastService.success('Cliente eliminado exitosamente'); + this.dialogRef.close(); + }, + error: (error) => { + this.toastService.error(error.error['hydra:description']); + } + }); + }}) + } + + onCancel(): void { + this.dialogRef.close(false); + } +} diff --git a/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.css b/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.css index cc364fb..6dfa966 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.css +++ b/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.css @@ -1,7 +1,3 @@ -form { - max-width: 600px; - padding: 20px; -} mat-form-field { width: 100%; @@ -49,3 +45,31 @@ h3 { font-size: 1.2rem; color: #000000; } + +.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; +} diff --git a/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.html b/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.html index 757ea95..c302cb7 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.html +++ b/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.html @@ -1,27 +1,31 @@ -
-

Crear Plantilla PXE

-

Editar Plantilla PXE

+

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

- - Nombre de la Plantilla - - - El nombre de la plantilla es requerido. - - + +
+ - - Contenido de la Plantilla - - - El contenido de la plantilla es requerido. - - + + Nombre de la Plantilla + + + El nombre de la plantilla es requerido. + + - - - - - + + Contenido de la Plantilla + + + El contenido de la plantilla es requerido. + + + +
+
+ + + + + diff --git a/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.ts b/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.ts index ce88760..b16bc94 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.ts +++ b/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.ts @@ -1,8 +1,9 @@ import { HttpClient } from '@angular/common/http'; import { Component, Inject, OnInit } from '@angular/core'; import { FormGroup, FormBuilder, Validators } from '@angular/forms'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import {MatDialogRef, MAT_DIALOG_DATA, MatDialog} from '@angular/material/dialog'; import { ToastrService } from 'ngx-toastr'; +import {DeleteModalComponent} from "../../../../shared/delete_modal/delete-modal/delete-modal.component"; @Component({ selector: 'app-create-pxe-template', @@ -14,9 +15,11 @@ export class CreatePxeTemplateComponent implements OnInit { templateForm!: FormGroup; previewContent: string = ''; isEditMode: boolean = false; + clients: any[] = []; constructor( public dialogRef: MatDialogRef, + public dialog: MatDialog, private http: HttpClient, private fb: FormBuilder, private toastService: ToastrService, @@ -24,8 +27,12 @@ export class CreatePxeTemplateComponent implements OnInit { ) {} ngOnInit() { - this.isEditMode = !!this.data; // Verifica si hay datos inyectados (modo edición) - + this.isEditMode = !!this.data; + + if (this.isEditMode){ + this.getPxeClients() + } + this.templateForm = this.fb.group({ name: [this.data?.name || '', Validators.required], templateContent: [this.data?.templateContent || '', Validators.required] @@ -40,6 +47,17 @@ export class CreatePxeTemplateComponent implements OnInit { } } + getPxeClients(): void { + this.http.get(`${this.baseUrl}/clients?template.id=${this.data.id}`).subscribe({ + next: data => { + this.clients = data['hydra:member'] + }, + error: error => { + console.error('Error al obtener los clientes PXE:', error); + } + }); + } + createPxeTemplate(): void { const formValues = this.templateForm.value; const payload = { @@ -70,18 +88,51 @@ export class CreatePxeTemplateComponent implements OnInit { this.http.patch(`${this.baseUrl}/pxe-templates/${this.data.uuid}`, payload).subscribe({ next: data => { - console.log('Plantilla PXE actualizada:', data); this.toastService.success('Plantilla PXE actualizada exitosamente'); this.dialogRef.close(true); }, error: error => { - console.error('Error al actualizar la plantilla PXE:', error); this.toastService.error('Error al actualizar la plantilla PXE'); this.dialogRef.close(false); } }); } + addClientToTemplate(client: any): void { + const postData = { + client: client['@id'] + }; + + this.http.post(`${this.baseUrl}/pxe-templates/${this.data.uuid}/sync-client`, postData).subscribe( + response => { + this.toastService.success('Clientes asignados correctamente'); + }, + 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.post(`${this.baseUrl}/pxe-templates/${this.data.uuid}/delete-client`, { client: client['@id'] }).subscribe({ + next: () => { + this.toastService.success('Cliente eliminado exitosamente'); + this.dialogRef.close(); + }, + error: (error) => { + this.toastService.error(error.error['hydra:description']); + } + }); + }}) + } + onCancel(): void { this.dialogRef.close(false); } diff --git a/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.css b/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.css index 82a24ac..b9ee046 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.css +++ b/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.css @@ -1,52 +1,9 @@ -.header-container { - display: flex; - justify-content: space-between; - align-items: center; - height: 100px; - padding: 10px; - margin-top: 16px; -} - .title { - font-size: 24px; + font-size: 24px; } .divider { - margin: 20px 0; -} - -.lists-container { - padding: 16px; -} - -.templatesLists-container { - flex: 1; -} - -.card.unidad-card { - height: 100%; - box-sizing: border-box; -} - -.template-container { - display: flex; - align-items: center; - margin-bottom: 16px; - border-bottom: 1px solid rgba(122, 122, 122, 0.555); -} - -.template-container h4 { - margin: 0; - flex: 1; -} - -.mat-icon-button { - margin-left: 16px; - align-self: center; -} - -.template-name{ - cursor: pointer; + margin: 20px 0; } table { @@ -74,10 +31,10 @@ table { } .header-container { - margin-top: 16px; display: flex; justify-content: space-between; align-items: center; + padding: 10px; } .mat-elevation-z8 { @@ -90,66 +47,21 @@ table { margin-bottom: 30px; } -.info-container { - background-color: #e8eaf6; - padding: 16px; - border-radius: 4px; - font-size: 14px; - overflow-x: auto; - margin-top: 16px; - border: 1px solid #c5cae9; +.example-headers-align .mat-expansion-panel-header-description { + justify-content: space-between; + align-items: center; } -.info-container h3 { - margin-top: 0; - font-size: 16px; - color: #000000; +.example-headers-align .mat-mdc-form-field + .mat-mdc-form-field { + margin-left: 8px; } -.info-container p { - margin: 8px 0; - line-height: 1.5; +.example-button-row { + display: table-cell; + max-width: 600px; } -.info-container strong { - color: #0d47a1; +.example-button-row .mat-mdc-button-base { + margin: 8px 8px 8px 0; } -.info-container { - background-color: #e8eaf6; - padding: 16px; - border-radius: 4px; - font-size: 14px; - overflow-x: auto; - margin-top: 16px; - border: 1px solid #c5cae9; -} - -.info-container h3 { - margin-top: 0; - font-size: 16px; - color: #1e88e5; -} - -.info-container p { - margin: 8px 0; - line-height: 1.5; -} - -.info-container strong { - color: #0d47a1; -} - -.info-container pre { - background-color: #f5f5f5; - padding: 16px; - border-radius: 4px; - font-size: 12px; - overflow-x: auto; - white-space: pre; - border: 1px solid #dcdcdc; -} - -td { - cursor: pointer; -} diff --git a/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.html b/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.html index 4493cfc..4612525 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.html +++ b/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.html @@ -1,19 +1,18 @@ - + - Sincronización ogBoot - - {{ getIcon().name }} - + Información en servidor ogBoot -

Plantillas creadsa en servidor ogBoot: {{ alertMessage }}

-

Plantillas creadsa en servidor ogCore (base de datos): {{ length }}

- + +
+
+
+

Administrar plantillas PXE

@@ -40,32 +39,33 @@
{{ column.header }} + @@ -57,12 +56,24 @@ - - {{ image.downloadUrl ? image.downloadUrl.substring(0, 20) + '...' : '' }} - + + {{ image.downloadUrl ? image.downloadUrl.substring(0, 20) + '...' : '' }} + - + + + {{ image.name ? image.name.substring(0, 20) + '...' : '' }} + + + + + + {{ column.cell(image) }} + + + + {{ column.cell(image) }} @@ -72,14 +83,16 @@ Acciones + + - - + +
- - - - + @@ -82,7 +82,3 @@ (page)="onPageChange($event)"> -
-

Detalles de {{ selectedItem.name }}

-
{{ previewContent }}
-
diff --git a/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.ts b/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.ts index 55cea38..a30d193 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.ts +++ b/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.ts @@ -8,6 +8,18 @@ import { ToastrService } from 'ngx-toastr'; import { DatePipe } from '@angular/common'; import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component'; import { DataService } from './data.service'; +import { + ShowOrganizationalUnitComponent +} from "../../groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component"; +import {ShowTemplateContentComponent} from "./show-template-content/show-template-content.component"; +import {ServerInfoDialogComponent} from "../../ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component"; +import { + AddClientsToSubnetComponent +} from "../../ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component"; +import {Subnet} from "../../ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component"; +import {AddClientsToPxeComponent} from "./add-clients-to-pxe/add-clients-to-pxe.component"; +import {Observable} from "rxjs"; +import {ClientsComponent} from "./clients/clients.component"; @Component({ selector: 'app-pxe', @@ -43,7 +55,7 @@ export class PxeComponent { }, { columnDef: 'synchronized', - header: 'Creado en ogBoot', + header: 'Sincronizado', cell: (user: any) => `${user.synchronized}` }, { @@ -65,7 +77,6 @@ export class PxeComponent { ngOnInit(): void { this.search(); - this.loadAlert(); } search(): void { @@ -84,7 +95,7 @@ export class PxeComponent { addPxeTemplate() { const dialogRef = this.dialog.open(CreatePxeTemplateComponent, { - width: '600px' + width: '800px' }); dialogRef.afterClosed().subscribe(() => { @@ -95,7 +106,7 @@ export class PxeComponent { editPxeTemplate(template: any) { const dialogRef = this.dialog.open(CreatePxeTemplateComponent, { data: template, // Pasa los datos del template para edición - width: '600px' + width: '800px' }); dialogRef.afterClosed().subscribe(() => { @@ -103,11 +114,6 @@ export class PxeComponent { }); } - showPxeInfo(template: any) { - this.selectedItem = template; - this.previewContent = template.templateContent; - } - toggleAction(image: any, action: string): void { switch (action) { case 'create': @@ -115,7 +121,19 @@ export class PxeComponent { next: (response) => { this.search(); // @ts-ignore - this.toastService.success(response.message); + this.toastService.success(response.success); + }, + error: (error) => { + this.toastService.error(error.error.error); + } + }); + break; + case 'sync': + this.http.get(`${this.apiUrl}/server/${image.uuid}/get`, {}).subscribe({ + next: (response) => { + this.search(); + // @ts-ignore + this.toastService.success(response.success); }, error: (error) => { this.toastService.error(error.error.error); @@ -125,11 +143,11 @@ export class PxeComponent { case 'delete': this.http.post(`${this.apiUrl}/server/${image.uuid}/delete`, {}).subscribe({ next: () => { - console.log('Plantilla cambiada'); + this.toastService.success('Plantilla eliminada correctamente'); this.search(); }, error: (error) => { - console.error('Error al cambiar la imagen:', error); + this.toastService.error(error.error.error); } }); break; @@ -139,6 +157,38 @@ export class PxeComponent { } } + showTemplate(event: MouseEvent, data: any): void { + event.stopPropagation(); + const dialogRef = this.dialog.open(ShowTemplateContentComponent, { data: { data }, width: '700px'}); + } + + editClients(event: MouseEvent, data: any): void { + event.stopPropagation(); + const dialogRef = this.dialog.open(ClientsComponent, { data: { data }, width: '700px'}); + } + + syncTemplates() { + this.http.post(`${this.apiUrl}/sync`, {}) + .subscribe(response => { + this.toastService.success('Sincronización completada'); + this.search() + }, error => { + console.error('Error al sincronizar', error); + this.toastService.error('Error al sincronizar'); + }); + } + + addClientsToPxe(template: Subnet) { + const dialogRef = this.dialog.open(AddClientsToPxeComponent, { + width: '600px', + data: { subnetUuid: template.uuid, subnetName: template.name } + }); + + dialogRef.afterClosed().subscribe(result => { + this.search(); + }); + } + applyFilter() { this.http.get(`${this.apiUrl}?page=${this.page}&itemsPerPage=${this.itemsPerPage}`).subscribe({ next: (response) => { @@ -151,38 +201,31 @@ export class PxeComponent { }); } + loadAlert(): Observable { + return this.http.get(`${this.apiUrl}/server/get-collection`); + } + + openSubnetInfoDialog() { + this.loadAlert().subscribe( + response => { + this.alertMessage = response.message; + + this.dialog.open(ServerInfoDialogComponent, { + width: '600px', + data: { + message: this.alertMessage + } + }); + }, + error => { + console.error('Error al cargar la información del alert', error); + } + ); + } + onPageChange(event: PageEvent) { this.page = event.pageIndex; this.itemsPerPage = event.pageSize; this.applyFilter(); } - - loadAlert() { - this.http.get(`${this.apiUrl}/server/get-collection`) - .subscribe(response => { - // @ts-ignore - this.alertMessage = response.templates.length - }, error => { - console.error('Error al cargar la información del alert', error); - }); - } - - getIcon(): { name: string, color: string } { - if (Number(this.alertMessage) === this.length) { - return { name: 'check_circle', color: 'green' }; // Icono de check verde - } else { - return { name: 'cancel', color: 'red' }; // Icono de cruz roja - } - } - - syncOgCore(): void { - this.http.post(`${this.apiUrl}/sync`, {}) - .subscribe(response => { - this.toastService.success('Sincronización completada'); - this.search(); - }, error => { - console.error('Error al sincronizar', error); - this.toastService.error('Error al sincronizar'); - }); - } } diff --git a/ogWebconsole/src/app/components/ogboot/pxe/show-template-content/show-template-content.component.css b/ogWebconsole/src/app/components/ogboot/pxe/show-template-content/show-template-content.component.css new file mode 100644 index 0000000..d01dcc9 --- /dev/null +++ b/ogWebconsole/src/app/components/ogboot/pxe/show-template-content/show-template-content.component.css @@ -0,0 +1,33 @@ +.info-container { + background-color: #e8eaf6; + padding: 16px; + border-radius: 4px; + font-size: 14px; + overflow-x: auto; + border: 1px solid #c5cae9; +} + +.info-container h3 { + margin-top: 0; + font-size: 16px; + color: #000000; +} + +.info-container p { + margin: 8px 0; + line-height: 1.5; +} + +.info-container strong { + color: #0d47a1; +} + +.info-container pre { + background-color: #f5f5f5; + padding: 16px; + border-radius: 4px; + font-size: 12px; + overflow-x: auto; + white-space: pre; + border: 1px solid #dcdcdc; +} diff --git a/ogWebconsole/src/app/components/ogboot/pxe/show-template-content/show-template-content.component.html b/ogWebconsole/src/app/components/ogboot/pxe/show-template-content/show-template-content.component.html new file mode 100644 index 0000000..1b1976d --- /dev/null +++ b/ogWebconsole/src/app/components/ogboot/pxe/show-template-content/show-template-content.component.html @@ -0,0 +1,4 @@ +
+

Detalles de {{ data.data.name }}

+
{{ data.data.templateContent }}
+
diff --git a/ogWebconsole/src/app/components/ogboot/pxe/show-template-content/show-template-content.component.spec.ts b/ogWebconsole/src/app/components/ogboot/pxe/show-template-content/show-template-content.component.spec.ts new file mode 100644 index 0000000..71f9be9 --- /dev/null +++ b/ogWebconsole/src/app/components/ogboot/pxe/show-template-content/show-template-content.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ShowTemplateContentComponent } from './show-template-content.component'; + +describe('ShowTemplateContentComponent', () => { + let component: ShowTemplateContentComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ShowTemplateContentComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ShowTemplateContentComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ogWebconsole/src/app/components/ogboot/pxe/show-template-content/show-template-content.component.ts b/ogWebconsole/src/app/components/ogboot/pxe/show-template-content/show-template-content.component.ts new file mode 100644 index 0000000..6d7588a --- /dev/null +++ b/ogWebconsole/src/app/components/ogboot/pxe/show-template-content/show-template-content.component.ts @@ -0,0 +1,19 @@ +import {Component, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA} from "@angular/material/dialog"; +import {HttpClient} from "@angular/common/http"; + +@Component({ + selector: 'app-show-template-content', + templateUrl: './show-template-content.component.html', + styleUrl: './show-template-content.component.css' +}) +export class ShowTemplateContentComponent { + baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; + displayedColumns: string[] = ['property', 'value']; + generalData: any[] = []; + constructor( + @Inject(MAT_DIALOG_DATA) public data: any, + private http: HttpClient + ) { + } +}
{{ column.header }} - + {{ image[column.columnDef] ? 'check_circle' : 'cancel' }} - {{ column.cell(image) }} Acciones + + Acciones + + - + + +