New client option. Disk logs. #87

Merged
maranda merged 2 commits from develop into main 2026-05-05 18:21:08 +02:00
9 changed files with 235 additions and 0 deletions

View File

@ -185,6 +185,7 @@ import { ScrollToTopComponent } from './shared/scroll-to-top/scroll-to-top.compo
import { CreateTagModalComponent } from './components/repositories/show-git-images/create-tag-modal/create-tag-modal.component';
import { CreateBranchModalComponent } from './components/repositories/show-git-images/create-branch-modal/create-branch-modal.component';
import { ClientLogsModalComponent } from './components/groups/shared/client-logs-modal/client-logs-modal.component';
import { ClientDiskLogsModalComponent } from './components/groups/shared/client-disk-logs-modal/client-disk-logs-modal.component';
import { BackupRepositoryModalComponent } from './components/repositories/show-git-images/backup-repository-modal/backup-repository-modal.component';
import { HardwareComponent } from './components/hardware/hardware.component';
import { CreateHardwareComponent } from './components/hardware/create-hardware/create-hardware.component';
@ -325,6 +326,7 @@ registerLocaleData(localeEs, 'es-ES');
CreateTagModalComponent,
CreateBranchModalComponent,
ClientLogsModalComponent,
ClientDiskLogsModalComponent,
SafePipe,
BackupRepositoryModalComponent,
HardwareComponent,

View File

@ -458,6 +458,10 @@
<mat-icon>analytics</mat-icon>
<span>{{ 'clientLogs' | translate }}</span>
</button>
<button mat-menu-item (click)="openClientDiskLogsModal($event, client)">
<mat-icon>storage</mat-icon>
<span>{{ 'diskLogs' | translate }}</span>
</button>
<button mat-menu-item (click)="onDeleteClick($event, client)" *ngIf="auth.userCategory !== 'ou-minimal'">
<mat-icon>delete</mat-icon>
<span>{{ 'buttonDelete' | translate }}</span>
@ -653,6 +657,10 @@
<mat-icon>analytics</mat-icon>
<span>{{ 'clientLogs' | translate }}</span>
</button>
<button mat-menu-item (click)="openClientDiskLogsModal($event, client)">
<mat-icon>storage</mat-icon>
<span>{{ 'diskLogs' | translate }}</span>
</button>
<button mat-menu-item (click)="onDeleteClick($event, client)" *ngIf="auth.userCategory !== 'ou-minimal'">
<mat-icon>delete</mat-icon>
<span>{{ 'buttonDelete' | translate }}</span>

View File

@ -34,6 +34,7 @@ import {ChangeParentComponent} from "./shared/change-parent/change-parent.compon
import { AuthService } from '@services/auth.service';
import { ClientPendingTasksComponent } from '../task-logs/client-pending-tasks/client-pending-tasks.component';
import { ClientLogsModalComponent } from './shared/client-logs-modal/client-logs-modal.component';
import { ClientDiskLogsModalComponent } from './shared/client-disk-logs-modal/client-disk-logs-modal.component';
import { DeleteResultsModalComponent } from './shared/delete-results-modal/delete-results-modal.component';
enum NodeType {
@ -1085,6 +1086,19 @@ export class GroupsComponent implements OnInit, OnDestroy {
});
}
openClientDiskLogsModal(event: MouseEvent, client: Client): void {
event.stopPropagation();
this.dialog.open(ClientDiskLogsModalComponent, {
width: '1100px',
height: '80vh',
data: { client },
disableClose: false,
hasBackdrop: true,
backdropClass: 'non-clickable-backdrop',
});
}
openOUPendingTasks(event: MouseEvent, node: any): void {
event.stopPropagation();
this.loading = true;

View File

@ -0,0 +1,116 @@
.disk-logs-modal {
display: flex;
flex-direction: column;
height: 100%;
max-height: 90vh;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 24px;
border-bottom: 1px solid #e0e0e0;
background-color: #fafafa;
}
.modal-header h2 {
margin: 0;
display: flex;
align-items: center;
gap: 8px;
font-size: 1.25rem;
color: #333;
}
.header-actions {
display: flex;
gap: 8px;
}
.modal-content {
flex: 1;
padding: 24px;
overflow: hidden;
display: flex;
flex-direction: column;
min-height: 0;
}
.client-info {
margin-bottom: 16px;
padding: 12px;
background-color: #f5f5f5;
border-radius: 4px;
border-left: 4px solid #2196f3;
flex-shrink: 0;
}
.client-info p {
margin: 4px 0;
font-size: 0.9rem;
}
.client-info strong {
color: #333;
}
.log-container {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
border: 1px solid #e0e0e0;
border-radius: 4px;
background-color: #1e1e1e;
overflow: hidden;
}
.log-loading,
.log-error {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
flex: 1;
color: #aaa;
padding: 32px;
}
.log-error {
color: #f44336;
}
.log-content {
flex: 1;
margin: 0;
padding: 16px;
overflow: auto;
font-family: 'Courier New', Courier, monospace;
font-size: 0.82rem;
line-height: 1.5;
color: #d4d4d4;
background-color: transparent;
white-space: pre-wrap;
word-break: break-all;
}
.modal-actions {
padding: 16px 24px;
border-top: 1px solid #e0e0e0;
display: flex;
justify-content: flex-end;
background-color: #fafafa;
}
.action-button {
border-radius: 8px;
font-weight: 500;
padding: 12px 24px;
transition: all 0.3s ease;
}
.action-button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

View File

@ -0,0 +1,39 @@
<div class="disk-logs-modal">
<div class="modal-header">
<h2 mat-dialog-title>
<mat-icon>storage</mat-icon>
{{ 'diskLogs' | translate }} - {{ data.client.name }}
</h2>
<div class="header-actions">
<button mat-icon-button (click)="loadLogs()" [matTooltip]="'buttonRefresh' | translate" [disabled]="loading">
<mat-icon>refresh</mat-icon>
</button>
</div>
</div>
<div class="modal-content">
<div class="client-info">
<p><strong>{{ 'labelClient' | translate }}</strong> {{ data.client.name }}</p>
<p><strong>{{ 'labelIpColon' | translate }}</strong> {{ data.client.ip }}</p>
</div>
<div class="log-container">
<div *ngIf="loading" class="log-loading">
<mat-spinner diameter="40"></mat-spinner>
</div>
<div *ngIf="error && !loading" class="log-error">
<mat-icon>error_outline</mat-icon>
<span>{{ error }}</span>
</div>
<pre *ngIf="!loading && !error" class="log-content">{{ content || ('noLogsAvailable' | translate) }}</pre>
</div>
</div>
<div class="modal-actions">
<button class="action-button" (click)="closeModal()">
{{ 'buttonClose' | translate }}
</button>
</div>
</div>

View File

@ -0,0 +1,53 @@
import { Component, Inject, OnInit, OnDestroy } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { HttpClient } from '@angular/common/http';
import { ConfigService } from '@services/config.service';
@Component({
selector: 'app-client-disk-logs-modal',
templateUrl: './client-disk-logs-modal.component.html',
styleUrls: ['./client-disk-logs-modal.component.css']
})
export class ClientDiskLogsModalComponent implements OnInit, OnDestroy {
content: string = '';
loading: boolean = false;
error: string | null = null;
private apiUrl: string;
constructor(
public dialogRef: MatDialogRef<ClientDiskLogsModalComponent>,
@Inject(MAT_DIALOG_DATA) public data: { client: any },
private http: HttpClient,
private configService: ConfigService,
) {
this.apiUrl = this.configService.apiUrl;
}
ngOnInit(): void {
this.loadLogs();
}
ngOnDestroy(): void {}
loadLogs(): void {
this.loading = true;
this.error = null;
this.http.get<{ content: string }>(`${this.apiUrl}/clients/${this.data.client.uuid}/disk-logs`).subscribe({
next: (response) => {
this.content = response.content || '';
this.loading = false;
},
error: (err) => {
this.error = err.status === 404
? 'No se encontró el archivo de logs para este cliente.'
: 'Error al obtener los logs de disco.';
this.loading = false;
}
});
}
closeModal(): void {
this.dialogRef.close();
}
}

View File

@ -231,6 +231,7 @@
"clientListExecuteScript": "Llistat de clients on s'executarà l'script seleccionat",
"clientListPartition": "Llistat de clients on es realitzarà el particionat",
"clientLogs": "Registres de client",
"diskLogs": "Registres de disc",
"clientMacOS": "Client MacOS",
"clientOff": "Client apagat",
"clientOgLive": "Client OGLive",

View File

@ -231,6 +231,7 @@
"clientListExecuteScript": "List of clients where the selected script will be executed",
"clientListPartition": "List of clients where partitioning will be performed",
"clientLogs": "Client Logs",
"diskLogs": "Disk Logs",
"clientMacOS": "MacOS client",
"clientOff": "Client off",
"clientOgLive": "OGLive client",

View File

@ -231,6 +231,7 @@
"clientListExecuteScript": "Listado de clientes donde se ejecutara el script seleccionado",
"clientListPartition": "Listado de clientes donde se realizará el particionado",
"clientLogs": "Logs de cliente",
"diskLogs": "Logs de disco",
"clientMacOS": "Cliente MacOS",
"clientOff": "Cliente apagado",
"clientOgLive": "Cliente OGLive",