refs #1968. Pxe some UX improvements
parent
a3f99958a3
commit
fc51481977
|
@ -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;
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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>
|
|
@ -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 {
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue