Some improvements. Added filter search and refactor
parent
2d6785198f
commit
cf3785d863
|
@ -10,7 +10,7 @@ import { UsersComponent } from './components/admin/users/users/users.component';
|
|||
import { RolesComponent } from './components/admin/roles/roles/roles.component';
|
||||
import { GroupsComponent } from './components/groups/groups.component';
|
||||
import { ImagesComponent } from './components/ogboot/images/images.component';
|
||||
import { PxeComponent } from './components/ogboot/pxe/pxe/pxe.component';
|
||||
import { PxeComponent } from './components/ogboot/pxe/pxe.component';
|
||||
import { PxeBootFilesComponent } from './components/ogboot/pxe-boot-files/pxe-boot-files.component';
|
||||
import {OgbootStatusComponent} from "./components/ogboot/ogboot-status/ogboot-status.component";
|
||||
import { OgdhcpComponent } from './components/ogdhcp/ogdhcp.component';
|
||||
|
|
|
@ -73,9 +73,9 @@ import { ImagesComponent } from './components/ogboot/images/images.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 { PxeComponent } from './components/ogboot/pxe/pxe/pxe.component';
|
||||
import { CreatePxeTemplateComponent } from './components/ogboot/pxe/pxe/create-pxeTemplate/create-pxe-template/create-pxe-template.component';
|
||||
import { EditPxeTemplateComponent } from './components/ogboot/pxe/pxe/edit-pxe-template/edit-pxe-template.component';
|
||||
import { PxeComponent } from './components/ogboot/pxe/pxe.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 {MatExpansionPanel, MatExpansionPanelDescription, MatExpansionPanelTitle} from "@angular/material/expansion";
|
||||
import { OgbootStatusComponent } from './components/ogboot/ogboot-status/ogboot-status.component';
|
||||
|
|
|
@ -91,7 +91,6 @@ export class GroupsComponent implements OnInit {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
onSelectUnidad(unidad: UnidadOrganizativa): void {
|
||||
this.selectedUnidad = unidad;
|
||||
this.selectedDetail = unidad;
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class DataService {
|
||||
private apiUrl = 'http://127.0.0.1:8080/og-lives?page=1&itemsPerPage=1000';
|
||||
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
getImages(search: string = ''): Observable<any[]> {
|
||||
let url = `${this.apiUrl}`;
|
||||
if (search) {
|
||||
url += `&name=${encodeURIComponent(search)}`;
|
||||
}
|
||||
|
||||
return this.http.get<any>(url).pipe(
|
||||
map(response => {
|
||||
if (response['hydra:member'] && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member'];
|
||||
} else {
|
||||
throw new Error('Unexpected response format');
|
||||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching images', error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,3 @@
|
|||
.header-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 100px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
@ -16,11 +8,6 @@
|
|||
margin-top: 16px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-left: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
@ -50,33 +37,26 @@ button {
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
.mat-icon-button {
|
||||
margin-left: 16px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.mat-menu {
|
||||
min-width: 160px;
|
||||
}
|
||||
|
||||
.image-name{
|
||||
.image-name{
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.search-container mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header-container {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-container h1 {
|
||||
margin: 0;
|
||||
height: 100px;
|
||||
padding: 10px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.mat-elevation-z8 {
|
||||
|
|
|
@ -22,27 +22,32 @@
|
|||
</div>
|
||||
</div>
|
||||
<mat-divider class="divider"></mat-divider>
|
||||
<div class="search-container">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label i18n="@@searchLabel">Buscar nombre de imagen</mat-label>
|
||||
<input matInput placeholder="Búsqueda" [(ngModel)]="searchTerm" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<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)">
|
||||
|
||||
<!-- Condición para mostrar íconos para isDefault e installed -->
|
||||
<ng-container *ngIf="column.columnDef === 'isDefault' || column.columnDef === 'installed'">
|
||||
<mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'">
|
||||
{{ image[column.columnDef] ? 'check_circle' : 'cancel' }}
|
||||
</mat-icon>
|
||||
</ng-container>
|
||||
|
||||
<!-- Mostrar el downloadUrl truncado con tooltip -->
|
||||
<ng-container *ngIf="column.columnDef === 'downloadUrl'">
|
||||
<span matTooltip="{{ image.downloadUrl }}">
|
||||
{{ image.downloadUrl ? image.downloadUrl.substring(0, 20) + '...' : '' }}
|
||||
</span>
|
||||
</ng-container>
|
||||
|
||||
<!-- Mostrar otros campos normalmente -->
|
||||
<ng-container *ngIf="column.columnDef !== 'isDefault' && column.columnDef !== 'installed' && column.columnDef !== 'downloadUrl'">
|
||||
{{ column.cell(image) }}
|
||||
</ng-container>
|
||||
|
@ -50,7 +55,6 @@
|
|||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions">Acciones</th>
|
||||
<td mat-cell *matCellDef="let image">
|
||||
|
|
|
@ -9,6 +9,7 @@ import {PageEvent} from "@angular/material/paginator";
|
|||
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";
|
||||
|
||||
@Component({
|
||||
selector: 'app-images',
|
||||
|
@ -23,6 +24,8 @@ export class ImagesComponent implements OnInit {
|
|||
page: number = 1;
|
||||
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
|
||||
selectedElements: string[] = [];
|
||||
loading:boolean = false;
|
||||
searchTerm: string = '';
|
||||
alertMessage: string | null = null;
|
||||
readonly panelOpenState = signal(false);
|
||||
datePipe: DatePipe = new DatePipe('es-ES');
|
||||
|
@ -65,26 +68,15 @@ export class ImagesComponent implements OnInit {
|
|||
constructor(
|
||||
public dialog: MatDialog,
|
||||
private http: HttpClient,
|
||||
private dataService: DataService,
|
||||
private toastService: ToastrService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadImages();
|
||||
this.search();
|
||||
this.loadAlert();
|
||||
}
|
||||
|
||||
loadImages(): void {
|
||||
this.http.get<any>(`${this.apiUrl}?page=1&itemsPerPage=${this.itemsPerPage}`).subscribe({
|
||||
next: (response) => {
|
||||
this.dataSource.data = response['hydra:member'];
|
||||
this.length = response['hydra:totalItems'];
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al cargar las imágenes:', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addImage(): void {
|
||||
const dialogRef = this.dialog.open(CreateImageComponent, {
|
||||
width: '400px'
|
||||
|
@ -92,10 +84,24 @@ export class ImagesComponent implements OnInit {
|
|||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
console.log('The dialog was closed');
|
||||
this.loadImages(); // Opcional: recargar imágenes después de añadir una nueva
|
||||
this.search();
|
||||
});
|
||||
}
|
||||
|
||||
search(): void {
|
||||
this.loading = true;
|
||||
this.dataService.getImages(this.searchTerm).subscribe(
|
||||
data => {
|
||||
this.dataSource.data = data;
|
||||
this.loading = false;
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching og lives', error);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
showInfo(image: any): void {
|
||||
const dialogRef = this.dialog.open(InfoImageComponent, {
|
||||
width: '700px',
|
||||
|
@ -110,7 +116,7 @@ export class ImagesComponent implements OnInit {
|
|||
next: () => {
|
||||
console.log('Imagen cambiada');
|
||||
this.toastService.success('Petición de cambio de imagen enviada');
|
||||
this.loadImages();
|
||||
this.search();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al cambiar la imagen:', error);
|
||||
|
@ -123,7 +129,7 @@ export class ImagesComponent implements OnInit {
|
|||
next: () => {
|
||||
console.log('Imagen cambiada');
|
||||
this.toastService.success('Petición de instalación enviada');
|
||||
this.loadImages();
|
||||
this.search();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al instalar la imagen:', error);
|
||||
|
@ -137,7 +143,7 @@ export class ImagesComponent implements OnInit {
|
|||
console.log('Imagen cambiada');
|
||||
this.toastService.success('Petición de desinstalación enviada');
|
||||
/* this.deleteImage(image); */
|
||||
this.loadImages();
|
||||
this.search();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al desinstalar la imagen:', error);
|
||||
|
@ -151,29 +157,6 @@ export class ImagesComponent implements OnInit {
|
|||
}
|
||||
}
|
||||
|
||||
deleteImage(image: any): void {
|
||||
const dialogRef = this.dialog.open(DeleteModalComponent, {
|
||||
width: '300px',
|
||||
data: { name: image.name }
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.http.delete(`${this.apiUrl}/${image.uuid}`).subscribe({
|
||||
next: () => {
|
||||
console.log('Imagen eliminada');
|
||||
this.toastService.success('Image deleted successfully');
|
||||
this.loadImages();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al eliminar la imagen:', error);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('Eliminación de imagen cancelada');
|
||||
}
|
||||
}); }
|
||||
|
||||
editImage(image: any): void {
|
||||
const dialogRef = this.dialog.open(EditImageComponent, {
|
||||
width: '700px',
|
||||
|
@ -182,7 +165,7 @@ export class ImagesComponent implements OnInit {
|
|||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.loadImages();
|
||||
this.search();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -227,7 +210,7 @@ export class ImagesComponent implements OnInit {
|
|||
this.http.post(`${this.apiUrl}/sync`, {})
|
||||
.subscribe(response => {
|
||||
this.toastService.success('Sincronización completada');
|
||||
this.loadImages()
|
||||
this.search()
|
||||
}, error => {
|
||||
console.error('Error al sincronizar', error);
|
||||
this.toastService.error('Error al sincronizar');
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 100px;
|
||||
padding: 10px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
@ -15,11 +17,6 @@
|
|||
margin-top: 16px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-left: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
@ -54,26 +51,13 @@ button {
|
|||
align-self: center;
|
||||
}
|
||||
|
||||
.mat-menu {
|
||||
min-width: 160px;
|
||||
}
|
||||
|
||||
.template-name{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-container h1 {
|
||||
margin: 0;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.mat-elevation-z8 {
|
||||
|
|
|
@ -1,27 +1,60 @@
|
|||
<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-expansion-panel-header>
|
||||
<p *ngIf="alertMessage">Oglives creados en servidor ogBoot: {{ alertMessage }}</p>
|
||||
<p *ngIf="alertMessage">Oglives creados en servidor ogCore (base de datos): {{ length }}</p>
|
||||
|
||||
<div class="example-button-row">
|
||||
<button mat-flat-button color="primary" (click)="syncOgCore()"> Sincronizar OgCore</button>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
|
||||
<div class="header-container">
|
||||
<h2 class="title" i18n="@@adminPXETitle">Administrar ficheros de arranque PXE</h2>
|
||||
</div>
|
||||
|
||||
<mat-divider class="divider"></mat-divider>
|
||||
<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)">
|
||||
{{ column.cell(image) }}
|
||||
<th mat-header-cell *matHeaderCellDef>{{column.header}}</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
<ng-container *ngIf="column.columnDef === 'clients'">
|
||||
<button mat-icon-button [matMenuTriggerFor]="clientsMenu">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
</button>
|
||||
<mat-menu #clientsMenu="matMenu">
|
||||
<ng-container *ngFor="let client of column.cell(element)">
|
||||
<button mat-menu-item>
|
||||
<mat-list>
|
||||
<mat-list-item lines="3">
|
||||
<span matListItemTitle>{{ client.name }}</span>
|
||||
<span matListItemLine>{{ client.ip }}</span>
|
||||
<span matListItemLine>{{client.mac}}</span>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</button>
|
||||
</ng-container>
|
||||
</mat-menu>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="column.columnDef !== 'clients'">
|
||||
{{column.cell(element)}}
|
||||
</ng-container>
|
||||
</td>
|
||||
<td mat-cell *matCellDef="let user" > {{ column.cell(user) }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions">Acciones</th>
|
||||
<td mat-cell *matCellDef="let image">
|
||||
<button mat-button color="primary" (click)="editPxeTemplate(image)" i18n="@@editImage">Editar</button>
|
||||
<button mat-button color="warn" (click)="deletePxeTemplate(image)" i18n="@@buttonDeleteUser">Eliminar</button>
|
||||
<button mat-button [matMenuTriggerFor]="menu">
|
||||
Acciones (ogBoot)
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button mat-menu-item (click)="toggleAction(image, 'create')">Crear</button>
|
||||
<button mat-menu-item (click)="toggleAction(image, 'delete')">Eliminar</button>
|
||||
</mat-menu>
|
||||
</td>
|
||||
|
|
|
@ -2,9 +2,11 @@ import { Component } from '@angular/core';
|
|||
import {MatTableDataSource} from "@angular/material/table";
|
||||
import {MatDialog} from "@angular/material/dialog";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import { CreatePxeTemplateComponent } from '../pxe/pxe/create-pxeTemplate/create-pxe-template/create-pxe-template.component';
|
||||
import { EditPxeTemplateComponent } from '../pxe/pxe/edit-pxe-template/edit-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 {ToastrService} from "ngx-toastr";
|
||||
import {DatePipe} from "@angular/common";
|
||||
|
||||
@Component({
|
||||
selector: 'app-pxe-boot-files',
|
||||
|
@ -16,9 +18,11 @@ export class PxeBootFilesComponent {
|
|||
currentPage: number = 1;
|
||||
dataSource = new MatTableDataSource<any>();
|
||||
length: number = 0;
|
||||
alertMessage: string | null = null;
|
||||
itemsPerPage: number = 10;
|
||||
page: number = 1;
|
||||
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
|
||||
datePipe: DatePipe = new DatePipe('es-ES');
|
||||
selectedElements: string[] = [];
|
||||
columns = [
|
||||
{
|
||||
|
@ -27,27 +31,38 @@ export class PxeBootFilesComponent {
|
|||
cell: (user: any) => `${user.id}`
|
||||
},
|
||||
{
|
||||
columnDef: 'name',
|
||||
columnDef: 'templateName',
|
||||
header: 'Nombre de la plantilla',
|
||||
cell: (user: any) => `${user.name}`
|
||||
cell: (user: any) => `${user.template.name}`
|
||||
},
|
||||
{
|
||||
columnDef: 'clients',
|
||||
header: 'Clientes',
|
||||
cell: (user: any) => user.clients
|
||||
},
|
||||
{
|
||||
columnDef: 'createdAt',
|
||||
header: 'Fecha de creación',
|
||||
cell: (user: any) => `${user.createdAt}`
|
||||
cell: (user: any) => `${this.datePipe.transform(user.createdAt, 'dd/MM/yyyy hh:mm:ss')}`
|
||||
}
|
||||
];
|
||||
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
||||
|
||||
private apiUrl = 'http://127.0.0.1:8080/pxe-boot-files';
|
||||
|
||||
constructor(public dialog: MatDialog, private http: HttpClient) { }
|
||||
constructor(
|
||||
public dialog: MatDialog,
|
||||
private http: HttpClient,
|
||||
private toastService: ToastrService
|
||||
)
|
||||
{ }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadPxeTemplates();
|
||||
this.loadPxeBootFiles();
|
||||
this.loadAlert();
|
||||
}
|
||||
|
||||
loadPxeTemplates(): void {
|
||||
loadPxeBootFiles(): void {
|
||||
this.http.get<any>(`${this.apiUrl}?page=1&itemsPerPage=${this.itemsPerPage}`).subscribe({
|
||||
next: (response) => {
|
||||
this.dataSource.data = response['hydra:member'];
|
||||
|
@ -65,7 +80,7 @@ export class PxeBootFilesComponent {
|
|||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(() => {
|
||||
this.loadPxeTemplates();
|
||||
this.loadPxeBootFiles();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -79,7 +94,7 @@ export class PxeBootFilesComponent {
|
|||
this.http.post(`${this.apiUrl}/server/${image.uuid}/post`, {}).subscribe({
|
||||
next: () => {
|
||||
console.log('Plantilla cambiada');
|
||||
this.loadPxeTemplates();
|
||||
this.loadPxeBootFiles();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al cambiar la imagen:', error);
|
||||
|
@ -90,7 +105,7 @@ export class PxeBootFilesComponent {
|
|||
this.http.post(`${this.apiUrl}/server/${image.uuid}/delete`, {}).subscribe({
|
||||
next: () => {
|
||||
console.log('Plantilla cambiada');
|
||||
this.loadPxeTemplates();
|
||||
this.loadPxeBootFiles();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al cambiar la imagen:', error);
|
||||
|
@ -113,7 +128,7 @@ export class PxeBootFilesComponent {
|
|||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(() => {
|
||||
this.loadPxeTemplates();
|
||||
this.loadPxeBootFiles();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -135,4 +150,33 @@ export class PxeBootFilesComponent {
|
|||
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.loadPxeBootFiles()
|
||||
}, error => {
|
||||
console.error('Error al sincronizar', error);
|
||||
this.toastService.error('Error al sincronizar');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class DataService {
|
||||
private apiUrl = 'http://127.0.0.1:8080/pxe-templates?page=1&itemsPerPage=1000';
|
||||
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
getPxeTemplates(search: string = ''): Observable<any[]> {
|
||||
let url = `${this.apiUrl}`;
|
||||
if (search) {
|
||||
url += `&name=${encodeURIComponent(search)}`;
|
||||
}
|
||||
|
||||
return this.http.get<any>(url).pipe(
|
||||
map(response => {
|
||||
if (response['hydra:member'] && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member'];
|
||||
} else {
|
||||
throw new Error('Unexpected response format');
|
||||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching pxe templates', error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
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;
|
||||
}
|
|
@ -4,23 +4,13 @@
|
|||
align-items: center;
|
||||
height: 100px;
|
||||
padding: 10px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.templates-button-row {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-left: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
@ -55,10 +45,6 @@ button {
|
|||
align-self: center;
|
||||
}
|
||||
|
||||
.mat-menu {
|
||||
min-width: 160px;
|
||||
}
|
||||
|
||||
.template-name{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -68,6 +54,10 @@ table {
|
|||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.search-container mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header-container {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
|
@ -75,10 +65,6 @@ table {
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.header-container h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mat-elevation-z8 {
|
||||
box-shadow: 0px 0px 0px rgba(0,0,0,0.2);
|
||||
}
|
|
@ -8,6 +8,9 @@
|
|||
</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>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
|
||||
|
@ -18,6 +21,14 @@
|
|||
</div>
|
||||
</div>
|
||||
<mat-divider class="divider"></mat-divider>
|
||||
<div class="search-container">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label i18n="@@searchLabel">Buscar nombre de plantilla</mat-label>
|
||||
<input matInput placeholder="Búsqueda" [(ngModel)]="searchTerm" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar </mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<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>
|
|
@ -1,13 +1,14 @@
|
|||
import { HttpClient } from '@angular/common/http';
|
||||
import { Component } from '@angular/core';
|
||||
import { CreatePxeTemplateComponent } from './create-pxeTemplate/create-pxe-template/create-pxe-template.component';
|
||||
import { CreatePxeTemplateComponent } from './create-pxeTemplate/create-pxe-template.component';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { EditPxeTemplateComponent } from './edit-pxe-template/edit-pxe-template.component';
|
||||
import {MatTableDataSource} from "@angular/material/table";
|
||||
import {PageEvent} from "@angular/material/paginator";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
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";
|
||||
|
||||
@Component({
|
||||
selector: 'app-pxe',
|
||||
|
@ -23,6 +24,8 @@ export class PxeComponent {
|
|||
page: number = 1;
|
||||
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
|
||||
selectedElements: string[] = [];
|
||||
loading:boolean = false;
|
||||
searchTerm: string = ''
|
||||
alertMessage: string | null = null;
|
||||
datePipe: DatePipe = new DatePipe('es-ES');
|
||||
selectedItem: any = null;
|
||||
|
@ -57,24 +60,26 @@ export class PxeComponent {
|
|||
public dialog: MatDialog,
|
||||
private http: HttpClient,
|
||||
private toastService: ToastrService,
|
||||
private dataService: DataService
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadPxeTemplates();
|
||||
this.loadAlert()
|
||||
this.search()
|
||||
this.loadAlert();
|
||||
}
|
||||
|
||||
loadPxeTemplates(): void {
|
||||
this.http.get<any>(`${this.apiUrl}?page=1&itemsPerPage=${this.itemsPerPage}`).subscribe({
|
||||
next: (response) => {
|
||||
this.dataSource.data = response['hydra:member'];
|
||||
this.length = response['hydra:totalItems'];
|
||||
console.log('Plantillas PXE cargadas:', this.pxeTemplates);
|
||||
search(): void {
|
||||
this.loading = true;
|
||||
this.dataService.getPxeTemplates(this.searchTerm).subscribe(
|
||||
data => {
|
||||
this.dataSource.data = data;
|
||||
this.loading = false;
|
||||
},
|
||||
error: error => {
|
||||
console.error('Error al cargar plantillas PXE:', error);
|
||||
error => {
|
||||
console.error('Error fetching pxe templates', error);
|
||||
this.loading = false;
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
addPxeTemplate() {
|
||||
|
@ -83,7 +88,7 @@ export class PxeComponent {
|
|||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(() => {
|
||||
this.loadPxeTemplates();
|
||||
this.search();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -98,7 +103,7 @@ export class PxeComponent {
|
|||
case 'create':
|
||||
this.http.post(`${this.apiUrl}/server/${image.uuid}/post`, {}).subscribe({
|
||||
next: (response) => {
|
||||
this.loadPxeTemplates();
|
||||
this.search();
|
||||
// @ts-ignore
|
||||
this.toastService.success(response.message);
|
||||
},
|
||||
|
@ -111,7 +116,7 @@ export class PxeComponent {
|
|||
this.http.post(`${this.apiUrl}/server/${image.uuid}/delete`, {}).subscribe({
|
||||
next: () => {
|
||||
console.log('Plantilla cambiada');
|
||||
this.loadPxeTemplates();
|
||||
this.search();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al cambiar la imagen:', error);
|
||||
|
@ -124,40 +129,14 @@ export class PxeComponent {
|
|||
}
|
||||
}
|
||||
|
||||
deletePxeTemplate(template: any) {
|
||||
// Lógica para eliminar una plantilla
|
||||
const dialogRef = this.dialog.open(DeleteModalComponent, {
|
||||
width: '300px'
|
||||
});
|
||||
|
||||
console.log('Eliminando pxe:', template.uuid);
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.http.delete(`http://127.0.0.1:8080/pxe-templates/${template.uuid}`).subscribe({
|
||||
next: () => {
|
||||
console.log('pxe eliminado');
|
||||
this.toastService.success('PXE deleted successfully');
|
||||
this.loadPxeTemplates();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al eliminar la pxe:', error);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('Eliminación de pxe cancelada');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
editPxeTemplate(template: any) {
|
||||
const dialogRef = this.dialog.open(EditPxeTemplateComponent, {
|
||||
data: template
|
||||
data: template,
|
||||
width: '600px'
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(() => {
|
||||
this.loadPxeTemplates();
|
||||
this.search();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -197,4 +176,14 @@ export class PxeComponent {
|
|||
}
|
||||
}
|
||||
|
||||
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');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
mat-form-field {
|
||||
width: 100%;
|
||||
margin-bottom: 16px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 48%;
|
||||
}
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.mat-form-field {
|
||||
width: 100%;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.mat-step-label {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.mat-stepper-header {
|
||||
background-color: #fff;
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.mat-stepper-horizontal-line {
|
||||
border-color: #3f51b5;
|
||||
}
|
||||
|
||||
.mat-stepper-horizontal {
|
||||
background-color: #fff;
|
||||
padding: 0;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mat-step-header {
|
||||
background-color: #e8eaf6;
|
||||
color: #3f51b5;
|
||||
}
|
||||
|
||||
.mat-step-header .mat-step-icon {
|
||||
background-color: #3f51b5;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.mat-stepper-content {
|
||||
padding: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 0 0 8px 8px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #e8eaf6;
|
||||
padding: 16px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.mat-raised-button {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.mat-button {
|
||||
margin-right: 8px;
|
||||
}
|
Loading…
Reference in New Issue