refs #691. Important improvements ogBoot
parent
4871d443a5
commit
54bdcd926a
|
@ -10,9 +10,6 @@
|
|||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<span>
|
||||
Clientes: {{ getClientesNames() }}
|
||||
</span>
|
||||
<div class="mat-dialog-actions">
|
||||
<button mat-button (click)="onCancel()">Cancelar</button>
|
||||
<button mat-button color="primary" (click)="onSave()">{{ isEditMode ? 'Guardar' : 'Añadir' }}</button>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<h2 mat-dialog-title>Imagen ogLive</h2>
|
||||
<mat-dialog-content>
|
||||
<h3>Nombre</h3>
|
||||
<p>{{name}}</p>
|
||||
<h3>URL</h3>
|
||||
<p>{{downloadUrl}}</p>
|
||||
<pre>{{ data | json }}</pre>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button (click)="onNoClick()">Cancel</button>
|
||||
|
|
|
@ -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<InfoImageComponent>,
|
||||
@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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -47,8 +47,7 @@
|
|||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<td mat-cell *matCellDef="let image" [ngClass]="{'clickable': column.columnDef === 'name'}"
|
||||
(click)="column.columnDef === 'name' && showInfo(image)">
|
||||
<td mat-cell *matCellDef="let image" >
|
||||
|
||||
<ng-container *ngIf="column.columnDef === 'isDefault' || column.columnDef === 'installed'">
|
||||
<mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'">
|
||||
|
@ -57,12 +56,24 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef === 'downloadUrl'">
|
||||
<span matTooltip="{{ image.downloadUrl }}">
|
||||
{{ image.downloadUrl ? image.downloadUrl.substring(0, 20) + '...' : '' }}
|
||||
</span>
|
||||
<span matTooltip="{{ image.downloadUrl }}">
|
||||
{{ image.downloadUrl ? image.downloadUrl.substring(0, 20) + '...' : '' }}
|
||||
</span>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef !== 'isDefault' && column.columnDef !== 'installed' && column.columnDef !== 'downloadUrl'">
|
||||
<ng-container *ngIf="column.columnDef === 'name'">
|
||||
<span matTooltip="{{ image.name }}">
|
||||
{{ image.name ? image.name.substring(0, 20) + '...' : '' }}
|
||||
</span>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef === 'status'">
|
||||
<mat-chip>
|
||||
{{ column.cell(image) }}
|
||||
</mat-chip>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef !== 'isDefault' && column.columnDef !== 'installed' && column.columnDef !== 'downloadUrl' && column.columnDef !== 'status' && column.columnDef !== 'name' ">
|
||||
{{ column.cell(image) }}
|
||||
</ng-container>
|
||||
|
||||
|
@ -72,14 +83,16 @@
|
|||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions">Acciones</th>
|
||||
<td mat-cell *matCellDef="let image">
|
||||
<button mat-icon-button color="info" (click)="showOgLive($event, image)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button>
|
||||
<button mat-icon-button color="primary" (click)="editImage(image)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
|
||||
<button mat-icon-button color="warn" (click)="deleteImage(image)" i18n="@@buttonDelete"><mat-icon>delete</mat-icon></button>
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button mat-menu-item (click)="toggleAction(image, 'install')">Instalar</button>
|
||||
<button mat-menu-item (click)="toggleAction(image, 'uninstall')">Desinstalar</button>
|
||||
<button mat-menu-item (click)="toggleAction(image, 'set-default')">Cambiar a imagen por defecto</button>
|
||||
<button mat-menu-item [disabled]="!image.installed" (click)="toggleAction(image, 'uninstall')">Desinstalar</button>
|
||||
<button mat-menu-item [disabled]="!image.installed" (click)="toggleAction(image, 'set-default')">Cambiar a imagen por defecto</button>
|
||||
</mat-menu>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
|
|
@ -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<any>(`${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<any> {
|
||||
return this.http.get<any>(`${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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<h2 mat-dialog-title>Añade clientes a {{data.subnetName}}</h2>
|
||||
|
||||
<mat-dialog-content>
|
||||
<mat-form-field appearance="fill" class="search-select">
|
||||
<input type="text" matInput [formControl]="clientControl" [matAutocomplete]="clientAuto" placeholder="Seleccione un cliente">
|
||||
<mat-autocomplete #clientAuto="matAutocomplete" [displayWith]="displayFnClient" (optionSelected)="onOptionClientSelected($event.option.value)">
|
||||
<mat-option *ngFor="let client of filteredClients | async" [value]="client">
|
||||
{{ client.name }}
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
|
||||
<div *ngIf="selectedClients.length > 0">
|
||||
<h3>Clientes seleccionados:</h3>
|
||||
<ul>
|
||||
<li *ngFor="let client of selectedClients">
|
||||
{{ client.name }}
|
||||
<button mat-icon-button color="warn" (click)="removeClient(client)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions>
|
||||
<button mat-button (click)="close()">Cancelar</button>
|
||||
<button mat-button (click)="save()">Añadir</button>
|
||||
</mat-dialog-actions>
|
|
@ -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<AddClientsToPxeComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [AddClientsToPxeComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AddClientsToPxeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -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<any[]>;
|
||||
clientControl = new FormControl();
|
||||
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
public dialogRef: MatDialogRef<AddClientsToPxeComponent>,
|
||||
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<any>( `${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('');
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<h2 mat-dialog-title>Gestionar clientes </h2>
|
||||
<mat-dialog-content>
|
||||
<mat-list>
|
||||
<ng-container *ngFor="let client of clients">
|
||||
<mat-list-item >
|
||||
<div class="list-item-content">
|
||||
<mat-icon matListItemIcon [ngClass]="{'red-icon': client.pxeSync === false || !client.pxeSync, 'green-icon': client.pxeSync === true}">computer</mat-icon>
|
||||
<div class="text-content">
|
||||
<div matListItemTitle>{{ client.name }}</div>
|
||||
<div matListItemLine>{{ client.mac }}</div>
|
||||
</div>
|
||||
<div class="icon-container">
|
||||
<button mat-icon-button color="primary" (click)="addClientToTemplate(client)" i18n="@@editImage"> <mat-icon>sync</mat-icon></button>
|
||||
<button mat-icon-button color="warn" class="right-icon" (click)="deleteClient(client)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-list-item>
|
||||
</ng-container>
|
||||
</mat-list>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button type="button" (click)="onCancel()">Cancelar</button>
|
||||
</mat-dialog-actions>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ClientsComponent } from './clients.component';
|
||||
|
||||
describe('ClientsComponent', () => {
|
||||
let component: ClientsComponent;
|
||||
let fixture: ComponentFixture<ClientsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ClientsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ClientsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -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<ClientsComponent>,
|
||||
public dialog: MatDialog,
|
||||
private http: HttpClient,
|
||||
private toastService: ToastrService,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.getPxeClients()
|
||||
}
|
||||
|
||||
getPxeClients(): void {
|
||||
this.http.get<any>(`${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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,27 +1,31 @@
|
|||
<form [formGroup]="templateForm" (ngSubmit)="onSave()">
|
||||
<h2 *ngIf="!isEditMode">Crear Plantilla PXE</h2>
|
||||
<h2 *ngIf="isEditMode">Editar Plantilla PXE</h2>
|
||||
<h2 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Añadir' }} plantilla </h2>
|
||||
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Nombre de la Plantilla</mat-label>
|
||||
<input matInput formControlName="name" placeholder="Introduce el nombre de la plantilla">
|
||||
<mat-error *ngIf="templateForm.get('name')?.hasError('required')">
|
||||
El nombre de la plantilla es requerido.
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-dialog-content>
|
||||
<div class="spacing-container">
|
||||
<form [formGroup]="templateForm" (ngSubmit)="onSave()">
|
||||
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Contenido de la Plantilla</mat-label>
|
||||
<textarea matInput formControlName="templateContent" rows="20" placeholder="Introduce el contenido de la plantilla"></textarea>
|
||||
<mat-error *ngIf="templateForm.get('templateContent')?.hasError('required')">
|
||||
El contenido de la plantilla es requerido.
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Nombre de la Plantilla</mat-label>
|
||||
<input matInput formControlName="name" placeholder="Introduce el nombre de la plantilla">
|
||||
<mat-error *ngIf="templateForm.get('name')?.hasError('required')">
|
||||
El nombre de la plantilla es requerido.
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button type="button" (click)="onCancel()">Cancelar</button>
|
||||
<button mat-raised-button color="primary" type="submit" [disabled]="!templateForm.valid">
|
||||
{{ isEditMode ? 'Actualizar' : 'Crear' }}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
</form>
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Contenido de la Plantilla</mat-label>
|
||||
<textarea matInput formControlName="templateContent" rows="20" placeholder="Introduce el contenido de la plantilla"></textarea>
|
||||
<mat-error *ngIf="templateForm.get('templateContent')?.hasError('required')">
|
||||
El contenido de la plantilla es requerido.
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</div>
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button type="button" (click)="onCancel()">Cancelar</button>
|
||||
<button mat-raised-button color="primary" type="submit" (click)="onSave()" [disabled]="!templateForm.valid">
|
||||
{{ isEditMode ? 'Actualizar' : 'Crear' }}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
@ -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<CreatePxeTemplateComponent>,
|
||||
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<any>(`${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<any>(`${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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
<mat-accordion>
|
||||
<mat-accordion class="example-headers-align">
|
||||
<mat-expansion-panel hideToggle>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>Sincronización ogBoot </mat-panel-title>
|
||||
<mat-panel-description>
|
||||
<mat-icon [style.color]="getIcon().color">{{ getIcon().name }}</mat-icon>
|
||||
</mat-panel-description>
|
||||
<mat-panel-title> Información en servidor ogBoot </mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<p *ngIf="alertMessage">Plantillas creadsa en servidor ogBoot: {{ alertMessage }}</p>
|
||||
<p *ngIf="alertMessage">Plantillas creadsa en servidor ogCore (base de datos): {{ length }}</p>
|
||||
<div class="example-button-row">
|
||||
<button mat-flat-button color="primary" (click)="syncOgCore()"> Sincronizar OgCore</button>
|
||||
<button mat-flat-button color="primary" (click)="syncTemplates()"> Sincronizar base de datos</button>
|
||||
</div>
|
||||
<div class="example-button-row">
|
||||
<button mat-flat-button color="accent" (click)="openSubnetInfoDialog()">Ver Información</button>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
|
||||
|
||||
<div class="header-container">
|
||||
<h2 class="title" i18n="@@adminPXETitle">Administrar plantillas PXE</h2>
|
||||
<div class="pxe-button-row">
|
||||
|
@ -40,32 +39,33 @@
|
|||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<td mat-cell *matCellDef="let image" [ngClass]="{'clickable': column.columnDef === 'name'}"
|
||||
(click)="column.columnDef === 'name' && showPxeInfo(image)">
|
||||
<!-- Condición para mostrar íconos para isDefault e installed -->
|
||||
<td mat-cell *matCellDef="let image" >
|
||||
<ng-container *ngIf="column.columnDef === 'synchronized'">
|
||||
<mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'">
|
||||
{{ image[column.columnDef] ? 'check_circle' : 'cancel' }}
|
||||
</mat-icon>
|
||||
</ng-container>
|
||||
|
||||
<!-- Mostrar otros campos normalmente -->
|
||||
<ng-container *ngIf="column.columnDef !== 'synchronized'">
|
||||
{{ column.cell(image) }}
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions">Acciones</th>
|
||||
<td mat-cell *matCellDef="let template">
|
||||
<ng-container matColumnDef="actions" >
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
|
||||
<td mat-cell *matCellDef="let template" style="text-align: center;">
|
||||
<button mat-icon-button color="info" (click)="showTemplate($event, template)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button>
|
||||
<button mat-icon-button color="info" [disabled]="template.clientsLength === 0" (click)="editClients($event, template)"><mat-icon i18n="@@deleteElementTooltip">computer</mat-icon></button>
|
||||
<button mat-icon-button color="primary" (click)="editPxeTemplate(template)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #menu="matMenu">
|
||||
<button mat-menu-item (click)="toggleAction(template, 'create')">Crear</button>
|
||||
<button mat-menu-item (click)="toggleAction(template, 'create')">Crear en servidor ogBoot</button>
|
||||
<button mat-menu-item (click)="addClientsToPxe(template)">Añadir cliente</button>
|
||||
<button mat-menu-item (click)="toggleAction(template, 'sync')">Sincronizar base de datos</button>
|
||||
<button mat-menu-item (click)="toggleAction(template, 'delete')">Eliminar</button>
|
||||
</mat-menu>
|
||||
</td>
|
||||
|
@ -82,7 +82,3 @@
|
|||
(page)="onPageChange($event)">
|
||||
</mat-paginator>
|
||||
</div>
|
||||
<div class="info-container" *ngIf="selectedItem">
|
||||
<h3>Detalles de {{ selectedItem.name }}</h3>
|
||||
<pre>{{ previewContent }}</pre>
|
||||
</div>
|
||||
|
|
|
@ -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<any>(`${this.apiUrl}?page=${this.page}&itemsPerPage=${this.itemsPerPage}`).subscribe({
|
||||
next: (response) => {
|
||||
|
@ -151,38 +201,31 @@ export class PxeComponent {
|
|||
});
|
||||
}
|
||||
|
||||
loadAlert(): Observable<any> {
|
||||
return this.http.get<any>(`${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');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<div class="info-container">
|
||||
<h3>Detalles de {{ data.data.name }}</h3>
|
||||
<pre class="code-block">{{ data.data.templateContent }}</pre>
|
||||
</div>
|
|
@ -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<ShowTemplateContentComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ShowTemplateContentComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ShowTemplateContentComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -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
|
||||
) {
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue