refs #1968. Pxe some UX improvements

pull/22/head
Manuel Aranda Rosales 2025-05-08 08:01:14 +02:00
parent a3f99958a3
commit fc51481977
14 changed files with 198 additions and 267 deletions

View File

@ -51,21 +51,3 @@
.mat-elevation-z8 {
box-shadow: 0px 0px 0px rgba(0, 0, 0, 0.2);
}
.example-headers-align .mat-expansion-panel-header-description {
justify-content: space-between;
align-items: center;
}
.example-headers-align .mat-mdc-form-field+.mat-mdc-form-field {
margin-left: 8px;
}
.example-button-row {
display: table-cell;
max-width: 600px;
}
.example-button-row .mat-mdc-button-base {
margin: 8px 8px 8px 0;
}

View File

@ -37,7 +37,7 @@
</button>
</div>
<mat-table [dataSource]="dataSource" class="mat-elevation-z8" joyrideStep="tableStep"
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" joyrideStep="tableStep"
text="{{ 'tableDescription' | translate }}">
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef>{{ 'idColumnHeader' | translate }}</mat-header-cell>
@ -50,12 +50,12 @@
</ng-container>
<ng-container matColumnDef="ip">
<mat-header-cell *matHeaderCellDef>{{ 'nameColumnHeader' | translate }}</mat-header-cell>
<mat-header-cell *matHeaderCellDef>{{ 'ipLabel' | translate }}</mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.ip }} </mat-cell>
</ng-container>
<ng-container matColumnDef="mac">
<mat-header-cell *matHeaderCellDef>{{ 'nameColumnHeader' | translate }}</mat-header-cell>
<mat-header-cell *matHeaderCellDef>{{ 'macLabel' | translate }}</mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.mac }} </mat-cell>
</ng-container>
@ -77,4 +77,4 @@
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
</table>

View File

@ -4,6 +4,7 @@ import { HttpClient } from '@angular/common/http';
import { ToastrService } from 'ngx-toastr';
import { ConfigService } from '@services/config.service';
import { JoyrideService } from 'ngx-joyride';
import {MatTableDataSource} from "@angular/material/table";
@Component({
selector: 'app-pxe-boot-files',
@ -15,7 +16,7 @@ export class PxeBootFilesComponent implements OnInit {
availableOrganizationalUnits: any[] = [];
selectedUnitChildren: any[] = [];
dataSource: any[] = [];
dataSource = new MatTableDataSource<any>();
taskForm: FormGroup;
units: any[] = [];
ogLiveOptions: any[] = [];
@ -72,14 +73,14 @@ export class PxeBootFilesComponent implements OnInit {
loadChildUnits(event: any) {
this.http.get<any>(`${this.baseUrl}/clients?organizationalUnit.id=${event.value.id}`).subscribe(
response => {
this.dataSource = response['hydra:member'];
this.dataSource.data = response['hydra:member'];
},
error => console.error('Error fetching child units:', error)
);
}
applyToAll(): void {
this.dataSource = this.dataSource.map(client => ({
this.dataSource.data = this.dataSource.data.map(client => ({
...client,
ogLive: this.globalOgLive || client.ogLive
}));
@ -88,7 +89,7 @@ export class PxeBootFilesComponent implements OnInit {
saveOgLiveTemplates(): void {
const groupedByTemplate: { [key: string]: string[] } = {};
this.dataSource.forEach(client => {
this.dataSource.data.forEach(client => {
if (client.ogLive) {
if (!groupedByTemplate[client.ogLive]) {
groupedByTemplate[client.ogLive] = [];
@ -107,10 +108,10 @@ export class PxeBootFilesComponent implements OnInit {
this.http.post(url, payload).subscribe({
next: () => {
this.toastService.success(`Clientes guardados correctamente para la plantilla ${templateId}`);
this.toastService.success(`Clientes guardados correctamente para la plantilla`);
},
error: () => {
this.toastService.error(`Error al guardar clientes para la plantilla ${templateId}`);
this.toastService.error(`Error al guardar clientes para la plantilla`);
}
});
});

View File

@ -8,7 +8,7 @@
</h2>
</div>
<div class="images-button-row">
<button class="action-button" (click)="openSubnetInfoDialog()">{{ 'viewInfoButton' | translate }}</button>
<button class="action-button" joyrideStep="viewInfoStep" [text]="'viewInfoStepText' | translate" (click)="openSubnetInfoDialog()">{{ 'viewInfoButton' | translate }}</button>
<button class="action-button" (click)="addImage()" joyrideStep="addImageStep"
[text]="'addOgLiveButtonDescription' | translate">
{{ 'addOgLiveButton' | translate }}
@ -57,14 +57,14 @@
<th mat-header-cell *matHeaderCellDef>{{ column.header }}</th>
<td mat-cell *matCellDef="let image">
<ng-container *ngIf="column.columnDef === 'isDefault'">
<mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'">
<ng-container *ngIf="image[column.columnDef]; else cancelIcon">
{{ 'checkCircle' | translate }}
<mat-chip>
<ng-container *ngIf="image.isDefault">
{{ 'yesOption' | translate }}
</ng-container>
<ng-template #cancelIcon>
{{ 'cancelIcon' | translate }}
</ng-template>
</mat-icon>
<ng-container *ngIf="!image.isDefault">
{{ 'noOption' | translate }}
</ng-container>
</mat-chip>
</ng-container>
<ng-container *ngIf="column.columnDef === 'downloadUrl'">
@ -99,9 +99,6 @@
<button mat-icon-button color="info" (click)="showOgLive($event, image)">
<mat-icon>{{ 'viewIcon' | translate }}</mat-icon>
</button>
<button mat-icon-button disabled color="primary" (click)="editImage(image)">
<mat-icon>{{ 'editIcon' | translate }}</mat-icon>
</button>
<button mat-icon-button color="warn" (click)="deleteImage(image)">
<mat-icon>{{ 'deleteIcon' | translate }}</mat-icon>
</button>

View File

@ -25,8 +25,8 @@ export class PXEimagesComponent implements OnInit {
images: { downloadUrl: string; name: string; uuid: string }[] = [];
dataSource = new MatTableDataSource<any>();
length: number = 0;
itemsPerPage: number = 10;
page: number = 1;
itemsPerPage: number = 20;
page: number = 0;
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
selectedElements: string[] = [];
loading: boolean = false;
@ -94,12 +94,15 @@ export class PXEimagesComponent implements OnInit {
}
search(): void {
this.dataService.getImages(this.filters).subscribe(
this.loading = true;
this.http.get<any>(`${this.apiUrl}?page=${this.page +1 }&itemsPerPage=${this.itemsPerPage}`, { params: this.filters }).subscribe(
data => {
this.dataSource.data = data;
this.dataSource.data = data['hydra:member'];
this.length = data['hydra:totalItems'];
this.loading = false;
},
error => {
console.error('Error fetching og lives', error);
this.loading = false;
}
);
}
@ -160,19 +163,6 @@ export class PXEimagesComponent implements OnInit {
}
}
editImage(image: any): void {
const dialogRef = this.dialog.open(CreatePXEImageComponent, {
width: '700px',
data: image
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
this.search();
}
});
}
deleteImage(image: any): void {
const dialogRef = this.dialog.open(DeleteModalComponent, {
width: '400px',
@ -203,22 +193,11 @@ export class PXEimagesComponent implements OnInit {
const dialogRef = this.dialog.open(InfoImageComponent, { data: { data }, width: '700px' });
}
applyFilter() {
this.http.get<any>(`${this.apiUrl}?page=${this.page}&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);
}
});
}
onPageChange(event: PageEvent) {
onPageChange(event: any): void {
this.page = event.pageIndex;
this.itemsPerPage = event.pageSize;
this.applyFilter();
this.length = event.length;
this.search();
}
loadAlert(): Observable<any> {
@ -248,6 +227,7 @@ export class PXEimagesComponent implements OnInit {
this.joyrideService.startTour({
steps: [
'titleStep',
'viewInfoStep',
'addImageStep',
'searchNameStep',
'searchDefaultImageStep',

View File

@ -1,43 +0,0 @@
<h2 mat-dialog-title>{{ isEditMode ? ('editTemplateTitle' | translate) : ('addTemplateTitle' | translate) }}</h2>
<mat-dialog-content>
<div class="spacing-container">
<form [formGroup]="templateForm" (ngSubmit)="onSave()">
<mat-form-field appearance="fill">
<mat-label>{{ 'templateNameLabel' | translate }}</mat-label>
<input matInput formControlName="name" [placeholder]="'templateNamePlaceholder' | translate">
<mat-error *ngIf="templateForm.get('name')?.hasError('required')">
{{ 'templateNameError' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>{{ 'templateContentLabel' | translate }}</mat-label>
<textarea matInput formControlName="templateContent" rows="20"
[placeholder]="'templateContentPlaceholder' | translate"></textarea>
<mat-error *ngIf="templateForm.get('templateContent')?.hasError('required')">
{{ 'templateContentError' | translate }}
</mat-error>
</mat-form-field>
</form>
</div>
</mat-dialog-content>
<mat-dialog-actions>
<div class="actions-container">
<button class="action-button" [matMenuTriggerFor]="templateMenu">
{{ 'loadTemplateModelButton' | translate }}
</button>
<mat-menu #templateMenu="matMenu">
<button mat-menu-item (click)="loadTemplateModel('ogLive')">{{ 'ogLiveModel' | translate }}</button>
<button mat-menu-item (click)="loadTemplateModel('disco')">{{ 'diskModel' | translate }}</button>
</mat-menu>
<div class="action-buttons">
<button class="ordinary-button" (click)="onCancel()">{{ 'cancelButton' | translate }}</button>
<button class="submit-button" (click)="onSave()" [disabled]="!templateForm.valid">
{{ isEditMode ? ('updateButton' | translate) : ('createButton' | translate) }}
</button>
</div>
</div>
</mat-dialog-actions>

View File

@ -1,6 +1,3 @@
mat-form-field {
width: 100%;
}
pre {
background-color: #eceff1;
@ -12,41 +9,17 @@ pre {
color: #333;
}
mat-dialog-actions {
margin-top: 20px;
.dialog-content {
display: flex;
justify-content: flex-end;
flex-direction: column;
padding: 40px;
}
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;
}
.spacing-container {
margin-top: 20px;
margin-bottom: 16px;
.pxe-form {
width: 100%;
display: flex;
flex-direction: column;
}
.list-item-content {
@ -56,6 +29,11 @@ h3 {
width: 100%;
}
.form-field {
width: 100%;
margin-top: 16px;
}
.text-content {
flex-grow: 1;
margin-right: 16px;
@ -72,13 +50,11 @@ h3 {
cursor: pointer;
}
.actions-container {
.action-container {
display: flex;
justify-content: space-between;
width: 100%;
align-items: center;
margin-bottom: 1rem;
padding-right: 1rem;
justify-content: flex-end;
gap: 1em;
padding: 1.5em;
}
.action-buttons {

View File

@ -0,0 +1,44 @@
<h2 mat-dialog-title>{{ isEditMode ? ('editTemplateTitle' | translate) : ('addTemplateTitle' | translate) }}</h2>
<mat-dialog-content class="dialog-content">
<form [formGroup]="templateForm" (ngSubmit)="onSave()" class="pxe-form">
<mat-form-field appearance="fill" class="form-field">
<mat-label>{{ 'templateNameLabel' | translate }}</mat-label>
<input matInput formControlName="name" [placeholder]="'templateNamePlaceholder' | translate">
<mat-error *ngIf="templateForm.get('name')?.hasError('required')">
{{ 'templateNameError' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="form-field">
<mat-label>{{ 'templateContent' | translate }}</mat-label>
<textarea matInput formControlName="templateContent" rows="20"
[placeholder]="'templateContentPlaceholder' | translate"></textarea>
<mat-error *ngIf="templateForm.get('templateContent')?.hasError('required')">
{{ 'templateContentError' | translate }}
</mat-error>
</mat-form-field>
<mat-checkbox formControlName="isDefault">
{{ 'isDefaultLabel' | translate }}
</mat-checkbox>
</form>
</mat-dialog-content>
<div mat-dialog-actions class="action-container">
<button class="action-button" [matMenuTriggerFor]="templateMenu">
{{ 'loadTemplateModelButton' | translate }}
</button>
<mat-menu #templateMenu="matMenu">
<button mat-menu-item (click)="loadTemplateModel('ogLive')">{{ 'ogLiveModel' | translate }}</button>
<button mat-menu-item (click)="loadTemplateModel('disco')">{{ 'diskModel' | translate }}</button>
</mat-menu>
<div class="action-buttons">
<button class="ordinary-button" (click)="onCancel()">{{ 'cancelButton' | translate }}</button>
<button class="submit-button" (click)="onSave()" [disabled]="!templateForm.valid">
{{ isEditMode ? ('saveButton' | translate) : ('saveButton' | translate) }}
</button>
</div>
</div>

View File

@ -20,35 +20,35 @@ export class CreatePxeTemplateComponent implements OnInit {
templateModels = {
ogLive: `#!ipxe
set timeout 0
set timeout-style hidden
set ISODIR __OGLIVE__
set default 0
set kernelargs __INFOHOST__
:try_iso
kernel http://__SERVERIP__/tftpboot/\${ISODIR}/ogvmlinuz \${kernelargs} || goto fallback
initrd http://__SERVERIP__/tftpboot/\${ISODIR}/oginitrd.img
boot
set timeout 0
set timeout-style hidden
set ISODIR __OGLIVE__
set default 0
set kernelargs __INFOHOST__
:try_iso
kernel http://__SERVERIP__/tftpboot/\${ISODIR}/ogvmlinuz \${kernelargs} || goto fallback
initrd http://__SERVERIP__/tftpboot/\${ISODIR}/oginitrd.img
boot
:fallback
set ISODIR ogLive
kernel http://__SERVERIP__/tftpboot/\${ISODIR}/ogvmlinuz \${kernelargs}
initrd http://__SERVERIP__/tftpboot/\${ISODIR}/oginitrd.img
boot`,
:fallback
set ISODIR ogLive
kernel http://__SERVERIP__/tftpboot/\${ISODIR}/ogvmlinuz \${kernelargs}
initrd http://__SERVERIP__/tftpboot/\${ISODIR}/oginitrd.img
boot`,
disco: `#!ipxe
disco: `#!ipxe
iseq \${platform} efi && goto uefi_boot || goto bios_boot
iseq \${platform} efi && goto uefi_boot || goto bios_boot
:bios_boot
echo "Running in BIOS mode - Booting first disk"
chain http://__SERVERIP__/tftpboot/grub.exe --config-file="title FirstHardDisk;chainloader (hd0)+1;rootnoverify (hd0);boot" || echo "Failed to boot in BIOS mode"
exit
:bios_boot
echo "Running in BIOS mode - Booting first disk"
chain http://__SERVERIP__/tftpboot/grub.exe --config-file="title FirstHardDisk;chainloader (hd0)+1;rootnoverify (hd0);boot" || echo "Failed to boot in BIOS mode"
exit
:uefi_boot
echo "Running in UEFI mode - Booting first disk"
sanboot --no-describe --drive 0 --filename \\EFI\\grub\\Boot\\grubx64.efi || echo "Failed to boot in UEFI mode"
exit`
:uefi_boot
echo "Running in UEFI mode - Booting first disk"
sanboot --no-describe --drive 0 --filename \\EFI\\grub\\Boot\\grubx64.efi || echo "Failed to boot in UEFI mode"
exit`
};
constructor(
@ -72,7 +72,8 @@ exit`
this.templateForm = this.fb.group({
name: [this.data?.name || '', Validators.required],
templateContent: [this.data?.templateContent || '', Validators.required]
templateContent: [this.data?.templateContent || '', Validators.required],
isDefault: [this.data?.isDefault || false]
});
}
@ -99,7 +100,8 @@ exit`
const formValues = this.templateForm.value;
const payload = {
name: formValues.name,
templateContent: formValues.templateContent
templateContent: formValues.templateContent,
isDefault: formValues.isDefault,
};
this.http.post<any>(`${this.baseUrl}/pxe-templates`, payload).subscribe({
@ -117,7 +119,8 @@ exit`
const formValues = this.templateForm.value;
const payload = {
name: formValues.name,
templateContent: formValues.templateContent
templateContent: formValues.templateContent,
isDefault: formValues.isDefault,
};
this.http.patch<any>(`${this.baseUrl}/pxe-templates/${this.data.uuid}`, payload).subscribe({
@ -138,42 +141,6 @@ exit`
this.toastService.info(`Plantilla ${type} cargada.`);
}
addClientToTemplate(client: any): void {
const postData = {
client: client['@id']
};
this.http.post(`${this.baseUrl}/pxe-templates/${this.data.uuid}/sync-client`, postData).subscribe(
() => {
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);
}

View File

@ -1,5 +1,5 @@
<div class="header-container">
<button mat-icon-button color="primary" (click)="iniciarTour()">
<button mat-icon-button color="primary" (click)="initTour()">
<mat-icon>help</mat-icon>
</button>
<div class="header-container-title">
@ -7,7 +7,7 @@
translate }}</h2>
</div>
<div class="template-button-row">
<button class="action-button" (click)="openInfoDialog()">{{ 'viewInfoButton' | translate }}</button>
<button class="action-button" joyrideStep="viewInfoStep" [text]="'viewInfoStepText' | translate" (click)="openInfoDialog()">{{ 'viewInfoButton' | translate }}</button>
<button class="action-button" (click)="addPxeTemplate()" joyrideStep="addTemplateStep"
text="{{ 'addTemplateButtonDescription' | translate }}">{{ 'addTemplateButton' | translate }}</button>
</div>
@ -22,10 +22,10 @@
<mat-icon matSuffix>search</mat-icon>
<mat-hint>{{ 'searchHint' | translate }}</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill" class="search-boolean" joyrideStep="searchSyncStep"
text="{{ 'searchSyncDescription' | translate }}">
<mat-label>{{ 'createdInOgbootLabel' | translate }}</mat-label>
<mat-select [(ngModel)]="filters['synchronized']" (selectionChange)="search()"
<mat-form-field appearance="fill" class="search-boolean" joyrideStep="searchIsDefaultStep"
text="{{ 'searchIsDefaultText' | translate }}">
<mat-label>{{ 'isDefaultLabel' | translate }}</mat-label>
<mat-select [(ngModel)]="filters['isDefault']" (selectionChange)="search()"
placeholder="{{ 'selectOptionPlaceholder' | translate }}">
<mat-option [value]="''">{{ 'allOption' | translate }}</mat-option>
<mat-option [value]="true">{{ 'yesOption' | translate }}</mat-option>
@ -36,16 +36,31 @@
<app-loading [isLoading]="loading"></app-loading>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" joyrideStep="tableStep"
text="{{ 'tableDescription' | translate }}">
text="{{ 'tableDatePxeTemplateText' | translate }}">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef>{{ column.header }}</th>
<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>
<mat-chip>
<ng-container *ngIf="image.synchronized">
{{ 'yesOption' | translate }}
</ng-container>
<ng-container *ngIf="!image.synchronized">
{{ 'noOption' | translate }}
</ng-container>
</mat-chip>
</ng-container>
<ng-container *ngIf="column.columnDef !== 'synchronized'">
<ng-container *ngIf="column.columnDef === 'isDefault'">
<mat-chip>
<ng-container *ngIf="image.isDefault">
{{ 'yesOption' | translate }}
</ng-container>
<ng-container *ngIf="!image.isDefault">
{{ 'noOption' | translate }}
</ng-container>
</mat-chip>
</ng-container>
<ng-container *ngIf="column.columnDef !== 'synchronized' && column.columnDef !== 'isDefault'">
{{ column.cell(image) }}
</ng-container>
</td>
@ -60,7 +75,7 @@
<button mat-icon-button color="primary" (click)="editPxeTemplate(template)">
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button color="warn" (click)="toggleAction(template, 'delete')">
<button mat-icon-button color="warn" [disabled]="template.isDefault" (click)="toggleAction(template, 'delete')">
<mat-icon>{{ 'deleteIcon' | translate }}</mat-icon>
</button>
</td>

View File

@ -1,9 +1,8 @@
import { HttpClient } from '@angular/common/http';
import {Component, OnInit} from '@angular/core';
import { CreatePxeTemplateComponent } from './create-pxeTemplate/create-pxe-template.component';
import { CreatePxeTemplateComponent } from './manage-pxeTemplate/create-pxe-template.component';
import { MatDialog } from '@angular/material/dialog';
import { MatTableDataSource } from '@angular/material/table';
import { PageEvent } from '@angular/material/paginator';
import { ToastrService } from 'ngx-toastr';
import { DatePipe } from '@angular/common';
import { DataService } from './data.service';
@ -26,8 +25,8 @@ export class PxeComponent implements OnInit{
currentPage: number = 1;
dataSource = new MatTableDataSource<any>();
length: number = 0;
itemsPerPage: number = 10;
page: number = 1;
itemsPerPage: number = 20;
page: number = 0;
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
selectedElements: string[] = [];
loading: boolean = false;
@ -45,17 +44,22 @@ export class PxeComponent implements OnInit{
{
columnDef: 'name',
header: 'Nombre de la plantilla',
cell: (user: any) => `${user.name}`
cell: (user: any) => user.name
},
{
columnDef: 'synchronized',
header: 'Sincronizado',
cell: (user: any) => `${user.synchronized}`
cell: (user: any) => user.synchronized
},
{
columnDef: 'isDefault',
header: 'Plantilla por defecto',
cell: (user: any) => user.isDefault
},
{
columnDef: 'createdAt',
header: 'Fecha de creación',
cell: (user: any) => `${this.datePipe.transform(user.createdAt, 'dd/MM/yyyy hh:mm:ss')}`
cell: (user: any) => this.datePipe.transform(user.createdAt, 'dd/MM/yyyy hh:mm:ss')
}
];
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
@ -80,12 +84,15 @@ export class PxeComponent implements OnInit{
}
search(): void {
this.dataService.getPxeTemplates(this.filters).subscribe(
this.loading = true;
this.http.get<any>(`${this.apiUrl}?page=${this.page +1 }&itemsPerPage=${this.itemsPerPage}`, { params: this.filters }).subscribe(
data => {
this.dataSource.data = data;
this.dataSource.data = data['hydra:member'];
this.length = data['hydra:totalItems'];
this.loading = false;
},
error => {
console.error('Error fetching pxe templates', error);
this.loading = false;
}
);
}
@ -100,10 +107,9 @@ export class PxeComponent implements OnInit{
});
}
editPxeTemplate(template: any) {
const dialogRef = this.dialog.open(CreatePxeTemplateComponent, {
data: template, // Pasa los datos del template para edición
data: template,
width: '800px'
});
@ -128,7 +134,6 @@ export class PxeComponent implements OnInit{
this.search();
},
error: (error) => {
console.error('Error al eliminar la subred', error);
this.toastService.error(error.error['hydra:description']);
}
});
@ -143,19 +148,7 @@ export class PxeComponent implements OnInit{
showTemplate(event: MouseEvent, data: any): void {
event.stopPropagation();
const dialogRef = this.dialog.open(ShowTemplateContentComponent, { data: { data }, width: '700px' });
}
applyFilter() {
this.http.get<any>(`${this.apiUrl}?page=${this.page}&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);
}
});
const dialogRef = this.dialog.open(ShowTemplateContentComponent, { data: { data }, width: '800px' });
}
loadAlert(): Observable<any> {
@ -181,20 +174,21 @@ export class PxeComponent implements OnInit{
);
}
onPageChange(event: PageEvent) {
onPageChange(event: any): void {
this.page = event.pageIndex;
this.itemsPerPage = event.pageSize;
this.applyFilter();
this.length = event.length;
this.search();
}
iniciarTour(): void {
initTour(): void {
this.joyrideService.startTour({
steps: [
'serverInfoStep',
'titleStep',
'viewInfoStep',
'addTemplateStep',
'searchNameStep',
'searchSyncStep',
'searchIsDefaultStep',
'tableStep',
'actionsStep',
'paginationStep'

View File

@ -26,8 +26,15 @@
background-color: #f5f5f5;
padding: 16px;
border-radius: 4px;
font-size: 12px;
font-size: 14px;
overflow-x: auto;
white-space: pre;
border: 1px solid #dcdcdc;
}
.action-container {
display: flex;
justify-content: flex-end;
gap: 1em;
padding: 1.5em;
}

View File

@ -1,4 +1,10 @@
<div class="info-container">
<h3>{{ 'detailsTitle' | translate: { name: data.data.name } }}</h3>
<pre class="code-block">{{ data.data.templateContent }}</pre>
<mat-dialog-content class="dialog-content">
<div class="info-container">
<h3>{{ 'detailsTitle' | translate: { name: data.data.name } }}</h3>
<pre class="code-block">{{ data.data.templateContent }}</pre>
</div>
</mat-dialog-content>
<div mat-dialog-actions class="action-container">
<button class="ordinary-button" (click)="close()">Cancelar</button>
</div>

View File

@ -1,5 +1,5 @@
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA } from "@angular/material/dialog";
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import { HttpClient } from "@angular/common/http";
import { ConfigService } from "@services/config.service";
@ -15,8 +15,13 @@ export class ShowTemplateContentComponent {
constructor(
@Inject(MAT_DIALOG_DATA) public data: any,
private http: HttpClient,
private configService: ConfigService
private configService: ConfigService,
public dialogRef: MatDialogRef<ShowTemplateContentComponent>
) {
this.baseUrl = this.configService.apiUrl;
}
close(): void {
this.dialogRef.close();
}
}