Merge pull request 'Rediseño de ventana de detalles de equipo, la partición cache muestra los ficheros que contiene' (#60) from cache-content into main
oggui-debian-package/pipeline/head This commit looks good Details
testing/ogGui-multibranch/pipeline/head There was a failure building this commit Details

Reviewed-on: #60
pull/61/head 1.2.6
Juan Manuel Bardallo 2026-03-30 12:00:28 +02:00
commit 208d89d589
4 changed files with 215 additions and 56 deletions

View File

@ -1,4 +1,8 @@
# Changelog
## [1.2.6] - 2026-03-30
### Added
- Rediseño de la pantalla detalles de un equipo, en la partición CACHE, se muestra el listado de ficheros que contiene con el tamaño de cada uno.
## [1.2.5] - 2026-03-27
### Fixed
- Corregido error 401 Unauthorized en la edición de menús con nombres que contienen la palabra "login". Se ha refinado el interceptor para aplicar el prefijo "Bearer" de forma selectiva mediante validación exacta del path `/auth/login`.

View File

@ -130,3 +130,114 @@ table {
gap: 1em;
margin-bottom: 40px;
}
/* ngx-charts custom wrapped legend */
::ng-deep .charts-container .legend-labels {
display: flex !important;
flex-wrap: wrap !important;
justify-content: center !important;
}
::ng-deep .charts-container .legend-label {
width: auto !important;
margin-right: 16px !important;
margin-bottom: 8px !important;
}
::ng-deep .charts-container .legend-label-text {
max-width: none !important;
overflow: visible !important;
text-overflow: clip !important;
}
::ng-deep .charts-container .legend-wrap {
width: 100% !important;
}
/* Extracted Card Redesign Classes */
.disk-card-wrapper {
margin-bottom: 50px;
}
.disk-mat-card {
border-radius: 8px;
overflow: visible !important;
padding: 0;
}
.disk-card-header {
background-color: #f5f5f5;
padding: 16px 20px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #e0e0e0;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.disk-card-title {
margin: 0;
font-size: 1.2rem;
color: #3f51b5;
font-weight: bold;
}
.disk-card-metrics-wrapper {
display: flex;
align-items: center;
}
.disk-card-metrics-chip {
background-color: white !important;
border: 1px solid #ccc;
font-weight: bold;
color: #333;
}
.disk-card-layout {
display: flex;
align-items: stretch;
background: white;
gap: 0;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
.disk-table-container {
flex: 1;
overflow-x: auto;
}
.disk-table {
width: 100%;
box-shadow: none !important;
border: none !important;
}
.disk-chart-container {
flex: 0 0 400px;
border-left: 1px solid #e0e0e0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
padding: 30px 20px 50px 20px;
box-sizing: border-box;
background: #fafafa;
min-height: 350px;
border-bottom-right-radius: 8px;
}
.disk-chart-wrapper {
width: 100%;
height: auto;
display: flex;
justify-content: center;
}
/* OS Column Classes */
.os-col-wrapper {
display: flex;
flex-direction: column;
}
.cache-title {
font-weight: bold;
font-size: 0.8rem;
color: #666;
}
.cache-item {
font-size: 0.75rem;
color: #666;
}
.image-name {
font-size: 0.75rem;
color: gray;
}

View File

@ -1,7 +1,8 @@
<mat-dialog-content class="modal-content">
<app-loading [isLoading]="loading"></app-loading>
<div class="client-container" *ngIf="!loading">
@if (!loading) {
<div class="client-container">
<div class="header-container">
<h2 class="title">{{ 'clientDetailsTitle' | translate }} {{ clientData.name }}</h2>
</div>
@ -9,75 +10,112 @@
<div class="client-info-card">
<div class="info-columns">
<div class="info-column">
<div class="info-pair" *ngFor="let data of generalData">
@for (data of generalData; track data) {
<div class="info-pair">
<div class="label">{{ data?.property }}</div>
<div class="value">{{ data?.value || '--' }}</div>
</div>
}
</div>
<div class="info-column">
<div class="info-pair" *ngFor="let data of networkData">
@for (data of networkData; track data) {
<div class="info-pair">
<div class="label">{{ data?.property }}</div>
<div class="value">{{ data?.value || '--' }}</div>
</div>
}
</div>
</div>
</div>
<div class="table-header-container">
<h2 i18n="@@adminImagesTitle">Discos/Particiones</h2>
<mat-chip *ngIf="clientData.firmwareType"> {{ clientData.firmwareType }}</mat-chip>
@if (clientData.firmwareType) {
<mat-chip> {{ clientData.firmwareType }}</mat-chip>
}
</div>
<div class="disk-container">
<div class="disk-layout">
<div class="table-container">
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<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 !== 'size' && column.columnDef !== 'operativeSystem'">
{{ column.cell(image) }}
</ng-container>
<ng-container *ngIf="column.columnDef === 'size'">
<mat-chip color="primary">
{{ (image.size / 1024).toFixed(2) }} GB
</mat-chip>
</ng-container>
<ng-container *ngIf="column.columnDef === 'operativeSystem'">
<div style="display: flex; flex-direction: column;">
<span>{{image.operativeSystem?.name }}</span>
<span style="font-size: 0.75rem; color: gray;">{{ image.image?.name }}</span>
</div>
</ng-container>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [hidden]="row.partitionNumber === 0"></tr>
</ng-container>
</table>
</div>
<div class="charts-container" [ngClass]="{'single-disk': chartDisk.length === 1}">
<ng-container *ngIf="diskUsageData && diskUsageData.length > 0">
<div *ngFor="let disk of chartDisk" class="disk-usage">
<ngx-charts-pie-chart class="chart" [view]="view" [results]="disk.chartData" [doughnut]="true">
</ngx-charts-pie-chart>
<h3>Disco {{ disk.diskNumber }}</h3>
<p>Usado: {{ (disk.used).toFixed(2) }} GB ({{ disk.percentage }}%)</p>
<p>Total: {{ disk.total }} GB</p>
@for (disk of diskUsageData; track disk.diskNumber) {
<div class="disk-card-wrapper">
<mat-card class="disk-mat-card mat-elevation-z4">
<div class="disk-card-header">
<h3 class="disk-card-title">Disco {{ disk.diskNumber }}</h3>
<div class="disk-card-metrics-wrapper">
<mat-chip class="disk-card-metrics-chip">
Total: {{ disk.total.toFixed(2) }} GB &nbsp;|&nbsp; Usado: {{ (disk.used).toFixed(2) }} GB ({{ disk.percentage }}%)
</mat-chip>
</div>
</ng-container>
</div>
<div class="disk-card-layout">
<div class="disk-table-container">
<table mat-table [dataSource]="disk.partitions" class="disk-table">
@for (column of columns; track column.columnDef) {
<ng-container [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
<td mat-cell *matCellDef="let image">
@if (column.columnDef !== 'size' && column.columnDef !== 'operativeSystem') {
{{ column.cell(image) }}
}
@if (column.columnDef === 'size') {
<mat-chip color="primary">
{{ (image.size / 1024).toFixed(2) }} GB
</mat-chip>
}
@if (column.columnDef === 'operativeSystem') {
<div class="os-col-wrapper">
@if (image.filesystem === 'CACHE' && image.cacheContent) {
<span class="cache-title">Contenido:</span>
@for (item of parseCacheContent(image.cacheContent); track item.name) {
<div class="cache-item">
• {{ item.name }} ({{ item.size }})
</div>
}
}
@if (image.filesystem !== 'CACHE' || !image.cacheContent) {
<span>{{image.operativeSystem?.name }}</span>
<span class="image-name">{{ image.image?.name }}</span>
}
</div>
}
</td>
</ng-container>
}
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [hidden]="row.partitionNumber === 0"></tr>
</ng-container>
</table>
</div>
<div class="charts-container disk-chart-container">
<div class="disk-chart-wrapper">
<ngx-charts-pie-chart
class="chart"
[view]="[360, 230]"
[results]="disk.chartData"
[doughnut]="true"
[legend]="true"
[legendPosition]="legendPosition"
[legendTitle]="''">
</ngx-charts-pie-chart>
</div>
</div>
</div>
</mat-card>
</div>
}
</div>
</div>
}
</mat-dialog-content>
<mat-dialog-actions class="action-container">
<button class="ordinary-button" (click)="onNoClick()">{{ 'closeButton' | translate }}</button>
</mat-dialog-actions>
</mat-dialog-actions>

View File

@ -37,18 +37,14 @@ export class ClientDetailsComponent {
chartDisk: any[] = [];
view: [number, number] = [260, 160];
showLegend: boolean = true;
legendPosition: any = 'below';
datePipe: DatePipe = new DatePipe('es-ES');
columns = [
{
columnDef: 'diskNumber',
header: 'Disco',
cell: (partition: any) => partition.diskNumber,
},
{
columnDef: 'partitionNumber',
header: 'Particion',
cell: (partition: any) => partition.partitionNumber
columnDef: 'partition',
header: 'Partición',
cell: (partition: any) => `${partition.partitionNumber}`
},
{
columnDef: 'partitionCode',
@ -168,7 +164,8 @@ export class ClientDetailsComponent {
chartData: partitionData,
total,
used,
percentage: total > 0 ? Math.round((used / total) * 100) : 0
percentage: total > 0 ? Math.round((used / total) * 100) : 0,
partitions
};
});
@ -194,6 +191,15 @@ export class ClientDetailsComponent {
});
}
parseCacheContent(content: string): { name: string, size: string }[] {
if (!content) return [];
return content.split(',').map(item => {
const [name, bytes] = item.split(':');
const sizeMB = (parseInt(bytes) / (1024 * 1024)).toFixed(2) + ' MB';
return { name, size: sizeMB };
});
}
onNoClick(): void {
this.dialog.closeAll();
}