refs #798 Add styling to task-logs component and implement filtering functionality

oggui/calendar
Alvaro Puente Mella 2024-10-02 14:31:50 +02:00
parent d661d5c06c
commit 3089ca92fc
6 changed files with 195 additions and 66 deletions

View File

@ -1,36 +1,57 @@
<div class="detail-command-group-container">
<h2>Detalles del Grupo de Comandos</h2>
<h2>Detalles del Grupo de Comandos</h2>
<mat-card>
<mat-card-header>
<mat-card-title>{{ data.name }}</mat-card-title>
<mat-card-subtitle>Creado por: {{ data.createdBy }}</mat-card-subtitle>
</mat-card-header>
<mat-card>
<mat-card-header>
<mat-card-title>{{ data.name }}</mat-card-title>
<mat-card-subtitle>Creado por: {{ data.createdBy }}</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<p><strong>ID del Grupo:</strong> {{ data.uuid }}</p>
<p><strong>Fecha de Creación:</strong> {{ data.createdAt | date:'short' }}</p>
<mat-card-content>
<p><strong>ID del Grupo:</strong> {{ data.uuid }}</p>
<p><strong>Fecha de Creación:</strong> {{ data.createdAt | date:'short' }}</p>
<h3>Comandos Incluidos:</h3>
<table mat-table [dataSource]="data.commands" class="mat-elevation-z8">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Nombre </th>
<td mat-cell *matCellDef="let command"> {{ command.name }} </td>
</ng-container>
<ng-container matColumnDef="uuid">
<th mat-header-cell *matHeaderCellDef> UUID </th>
<td mat-cell *matCellDef="let command"> {{ command.uuid }} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="['name', 'uuid']"></tr>
<tr mat-row *matRowDef="let row; columns: ['name', 'uuid'];"></tr>
</table>
</mat-card-content>
</mat-card>
<div class="command-group-actions">
<button mat-flat-button color="warn" (click)="close()">Cancelar</button>
</div>
<h3>Comandos Incluidos:</h3>
<table mat-table [dataSource]="data.commands" class="mat-elevation-z8">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Nombre </th>
<td mat-cell *matCellDef="let command"> {{ command.name }} </td>
</ng-container>
<ng-container matColumnDef="uuid">
<th mat-header-cell *matHeaderCellDef> UUID </th>
<td mat-cell *matCellDef="let command"> {{ command.uuid }} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="['name', 'uuid']"></tr>
<tr mat-row *matRowDef="let row; columns: ['name', 'uuid'];"></tr>
</table>
</mat-card-content>
</mat-card>
<!-- Sección para seleccionar clientes -->
<div class="additional-section" *ngIf="showClientSelect">
<form [formGroup]="form">
<h4>Selecciona los clientes:</h4>
<mat-form-field appearance="fill">
<mat-label>Clientes</mat-label>
<mat-select formControlName="selectedClients" multiple (selectionChange)="onClientSelectionChange($event)">
<mat-option *ngFor="let client of clients" [value]="client.uuid">
{{ client.name }}
</mat-option>
</mat-select>
<mat-error *ngIf="form.get('selectedClients')?.invalid && form.get('selectedClients')?.touched">
Debes seleccionar al menos un cliente.
</mat-error>
</mat-form-field>
</form>
</div>
<div class="command-group-actions">
<button mat-flat-button color="primary" (click)="toggleClientSelect()">
{{ showClientSelect ? 'Ejecutar' : 'Programar Ejecución' }}
</button>
<button mat-flat-button color="warn" (click)="close()">Cancelar</button>
</div>
</div>

View File

@ -1,18 +1,74 @@
import { Component, Inject } from '@angular/core';
import { Component, Inject, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { HttpClient } from '@angular/common/http';
import { ToastrService } from 'ngx-toastr';
@Component({
selector: 'app-detail-command-group',
templateUrl: './detail-command-group.component.html',
styleUrls: ['./detail-command-group.component.css']
})
export class DetailCommandGroupComponent {
export class DetailCommandGroupComponent implements OnInit {
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
form!: FormGroup;
clients: any[] = [];
showClientSelect = false; // Ocultar selección de clientes inicialmente
canExecute = false;
constructor(
@Inject(MAT_DIALOG_DATA) public data: any,
private dialogRef: MatDialogRef<DetailCommandGroupComponent>
) {}
private dialogRef: MatDialogRef<DetailCommandGroupComponent>,
private fb: FormBuilder,
private http: HttpClient,
private toastService: ToastrService
) { }
ngOnInit(): void {
this.form = this.fb.group({
selectedClients: [[], Validators.required],
});
// Obtener la lista de clientes
this.http.get<any>(`${this.baseUrl}/clients?page=1&itemsPerPage=30`).subscribe(response => {
this.clients = response['hydra:member'];
});
}
toggleClientSelect(): void {
if (!this.showClientSelect) {
this.showClientSelect = true; // Mostrar selección de clientes
} else {
this.execute(); // Ejecutar si ya está visible
}
}
execute(): void {
if (this.form.get('selectedClients')?.value.length > 0) {
const payload = {
clients: this.form.value.selectedClients.map((uuid: any) => `/clients/${uuid}`)
};
const apiUrl = `${this.baseUrl}/command-groups/${this.data.uuid}/execute`;
this.http.post(apiUrl, payload).subscribe({
next: () => {
this.dialogRef.close();
this.toastService.success('Grupo de comandos ejecutado exitosamente');
},
error: (error) => {
console.error('Error ejecutando grupo de comandos:', error);
}
});
} else {
this.form.get('selectedClients')?.markAsTouched();
}
}
onClientSelectionChange(event: any): void {
this.canExecute = this.form.get('selectedClients')?.value.length > 0;
}
close(): void {
this.dialogRef.close();
this.dialogRef.close();
}
}

View File

@ -0,0 +1,3 @@
mat-form-field{
margin: 10px;
}

View File

@ -1,40 +1,65 @@
<div class="header-container">
<h2 class="title">Trazas de ejecuciones</h2>
</div>
<h2 class="title">Trazas de ejecuciones</h2>
<table mat-table [dataSource]="traces" class="mat-elevation-z8">
<ng-container matColumnDef="commandName">
<mat-form-field appearance="fill">
<mat-label>Buscar por comando</mat-label>
<input matInput [(ngModel)]="searchCommand" (ngModelChange)="filterTraces()" placeholder="Escribe el nombre del comando">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Buscar por cliente</mat-label>
<input matInput [(ngModel)]="searchClient" (ngModelChange)="filterTraces()" placeholder="Escribe el nombre del cliente">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Buscar por estado</mat-label>
<input matInput [(ngModel)]="searchStatus" (ngModelChange)="filterTraces()" placeholder="Escribe el estado">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Buscar por usuario</mat-label>
<input matInput [(ngModel)]="searchCreatedBy" (ngModelChange)="filterTraces()" placeholder="Escribe quien creó">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Buscar por fecha </mat-label>
<input matInput [(ngModel)]="searchExecutedAt" (ngModelChange)="filterTraces()" placeholder="Escribe la fecha ejecutada">
</mat-form-field>
</div>
<table mat-table [dataSource]="filteredTraces" class="mat-elevation-z8">
<ng-container matColumnDef="commandName">
<th mat-header-cell *matHeaderCellDef> Comando </th>
<td mat-cell *matCellDef="let trace"> {{ trace.command.name }} </td>
</ng-container>
<ng-container matColumnDef="clientName">
</ng-container>
<ng-container matColumnDef="clientName">
<th mat-header-cell *matHeaderCellDef> Cliente </th>
<td mat-cell *matCellDef="let trace"> {{ trace.client.name }} </td>
</ng-container>
<ng-container matColumnDef="status">
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef> Estado </th>
<td mat-cell *matCellDef="let trace"> {{ trace.status }} </td>
</ng-container>
<ng-container matColumnDef="executedAt">
</ng-container>
<ng-container matColumnDef="executedAt">
<th mat-header-cell *matHeaderCellDef> Ejecutado En </th>
<td mat-cell *matCellDef="let trace"> {{ trace.executedAt | date:'short' }} </td>
</ng-container>
<ng-container matColumnDef="createdBy">
</ng-container>
<ng-container matColumnDef="createdBy">
<th mat-header-cell *matHeaderCellDef> Creado Por </th>
<td mat-cell *matCellDef="let trace"> {{ trace.createdBy }} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [length]="length"
[pageSize]="itemsPerPage"
[pageSizeOptions]="pageSizeOptions"
(page)="onPageChange($event)">
</mat-paginator>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [length]="length"
[pageSize]="itemsPerPage"
[pageSizeOptions]="pageSizeOptions"
(page)="onPageChange($event)">
</mat-paginator>

View File

@ -10,12 +10,20 @@ export class TaskLogsComponent implements OnInit {
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; // Utilizando baseUrl desde el env
traces: any[] = [];
filteredTraces: any[] = []; // Nueva variable para las trazas filtradas
length: number = 0;
itemsPerPage: number = 20;
page: number = 1;
pageSizeOptions: number[] = [10, 20, 30, 50];
displayedColumns: string[] = ['commandName', 'clientName', 'status', 'executedAt', 'createdBy'];
// Variables para los términos de búsqueda
searchCommand: string = '';
searchClient: string = '';
searchStatus: string = '';
searchCreatedBy: string = '';
searchExecutedAt: string = '';
constructor(private http: HttpClient) {}
ngOnInit(): void {
@ -30,6 +38,7 @@ export class TaskLogsComponent implements OnInit {
(data) => {
this.traces = data['hydra:member'];
this.length = data['hydra:totalItems'];
this.filteredTraces = this.traces; // Inicializa con todas las trazas
console.log('Traces:', this.traces);
},
(error) => {
@ -44,4 +53,19 @@ export class TaskLogsComponent implements OnInit {
this.itemsPerPage = event.pageSize; // Actualiza los ítems por página
this.loadTraces(); // Recarga las trazas con los nuevos parámetros de paginación
}
// Método para filtrar las trazas
filterTraces(): void {
this.filteredTraces = this.traces.filter(trace => {
const commandMatch = trace.command.name.toLowerCase().includes(this.searchCommand.toLowerCase());
const clientMatch = trace.client.name.toLowerCase().includes(this.searchClient.toLowerCase());
const statusMatch = trace.status.toLowerCase().includes(this.searchStatus.toLowerCase());
const createdByMatch = trace.createdBy.toLowerCase().includes(this.searchCreatedBy.toLowerCase());
const executedAtMatch = trace.executedAt.toLowerCase().includes(this.searchExecutedAt.toLowerCase());
return commandMatch && clientMatch && statusMatch && createdByMatch && executedAtMatch;
});
this.length = this.filteredTraces.length; // Actualiza la longitud para el paginador
}
}

View File

@ -22,7 +22,7 @@ export class EditOrganizationalUnitComponent implements OnInit {
parentUnits: any[] = [];
hardwareProfiles: any[] = [];
isEditMode: boolean;
currentCalendar: any;
currentCalendar: any = [];
protected p2pModeOptions = [
{"name": 'Leecher', "value": "p2p-mode-leecher"},
{"name": 'Peer', "value": "p2p-mode-peer"},