Delete pxe and ogshcp edit modals
parent
35c326e65d
commit
a3195f81e1
|
@ -71,11 +71,9 @@ import { SaveFiltersDialogComponent } from './components/groups/save-filters-dia
|
||||||
import { AcctionsModalComponent } from './components/groups/acctions-modal/acctions-modal.component';
|
import { AcctionsModalComponent } from './components/groups/acctions-modal/acctions-modal.component';
|
||||||
import { ImagesComponent } from './components/ogboot/images/images.component';
|
import { ImagesComponent } from './components/ogboot/images/images.component';
|
||||||
import { CreateImageComponent } from './components/ogboot/images/create-image/create-image/create-image.component';
|
import { CreateImageComponent } from './components/ogboot/images/create-image/create-image/create-image.component';
|
||||||
import { EditImageComponent } from './components/ogboot/images/edit-image/edit-image/edit-image.component';
|
|
||||||
import { InfoImageComponent } from './components/ogboot/images/info-image/info-image/info-image.component';
|
import { InfoImageComponent } from './components/ogboot/images/info-image/info-image/info-image.component';
|
||||||
import { PxeComponent } from './components/ogboot/pxe/pxe.component';
|
import { PxeComponent } from './components/ogboot/pxe/pxe.component';
|
||||||
import { CreatePxeTemplateComponent } from './components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component';
|
import { CreatePxeTemplateComponent } from './components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component';
|
||||||
import { EditPxeTemplateComponent } from './components/ogboot/pxe/edit-pxe-template/edit-pxe-template.component';
|
|
||||||
import { PxeBootFilesComponent } from './components/ogboot/pxe-boot-files/pxe-boot-files.component';
|
import { PxeBootFilesComponent } from './components/ogboot/pxe-boot-files/pxe-boot-files.component';
|
||||||
import {MatExpansionPanel, MatExpansionPanelDescription, MatExpansionPanelTitle} from "@angular/material/expansion";
|
import {MatExpansionPanel, MatExpansionPanelDescription, MatExpansionPanelTitle} from "@angular/material/expansion";
|
||||||
import { OgbootStatusComponent } from './components/ogboot/ogboot-status/ogboot-status.component';
|
import { OgbootStatusComponent } from './components/ogboot/ogboot-status/ogboot-status.component';
|
||||||
|
@ -117,11 +115,9 @@ import { CreateSubnetComponent } from './components/ogdhcp/og-dhcp-subnets/creat
|
||||||
AcctionsModalComponent,
|
AcctionsModalComponent,
|
||||||
ImagesComponent,
|
ImagesComponent,
|
||||||
CreateImageComponent,
|
CreateImageComponent,
|
||||||
EditImageComponent,
|
|
||||||
InfoImageComponent,
|
InfoImageComponent,
|
||||||
PxeComponent,
|
PxeComponent,
|
||||||
CreatePxeTemplateComponent,
|
CreatePxeTemplateComponent,
|
||||||
EditPxeTemplateComponent,
|
|
||||||
PxeBootFilesComponent,
|
PxeBootFilesComponent,
|
||||||
OgbootStatusComponent,
|
OgbootStatusComponent,
|
||||||
CreatePxeBootFileComponent,
|
CreatePxeBootFileComponent,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<h2 mat-dialog-title>Añadir imagen ogLive</h2>
|
<h2 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Añadir' }} imagen ogLive</h2>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<mat-form-field appearance="fill" class="full-width">
|
<mat-form-field appearance="fill" class="full-width">
|
||||||
<mat-label>Nombre</mat-label>
|
<mat-label>Nombre</mat-label>
|
||||||
|
@ -14,6 +14,6 @@
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
<mat-dialog-actions align="end">
|
<mat-dialog-actions align="end">
|
||||||
<button mat-button (click)="onNoClick()">Cancel</button>
|
<button mat-button (click)="onNoClick()">Cancelar</button>
|
||||||
<button mat-button (click)="addOgLive()" cdkFocusInitial>Añadir</button>
|
<button mat-button (click)="submitForm()" cdkFocusInitial>{{ isEditMode ? 'Guardar' : 'Añadir' }}</button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
|
|
|
@ -12,6 +12,8 @@ export class CreateImageComponent implements OnInit {
|
||||||
name: string = '';
|
name: string = '';
|
||||||
downloads: any[] = [];
|
downloads: any[] = [];
|
||||||
selectedDownload: any;
|
selectedDownload: any;
|
||||||
|
isEditMode: boolean = false;
|
||||||
|
imageId: string | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
|
@ -22,6 +24,12 @@ export class CreateImageComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.fetchDownloads();
|
this.fetchDownloads();
|
||||||
|
if (this.data) {
|
||||||
|
this.isEditMode = true;
|
||||||
|
this.name = this.data.name;
|
||||||
|
this.selectedDownload = this.data.downloadUrl;
|
||||||
|
this.imageId = this.data.uuid; // Assuming UUID is used for edit
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchDownloads(): void {
|
fetchDownloads(): void {
|
||||||
|
@ -35,25 +43,36 @@ export class CreateImageComponent implements OnInit {
|
||||||
this.toastService.error('Error fetching iso files');
|
this.toastService.error('Error fetching iso files');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onNoClick(): void {
|
onNoClick(): void {
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
addOgLive(): void {
|
submitForm(): void {
|
||||||
const payload = {
|
const payload = {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
downloadUrl: this.selectedDownload.URL
|
downloadUrl: this.selectedDownload.URL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this.isEditMode && this.imageId) {
|
||||||
|
this.http.patch(`http://127.0.0.1:8080/og-lives/${this.imageId}`, payload)
|
||||||
|
.subscribe({
|
||||||
|
next: (response) => {
|
||||||
|
this.toastService.success('Image updated successfully');
|
||||||
|
this.dialogRef.close(true);
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
this.toastService.error('Error updating image');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
this.http.post('http://127.0.0.1:8080/og-lives', payload)
|
this.http.post('http://127.0.0.1:8080/og-lives', payload)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
console.log('Success:', response);
|
|
||||||
this.toastService.success('Image created successfully');
|
this.toastService.success('Image created successfully');
|
||||||
this.dialogRef.close();
|
this.dialogRef.close(true);
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
|
@ -62,3 +81,4 @@ export class CreateImageComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
.form-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 16px; /* Espacio entre los campos */
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field {
|
|
||||||
width: 100%; /* Para que cada campo ocupe todo el ancho disponible */
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 8px; /* Espacio entre los botones */
|
|
||||||
margin-top: 16px; /* Separación superior para los botones */
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<h1 mat-dialog-title>Editar Imagen</h1>
|
|
||||||
<div mat-dialog-content class="form-container">
|
|
||||||
<mat-form-field appearance="fill" class="form-field">
|
|
||||||
<mat-label>Nombre</mat-label>
|
|
||||||
<input matInput [(ngModel)]="name" />
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field appearance="fill" class="form-field">
|
|
||||||
<mat-label>URL de descarga</mat-label>
|
|
||||||
<input matInput [(ngModel)]="downloadUrl" />
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div mat-dialog-actions class="actions-container">
|
|
||||||
<button mat-button (click)="onNoClick()">Cancelar</button>
|
|
||||||
<button mat-button color="primary" (click)="editOgLive()">Guardar</button>
|
|
||||||
</div>
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { EditImageComponent } from './edit-image.component';
|
|
||||||
|
|
||||||
describe('EditImageComponent', () => {
|
|
||||||
let component: EditImageComponent;
|
|
||||||
let fixture: ComponentFixture<EditImageComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [EditImageComponent]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(EditImageComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,52 +0,0 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
|
||||||
import { Component, Inject } from '@angular/core';
|
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|
||||||
import { ToastrService } from 'ngx-toastr';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-edit-image',
|
|
||||||
templateUrl: './edit-image.component.html',
|
|
||||||
styleUrls: ['./edit-image.component.css']
|
|
||||||
})
|
|
||||||
export class EditImageComponent {
|
|
||||||
name: string = '';
|
|
||||||
downloadUrl: string = '';
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private toastService: ToastrService,
|
|
||||||
private http: HttpClient,
|
|
||||||
public dialogRef: MatDialogRef<EditImageComponent>,
|
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
|
||||||
) {
|
|
||||||
// Rellenar los campos con los datos recibidos
|
|
||||||
if (data) {
|
|
||||||
this.name = data.name;
|
|
||||||
this.downloadUrl = data.downloadUrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onNoClick(): void {
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
editOgLive(): void {
|
|
||||||
const payload = {
|
|
||||||
name: this.name,
|
|
||||||
downloadUrl: this.downloadUrl
|
|
||||||
};
|
|
||||||
|
|
||||||
// Realizar PATCH para editar la imagen
|
|
||||||
this.http.patch(`http://127.0.0.1:8080/og-lives/${this.data.uuid}`, payload)
|
|
||||||
.subscribe({
|
|
||||||
next: (response) => {
|
|
||||||
console.log('Success:', response);
|
|
||||||
this.toastService.success('Image updated successfully');
|
|
||||||
this.dialogRef.close();
|
|
||||||
},
|
|
||||||
error: (error) => {
|
|
||||||
console.error('Error:', error);
|
|
||||||
this.toastService.error('Error updating image');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,7 +2,6 @@ import {Component, OnInit, signal} from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { CreateImageComponent } from './create-image/create-image/create-image.component';
|
import { CreateImageComponent } from './create-image/create-image/create-image.component';
|
||||||
import { EditImageComponent } from './edit-image/edit-image/edit-image.component';
|
|
||||||
import { InfoImageComponent } from './info-image/info-image/info-image.component';
|
import { InfoImageComponent } from './info-image/info-image/info-image.component';
|
||||||
import { MatTableDataSource } from "@angular/material/table";
|
import { MatTableDataSource } from "@angular/material/table";
|
||||||
import {PageEvent} from "@angular/material/paginator";
|
import {PageEvent} from "@angular/material/paginator";
|
||||||
|
@ -158,7 +157,7 @@ export class ImagesComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
editImage(image: any): void {
|
editImage(image: any): void {
|
||||||
const dialogRef = this.dialog.open(EditImageComponent, {
|
const dialogRef = this.dialog.open(CreateImageComponent, {
|
||||||
width: '700px',
|
width: '700px',
|
||||||
data: image
|
data: image
|
||||||
});
|
});
|
||||||
|
@ -170,6 +169,7 @@ export class ImagesComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
applyFilter() {
|
applyFilter() {
|
||||||
this.http.get<any>(`${this.apiUrl}?page=${this.page}&itemsPerPage=${this.itemsPerPage}`).subscribe({
|
this.http.get<any>(`${this.apiUrl}?page=${this.page}&itemsPerPage=${this.itemsPerPage}`).subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="create-PxeBootFile-container">
|
<div class="create-PxeBootFile-container">
|
||||||
<h1 mat-dialog-title>Añadir Cliente</h1>
|
<h1 mat-dialog-title>{{ isEditMode ? 'Editar Cliente' : 'Añadir Cliente' }}</h1>
|
||||||
<div class="mat-dialog-content">
|
<div class="mat-dialog-content">
|
||||||
<mat-form-field appearance="fill">
|
<mat-form-field appearance="fill">
|
||||||
<mat-label>Seleccione una plantilla PXE</mat-label>
|
<mat-label>Seleccione una plantilla PXE</mat-label>
|
||||||
|
@ -15,7 +15,6 @@
|
||||||
</span>
|
</span>
|
||||||
<div class="mat-dialog-actions">
|
<div class="mat-dialog-actions">
|
||||||
<button mat-button (click)="onCancel()">Cancelar</button>
|
<button mat-button (click)="onCancel()">Cancelar</button>
|
||||||
<button mat-button color="primary" (click)="onAdd()">Añadir</button>
|
<button mat-button color="primary" (click)="onSave()">{{ isEditMode ? 'Guardar' : 'Añadir' }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Component, Inject } from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
|
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
@ -9,27 +8,34 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
templateUrl: './create-pxe-boot-file.component.html',
|
templateUrl: './create-pxe-boot-file.component.html',
|
||||||
styleUrls: ['./create-pxe-boot-file.component.css']
|
styleUrls: ['./create-pxe-boot-file.component.css']
|
||||||
})
|
})
|
||||||
export class CreatePxeBootFileComponent {
|
export class CreatePxeBootFileComponent implements OnInit {
|
||||||
pxeTemplates: any[] = [];
|
pxeTemplates: any[] = [];
|
||||||
selectedPxeTemplate: string | undefined;
|
selectedPxeTemplate: string | undefined;
|
||||||
clientes: string[] = [];
|
clientes: string[] = [];
|
||||||
selectedElements: any;
|
selectedElements: any;
|
||||||
|
isEditMode: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private dialogRef: MatDialogRef<CreatePxeBootFileComponent>,
|
private dialogRef: MatDialogRef<CreatePxeBootFileComponent>,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: string[]
|
@Inject(MAT_DIALOG_DATA) public data: { clients: any[], bootFile?: any }
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.selectedElements = this.data;
|
this.selectedElements = this.data.clients;
|
||||||
this.clientes = this.selectedElements.map((client: { uuid: any; }) => `/clients/${client.uuid}`);
|
this.clientes = this.selectedElements.map((client: { uuid: any }) => `/clients/${client.uuid}`);
|
||||||
this.loadPxeTemplates();
|
this.loadPxeTemplates();
|
||||||
|
|
||||||
|
// Configura el modo de edición si se proporciona bootFile
|
||||||
|
if (this.data.bootFile) {
|
||||||
|
this.isEditMode = true;
|
||||||
|
this.selectedPxeTemplate = this.data.bootFile.template.uuid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getClientesNames(): string {
|
getClientesNames(): string {
|
||||||
return this.selectedElements.map((client: { name: any; }) => client.name).join(', ');
|
return this.selectedElements.map((client: { name: any }) => client.name).join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPxeTemplates(): void {
|
loadPxeTemplates(): void {
|
||||||
|
@ -45,25 +51,39 @@ export class CreatePxeBootFileComponent {
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
onAdd(): void {
|
onSave(): void {
|
||||||
if (this.selectedPxeTemplate) {
|
if (this.selectedPxeTemplate) {
|
||||||
const payload = {
|
const payload = {
|
||||||
template: `/pxe-templates/${this.selectedPxeTemplate}`,
|
template: `/pxe-templates/${this.selectedPxeTemplate}`,
|
||||||
clients: this.clientes
|
clients: this.clientes
|
||||||
};
|
};
|
||||||
console.log('Payload FINAAAL:', payload);
|
|
||||||
|
if (this.isEditMode && this.data.bootFile) {
|
||||||
|
// Edit mode: Actualizar boot file existente
|
||||||
|
this.http.put(`http://127.0.0.1:8080/pxe-boot-files/${this.data.bootFile.uuid}`, payload)
|
||||||
|
.subscribe({
|
||||||
|
next: response => {
|
||||||
|
this.toastService.success('PXE actualizado con éxito');
|
||||||
|
this.dialogRef.close(true);
|
||||||
|
},
|
||||||
|
error: error => {
|
||||||
|
this.toastService.error('Error al actualizar el PXE', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Create mode: Crear nuevo boot file
|
||||||
this.http.post('http://127.0.0.1:8080/pxe-boot-files', payload)
|
this.http.post('http://127.0.0.1:8080/pxe-boot-files', payload)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: response => {
|
next: response => {
|
||||||
this.toastService.success('PXE asignado con éxito');
|
this.toastService.success('PXE asignado con éxito');
|
||||||
this.dialogRef.close();
|
this.dialogRef.close(true);
|
||||||
},
|
},
|
||||||
error: error => {
|
error: error => {
|
||||||
this.toastService.error('Error enviando el payload', error);
|
this.toastService.error('Error enviando el payload', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error('No se ha seleccionado ninguna plantilla PXE');
|
|
||||||
this.toastService.error('No se ha seleccionado ninguna plantilla PXE');
|
this.toastService.error('No se ha seleccionado ninguna plantilla PXE');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {MatTableDataSource} from "@angular/material/table";
|
||||||
import {MatDialog} from "@angular/material/dialog";
|
import {MatDialog} from "@angular/material/dialog";
|
||||||
import {HttpClient} from "@angular/common/http";
|
import {HttpClient} from "@angular/common/http";
|
||||||
import { CreatePxeTemplateComponent } from '../pxe/create-pxeTemplate/create-pxe-template.component';
|
import { CreatePxeTemplateComponent } from '../pxe/create-pxeTemplate/create-pxe-template.component';
|
||||||
import { EditPxeTemplateComponent } from '../pxe/edit-pxe-template/edit-pxe-template.component';
|
|
||||||
import {PageEvent} from "@angular/material/paginator";
|
import {PageEvent} from "@angular/material/paginator";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import {ToastrService} from "ngx-toastr";
|
||||||
import {DatePipe} from "@angular/common";
|
import {DatePipe} from "@angular/common";
|
||||||
|
@ -123,7 +122,7 @@ export class PxeBootFilesComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
editPxeTemplate(template: any) {
|
editPxeTemplate(template: any) {
|
||||||
const dialogRef = this.dialog.open(EditPxeTemplateComponent, {
|
const dialogRef = this.dialog.open(CreatePxeTemplateComponent, {
|
||||||
data: template
|
data: template
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -132,6 +131,21 @@ export class PxeBootFilesComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* editPxeBootFile(bootFile: any) {
|
||||||
|
const dialogRef = this.dialog.open(CreatePxeBootFileComponent, {
|
||||||
|
data: {
|
||||||
|
clients: bootFile.clients,
|
||||||
|
bootFile: bootFile
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
this.loadPxeBootFiles(); // Refrescar la lista después de la edición
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} */
|
||||||
|
|
||||||
applyFilter() {
|
applyFilter() {
|
||||||
this.http.get<any>(`${this.apiUrl}?page=${this.page}&itemsPerPage=${this.itemsPerPage}`).subscribe({
|
this.http.get<any>(`${this.apiUrl}?page=${this.page}&itemsPerPage=${this.itemsPerPage}`).subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<form [formGroup]="templateForm" (ngSubmit)="onCreate()">
|
<form [formGroup]="templateForm" (ngSubmit)="onSave()">
|
||||||
<h2>Crear Plantilla PXE</h2>
|
<h2 *ngIf="!isEditMode">Crear Plantilla PXE</h2>
|
||||||
|
<h2 *ngIf="isEditMode">Editar Plantilla PXE</h2>
|
||||||
|
|
||||||
<mat-form-field appearance="fill">
|
<mat-form-field appearance="fill">
|
||||||
<mat-label>Nombre de la Plantilla</mat-label>
|
<mat-label>Nombre de la Plantilla</mat-label>
|
||||||
|
@ -19,6 +20,8 @@
|
||||||
|
|
||||||
<mat-dialog-actions align="end">
|
<mat-dialog-actions align="end">
|
||||||
<button mat-button type="button" (click)="onCancel()">Cancelar</button>
|
<button mat-button type="button" (click)="onCancel()">Cancelar</button>
|
||||||
<button mat-raised-button color="primary" type="submit" [disabled]="!templateForm.valid">Crear</button>
|
<button mat-raised-button color="primary" type="submit" [disabled]="!templateForm.valid">
|
||||||
|
{{ isEditMode ? 'Actualizar' : 'Crear' }}
|
||||||
|
</button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,44 +1,81 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Component } from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
import { MatDialogRef } from '@angular/material/dialog';
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-pxe-template',
|
selector: 'app-create-pxe-template',
|
||||||
templateUrl: './create-pxe-template.component.html',
|
templateUrl: './create-pxe-template.component.html',
|
||||||
styleUrls: ['./create-pxe-template.component.css']
|
styleUrls: ['./create-pxe-template.component.css']
|
||||||
})
|
})
|
||||||
export class CreatePxeTemplateComponent {
|
export class CreatePxeTemplateComponent implements OnInit {
|
||||||
templateForm!: FormGroup;
|
templateForm!: FormGroup;
|
||||||
previewContent: string = '';
|
previewContent: string = '';
|
||||||
|
isEditMode: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialogRef: MatDialogRef<CreatePxeTemplateComponent>,
|
public dialogRef: MatDialogRef<CreatePxeTemplateComponent>,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private fb: FormBuilder
|
private fb: FormBuilder,
|
||||||
|
private toastService: ToastrService,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.isEditMode = !!this.data; // Verifica si hay datos inyectados (modo edición)
|
||||||
|
|
||||||
this.templateForm = this.fb.group({
|
this.templateForm = this.fb.group({
|
||||||
name: ['', Validators.required],
|
name: [this.data?.name || '', Validators.required],
|
||||||
templateContent: ['', Validators.required]
|
templateContent: [this.data?.templateContent || '', Validators.required]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onCreate(): void {
|
onSave(): void {
|
||||||
|
if (this.isEditMode) {
|
||||||
|
this.updatePxeTemplate();
|
||||||
|
} else {
|
||||||
|
this.createPxeTemplate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createPxeTemplate(): void {
|
||||||
const formValues = this.templateForm.value;
|
const formValues = this.templateForm.value;
|
||||||
const payload = {
|
const payload = {
|
||||||
name: formValues.name,
|
name: formValues.name,
|
||||||
templateContent: formValues.templateContent
|
templateContent: formValues.templateContent
|
||||||
};
|
};
|
||||||
console.log(payload);
|
|
||||||
this.http.post<any>('http://127.0.0.1:8080/pxe-templates', payload).subscribe({
|
this.http.post<any>('http://127.0.0.1:8080/pxe-templates', payload).subscribe({
|
||||||
next: data => {
|
next: data => {
|
||||||
console.log('Plantilla PXE creada:', data);
|
console.log('Plantilla PXE creada:', data);
|
||||||
|
this.toastService.success('Plantilla PXE creada exitosamente');
|
||||||
this.dialogRef.close(true);
|
this.dialogRef.close(true);
|
||||||
},
|
},
|
||||||
error: error => {
|
error: error => {
|
||||||
console.error('Error al crear la plantilla PXE:', error);
|
console.error('Error al crear la plantilla PXE:', error);
|
||||||
|
this.toastService.error('Error al crear la plantilla PXE');
|
||||||
|
this.dialogRef.close(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePxeTemplate(): void {
|
||||||
|
const formValues = this.templateForm.value;
|
||||||
|
const payload = {
|
||||||
|
name: formValues.name,
|
||||||
|
templateContent: formValues.templateContent
|
||||||
|
};
|
||||||
|
|
||||||
|
this.http.patch<any>(`http://127.0.0.1:8080/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);
|
this.dialogRef.close(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
form {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 20px auto;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-form-field {
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background-color: #eceff1;
|
|
||||||
padding: 15px;
|
|
||||||
border-radius: 4px;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-wrap: break-word;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-dialog-actions {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button[type="submit"] {
|
|
||||||
background-color: #3f51b5;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
button[type="submit"]:disabled {
|
|
||||||
background-color: #c5cae9;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
color: #000000;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-top: 30px;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
color: #000000;
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
<form [formGroup]="templateForm" (ngSubmit)="onCreate()">
|
|
||||||
<h2>Editar Plantilla PXE</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-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-dialog-actions align="end">
|
|
||||||
<button mat-button type="button" (click)="onCancel()">Cancelar</button>
|
|
||||||
<button mat-raised-button color="primary" type="submit" [disabled]="!templateForm.valid">Crear</button>
|
|
||||||
</mat-dialog-actions>
|
|
||||||
</form>
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { EditPxeTemplateComponent } from './edit-pxe-template.component';
|
|
||||||
|
|
||||||
describe('EditPxeTemplateComponent', () => {
|
|
||||||
let component: EditPxeTemplateComponent;
|
|
||||||
let fixture: ComponentFixture<EditPxeTemplateComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [EditPxeTemplateComponent]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(EditPxeTemplateComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,52 +0,0 @@
|
||||||
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';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-edit-pxe-template',
|
|
||||||
templateUrl: './edit-pxe-template.component.html',
|
|
||||||
styleUrls: ['./edit-pxe-template.component.css']
|
|
||||||
})
|
|
||||||
export class EditPxeTemplateComponent implements OnInit {
|
|
||||||
templateForm!: FormGroup;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private fb: FormBuilder,
|
|
||||||
private http: HttpClient,
|
|
||||||
public dialogRef: MatDialogRef<EditPxeTemplateComponent>,
|
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
console.log(this.data);
|
|
||||||
this.templateForm = this.fb.group({
|
|
||||||
name: [this.data.name || '', Validators.required],
|
|
||||||
templateContent: [this.data.templateContent || '', Validators.required]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onCreate(): void {
|
|
||||||
if (this.templateForm.valid) {
|
|
||||||
const updatedTemplate = {
|
|
||||||
name: this.templateForm.value.name,
|
|
||||||
templateContent: this.templateForm.value.templateContent
|
|
||||||
};
|
|
||||||
|
|
||||||
this.http.patch(`http://127.0.0.1:8080/pxe-templates/${this.data.uuid}`, updatedTemplate)
|
|
||||||
.subscribe({
|
|
||||||
next: () => {
|
|
||||||
console.log('Plantilla actualizada correctamente');
|
|
||||||
this.dialogRef.close(true);
|
|
||||||
},
|
|
||||||
error: (error) => {
|
|
||||||
console.error('Error al actualizar la plantilla:', error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onCancel(): void {
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +1,18 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { CreatePxeTemplateComponent } from './create-pxeTemplate/create-pxe-template.component';
|
import { CreatePxeTemplateComponent } from './create-pxeTemplate/create-pxe-template.component'; // Asegúrate de que el path sea correcto
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { EditPxeTemplateComponent } from './edit-pxe-template/edit-pxe-template.component';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import {MatTableDataSource} from "@angular/material/table";
|
import { PageEvent } from '@angular/material/paginator';
|
||||||
import {PageEvent} from "@angular/material/paginator";
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { DatePipe } from '@angular/common';
|
||||||
import {DatePipe} from "@angular/common";
|
|
||||||
import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component';
|
import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component';
|
||||||
import {DataService} from "./data.service";
|
import { DataService } from './data.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pxe',
|
selector: 'app-pxe',
|
||||||
templateUrl: './pxe.component.html',
|
templateUrl: './pxe.component.html',
|
||||||
styleUrl: './pxe.component.css'
|
styleUrls: ['./pxe.component.css']
|
||||||
})
|
})
|
||||||
export class PxeComponent {
|
export class PxeComponent {
|
||||||
pxeTemplates: any[] = [];
|
pxeTemplates: any[] = [];
|
||||||
|
@ -25,7 +24,7 @@ export class PxeComponent {
|
||||||
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
|
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
|
||||||
selectedElements: string[] = [];
|
selectedElements: string[] = [];
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
searchTerm: string = ''
|
searchTerm: string = '';
|
||||||
alertMessage: string | null = null;
|
alertMessage: string | null = null;
|
||||||
datePipe: DatePipe = new DatePipe('es-ES');
|
datePipe: DatePipe = new DatePipe('es-ES');
|
||||||
selectedItem: any = null;
|
selectedItem: any = null;
|
||||||
|
@ -64,7 +63,7 @@ export class PxeComponent {
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.search()
|
this.search();
|
||||||
this.loadAlert();
|
this.loadAlert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,9 +91,19 @@ export class PxeComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editPxeTemplate(template: any) {
|
||||||
|
const dialogRef = this.dialog.open(CreatePxeTemplateComponent, {
|
||||||
|
data: template, // Pasa los datos del template para edición
|
||||||
|
width: '600px'
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe(() => {
|
||||||
|
this.search();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
showPxeInfo(template: any) {
|
showPxeInfo(template: any) {
|
||||||
this.selectedItem = template;
|
this.selectedItem = template;
|
||||||
|
|
||||||
this.previewContent = template.templateContent;
|
this.previewContent = template.templateContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,17 +138,6 @@ export class PxeComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
editPxeTemplate(template: any) {
|
|
||||||
const dialogRef = this.dialog.open(EditPxeTemplateComponent, {
|
|
||||||
data: template,
|
|
||||||
width: '600px'
|
|
||||||
});
|
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(() => {
|
|
||||||
this.search();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
applyFilter() {
|
applyFilter() {
|
||||||
this.http.get<any>(`${this.apiUrl}?page=${this.page}&itemsPerPage=${this.itemsPerPage}`).subscribe({
|
this.http.get<any>(`${this.apiUrl}?page=${this.page}&itemsPerPage=${this.itemsPerPage}`).subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
|
@ -180,7 +178,7 @@ export class PxeComponent {
|
||||||
this.http.post(`${this.apiUrl}/sync`, {})
|
this.http.post(`${this.apiUrl}/sync`, {})
|
||||||
.subscribe(response => {
|
.subscribe(response => {
|
||||||
this.toastService.success('Sincronización completada');
|
this.toastService.success('Sincronización completada');
|
||||||
this.search()
|
this.search();
|
||||||
}, error => {
|
}, error => {
|
||||||
console.error('Error al sincronizar', error);
|
console.error('Error al sincronizar', error);
|
||||||
this.toastService.error('Error al sincronizar');
|
this.toastService.error('Error al sincronizar');
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<h2 mat-dialog-title>Añadir configuración de red</h2>
|
<h2 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Añadir' }} configuración de red</h2>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<mat-form-field appearance="fill" class="full-width">
|
<mat-form-field appearance="fill" class="full-width">
|
||||||
<mat-label>Nombre</mat-label>
|
<mat-label>Nombre</mat-label>
|
||||||
|
@ -23,5 +23,5 @@
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
<mat-dialog-actions align="end">
|
<mat-dialog-actions align="end">
|
||||||
<button mat-button (click)="onNoClick()">Cancelar</button>
|
<button mat-button (click)="onNoClick()">Cancelar</button>
|
||||||
<button mat-button (click)="addNetworkConfig()" cdkFocusInitial>Añadir</button>
|
<button mat-button (click)="submitForm()" cdkFocusInitial>{{ isEditMode ? 'Guardar' : 'Añadir' }}</button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// create-subnet.component.ts
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Component, Inject, OnInit } from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
@ -14,6 +15,7 @@ export class CreateSubnetComponent implements OnInit {
|
||||||
ipAddress: string = '';
|
ipAddress: string = '';
|
||||||
nextServer: string = '';
|
nextServer: string = '';
|
||||||
bootFileName: string = '';
|
bootFileName: string = '';
|
||||||
|
isEditMode: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
|
@ -23,14 +25,21 @@ export class CreateSubnetComponent implements OnInit {
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
if (this.data && this.data.subnet) {
|
||||||
|
this.isEditMode = true;
|
||||||
|
this.name = this.data.subnet.name;
|
||||||
|
this.netmask = this.data.subnet.netmask;
|
||||||
|
this.ipAddress = this.data.subnet.ipAddress;
|
||||||
|
this.nextServer = this.data.subnet.nextServer;
|
||||||
|
this.bootFileName = this.data.subnet.bootFileName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onNoClick(): void {
|
onNoClick(): void {
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
addNetworkConfig(): void {
|
submitForm(): void {
|
||||||
const payload = {
|
const payload = {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
netmask: this.netmask,
|
netmask: this.netmask,
|
||||||
|
@ -39,6 +48,20 @@ export class CreateSubnetComponent implements OnInit {
|
||||||
bootFileName: this.bootFileName
|
bootFileName: this.bootFileName
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this.isEditMode) {
|
||||||
|
this.http.patch(`http://127.0.0.1:8080/subnets/${this.data.subnet.uuid}`, 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 al actualizar la configuración de red');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
this.http.post('http://127.0.0.1:8080/subnets', payload)
|
this.http.post('http://127.0.0.1:8080/subnets', payload)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
|
@ -53,3 +76,4 @@ export class CreateSubnetComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue