Updated trace and fixed status global

pull/30/head
Manuel Aranda Rosales 2025-06-27 09:36:56 +02:00
parent 0403385421
commit 642a439f21
6 changed files with 200 additions and 20 deletions

View File

@ -44,6 +44,14 @@ export class GlobalStatusComponent implements OnInit {
isDhcp: boolean = false;
isRepository: boolean = false;
// Loading específicos para cada sección
loadingOgBootOgLives: boolean = false;
loadingOgBootServices: boolean = false;
loadingOgBootDisk: boolean = false;
loadingDhcpSubnets: boolean = false;
loadingDhcpServices: boolean = false;
loadingDhcpDisk: boolean = false;
constructor(
private configService: ConfigService,
private toastService: ToastrService,
@ -160,6 +168,7 @@ export class GlobalStatusComponent implements OnInit {
if (data.message.installed_oglives) {
installedOgLives.push(...data.message.installed_oglives);
}
this.loadingOgBootOgLives = false;
}
diskUsageChartData.length = 0;

View File

@ -2,7 +2,7 @@
<div *ngIf="!loading" class="dashboard">
<!-- Sección de uso de recursos -->
<div class="resources-section" [ngClass]="{'repository-layout': isRepository}">
<div class="resources-section">
<!-- Disk Usage Section -->
<div class="resource-card disk-usage-container">
<div class="resource-header">
@ -32,7 +32,7 @@
</div>
<div class="info-item">
<span class="info-label">{{ 'usedPercentageLabel' | translate }}:</span>
<span class="info-value usage-percentage">{{ isRepository ? diskUsage.used_percentage : diskUsage.percentage }}</span>
<span class="info-value usage-percentage">{{ isRepository ? diskUsage.used_percentage : diskUsage.percentage }}%</span>
</div>
</div>
</div>
@ -67,7 +67,7 @@
</div>
<div class="info-item">
<span class="info-label">{{ 'usedPercentageLabel' | translate }}:</span>
<span class="info-value usage-percentage">{{ ramUsage.used_percentage }}</span>
<span class="info-value usage-percentage">{{ ramUsage.used_percentage }}%</span>
</div>
</div>
</div>
@ -84,7 +84,7 @@
<div class="resource-content">
<div class="cpu-usage-display">
<div class="cpu-circle">
<div class="cpu-percentage">{{ cpuUsage.used_percentage }}</div>
<div class="cpu-percentage">{{ cpuUsage.used_percentage }}%</div>
<div class="cpu-label">Uso actual</div>
</div>
</div>

View File

@ -73,9 +73,60 @@
border-left: 4px solid #667eea;
}
.stat-card:hover {
.stat-card.clickable {
cursor: pointer;
position: relative;
overflow: hidden;
}
.stat-card.clickable::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.5s ease;
}
.stat-card.clickable:hover::before {
left: 100%;
}
.stat-card.clickable:hover {
transform: translateY(-3px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}
.stat-card.clickable:active {
transform: translateY(-1px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
.stat-card.active-filter {
transform: translateY(-2px);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.15);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.25);
border: 2px solid #fff;
position: relative;
}
.stat-card.active-filter::after {
content: '✓';
position: absolute;
top: 8px;
right: 8px;
background: rgba(255, 255, 255, 0.9);
color: #28a745;
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 12px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.stat-total {
@ -161,6 +212,35 @@
margin-bottom: 15px;
}
.filters-header-actions {
display: flex;
align-items: center;
gap: 15px;
}
.active-filter-indicator {
display: flex;
align-items: center;
gap: 8px;
background: #e3f2fd;
color: #1976d2;
padding: 8px 12px;
border-radius: 20px;
font-size: 0.9rem;
font-weight: 500;
border: 1px solid #bbdefb;
}
.active-filter-indicator mat-icon {
font-size: 18px;
width: 18px;
height: 18px;
}
.active-filter-indicator button {
margin-left: 4px;
}
.filters-header h3 {
margin: 0;
color: #495057;

View File

@ -22,23 +22,38 @@
</div>
<div class="stats-container" *ngIf="!loading">
<div class="stat-card stat-total">
<div class="stat-card stat-total clickable"
[class.active-filter]="isFilterActive('total')"
(click)="filterByTotal()"
matTooltip="Ver todas las trazas">
<div class="stat-number">{{ totalStats.total }}</div>
<div class="stat-label">{{ 'totalTraces' | translate }}</div>
</div>
<div class="stat-card stat-today">
<div class="stat-card stat-today clickable"
[class.active-filter]="isFilterActive('today')"
(click)="filterByToday()"
matTooltip="Ver trazas de hoy">
<div class="stat-number">{{ getStatusCount('today') }}</div>
<div class="stat-label">{{ 'todayTraces' | translate }}</div>
</div>
<div class="stat-card stat-success">
<div class="stat-card stat-success clickable"
[class.active-filter]="isFilterActive('success')"
(click)="filterBySuccess()"
matTooltip="Ver trazas exitosas">
<div class="stat-number">{{ getStatusCount('success') }}</div>
<div class="stat-label">{{ 'successful' | translate }}</div>
</div>
<div class="stat-card stat-failed">
<div class="stat-card stat-failed clickable"
[class.active-filter]="isFilterActive('failed')"
(click)="filterByFailed()"
matTooltip="Ver trazas fallidas">
<div class="stat-number">{{ getStatusCount('failed') }}</div>
<div class="stat-label">{{ 'failed' | translate }}</div>
</div>
<div class="stat-card stat-in-progress">
<div class="stat-card stat-in-progress clickable"
[class.active-filter]="isFilterActive('in-progress')"
(click)="filterByInProgress()"
matTooltip="Ver trazas en progreso">
<div class="stat-number">{{ getStatusCount('in-progress') }}</div>
<div class="stat-label">{{ 'inProgress' | translate }}</div>
</div>
@ -47,10 +62,20 @@
<div class="filters-section" joyrideStep="filtersStep" text="{{ 'filtersStepText' | translate }}">
<div class="filters-header">
<h3>{{ 'filters' | translate }}</h3>
<button mat-button color="primary" (click)="toggleFilters()">
<mat-icon>{{ showAdvancedFilters ? 'expand_less' : 'expand_more' }}</mat-icon>
{{ showAdvancedFilters ? 'hideAdvanced' : 'showAdvanced' | translate }}
</button>
<div class="filters-header-actions">
<div *ngIf="activeFilter" class="active-filter-indicator">
<mat-icon>filter_alt</mat-icon>
<span>Filtro activo: {{ getActiveFilterLabel() }}</span>
<button mat-icon-button (click)="resetFilters(commandSearchInput, commandStatusInput, commandClientInput)"
matTooltip="Limpiar filtros">
<mat-icon>clear</mat-icon>
</button>
</div>
<button mat-button color="primary" (click)="toggleFilters()">
<mat-icon>{{ showAdvancedFilters ? 'expand_less' : 'expand_more' }}</mat-icon>
{{ showAdvancedFilters ? 'hideAdvanced' : 'showAdvanced' | translate }}
</button>
</div>
</div>
<div class="search-container" [class.expanded]="showAdvancedFilters">

View File

@ -113,6 +113,7 @@ export class TaskLogsComponent implements OnInit, OnDestroy {
clientControl = new FormControl();
filteredCommands!: Observable<any[]>;
commandControl = new FormControl();
activeFilter: string = '';
constructor(private http: HttpClient,
private joyrideService: JoyrideService,
@ -214,7 +215,7 @@ export class TaskLogsComponent implements OnInit, OnDestroy {
const today = new Date();
const todayString = this.datePipe.transform(today, 'yyyy-MM-dd');
return this.traces.filter(trace =>
trace.executedAt && trace.executedAt.startsWith(todayString)
trace.executedAt && todayString && trace.executedAt.startsWith(todayString)
).length;
}
@ -461,7 +462,9 @@ export class TaskLogsComponent implements OnInit, OnDestroy {
const totalRequest = this.http.get<any>(`${this.baseUrl}/traces?page=1&itemsPerPage=1`);
const todayString = this.datePipe.transform(new Date(), 'yyyy-MM-dd');
const todayRequest = this.http.get<any>(`${this.baseUrl}/traces?executedAt[after]=${todayString}&page=1&itemsPerPage=1`);
const todayRequest = todayString ?
this.http.get<any>(`${this.baseUrl}/traces?executedAt[after]=${todayString}&page=1&itemsPerPage=1`) :
this.http.get<any>(`${this.baseUrl}/traces?page=1&itemsPerPage=1`);
forkJoin([totalRequest, ...requests, todayRequest]).subscribe(
(responses) => {
@ -489,7 +492,7 @@ export class TaskLogsComponent implements OnInit, OnDestroy {
pending: this.traces.filter(trace => trace.status === 'pending').length,
inProgress: this.traces.filter(trace => trace.status === 'in-progress').length,
cancelled: this.traces.filter(trace => trace.status === 'cancelled').length,
today: this.traces.filter(trace => trace.executedAt && trace.executedAt.startsWith(todayString)).length
today: this.traces.filter(trace => trace.executedAt && todayString && trace.executedAt.startsWith(todayString)).length
};
}
);
@ -501,6 +504,7 @@ export class TaskLogsComponent implements OnInit, OnDestroy {
clientSearchStatusInput.value = null;
clientSearchClientInput.value = null;
this.filters = {};
this.activeFilter = '';
this.loadTraces();
}
@ -583,7 +587,6 @@ export class TaskLogsComponent implements OnInit, OnDestroy {
});
}
// Métodos para paginación
getPaginationFrom(): number {
return (this.page * this.itemsPerPage) + 1;
}
@ -595,4 +598,67 @@ export class TaskLogsComponent implements OnInit, OnDestroy {
getPaginationTotal(): number {
return this.length;
}
filterByTotal(): void {
this.resetAllFilters();
this.activeFilter = 'total';
this.loadTraces();
}
filterByToday(): void {
this.resetAllFilters();
const todayString = this.datePipe.transform(new Date(), 'yyyy-MM-dd');
if (todayString) {
this.filters['executedAt[after]'] = todayString;
}
this.activeFilter = 'today';
this.loadTraces();
}
filterBySuccess(): void {
this.resetAllFilters();
this.filters['status'] = 'success';
this.activeFilter = 'success';
this.loadTraces();
}
filterByFailed(): void {
this.resetAllFilters();
this.filters['status'] = 'failed';
this.activeFilter = 'failed';
this.loadTraces();
}
filterByInProgress(): void {
this.resetAllFilters();
this.filters['status'] = 'in-progress';
this.activeFilter = 'in-progress';
this.loadTraces();
}
isFilterActive(filterType: string): boolean {
return this.activeFilter === filterType;
}
getActiveFilterLabel(): string {
switch(this.activeFilter) {
case 'total':
return 'Todas las trazas';
case 'today':
return 'Trazas de hoy';
case 'success':
return 'Trazas exitosas';
case 'failed':
return 'Trazas fallidas';
case 'in-progress':
return 'Trazas en progreso';
default:
return '';
}
}
private resetAllFilters(): void {
this.filters = {};
this.activeFilter = '';
}
}

View File

@ -42,7 +42,7 @@ export class HeaderComponent implements OnInit {
showGlobalStatus() {
this.dialog.open(GlobalStatusComponent, {
width: '5vw',
width: '65vw',
height: '80vh',
})
}