refs #1042 Advanced search size buttons
testing/ogGui-multibranch/pipeline/head This commit looks good Details

oggui/translations
Alvaro Puente Mella 2024-10-29 12:24:07 +01:00
commit 07ac93c4af
8 changed files with 174 additions and 121 deletions

View File

@ -27,6 +27,9 @@ import { RestoreImageComponent } from './components/groups/components/client-mai
import {SoftwareComponent} from "./components/software/software.component";
import {SoftwareProfileComponent} from "./components/software-profile/software-profile.component";
import {OperativeSystemComponent} from "./components/operative-system/operative-system.component";
import {
PartitionAssistantComponent
} from "./components/groups/components/client-main-view/partition-assistant/partition-assistant.component";
const routes: Routes = [
{ path: '', redirectTo: 'auth/login', pathMatch: 'full' },
{
@ -51,6 +54,7 @@ const routes: Routes = [
{ path: 'commands-logs', component: TaskLogsComponent },
{ path: 'calendars', component: CalendarComponent },
{ path: 'client/:id', component: ClientMainViewComponent },
{ path: 'client/:id/partition-assistant', component: PartitionAssistantComponent },
{ path: 'images', component: ImagesComponent },
{ path: 'restore-image', component: RestoreImageComponent},
{ path: 'software', component: SoftwareComponent },

View File

@ -169,13 +169,6 @@ mat-spinner {
width: 100%;
}
.results-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 16px;
margin-bottom: 16px;
}
.result-card {
width: 100%;
max-width: 250px;
@ -224,6 +217,7 @@ mat-spinner {
.result-clients {
font-size: 0.9rem;
color: #007bff;
color: #007bff;
margin: 5px 0;
}
@ -246,6 +240,7 @@ mat-card {
}
.red-card {
background-color: #f35f53;
background-color: #f35f53;
color: white;
}
@ -253,6 +248,8 @@ mat-card {
.green-card {
background-color: #4caf50;
color: white;
background-color: #4caf50;
color: white;
}
.view-mode-buttons button.active {
@ -274,6 +271,7 @@ mat-card {
}
.result-card-list .result-title {
font-size: 14px;
font-size: 14px;
font-weight: bold;
margin-right: 8px;
@ -284,10 +282,12 @@ mat-card {
flex-direction: row;
gap: 8px;
font-size: 12px;
font-size: 12px;
}
.result-card-list p {
margin: 0;
margin: 0;
}
.result-list {

View File

@ -205,3 +205,37 @@
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.circular-chart {
display: block;
margin: 0 auto;
max-width: 100%;
max-height: 150px;
}
.circle-bg {
fill: none;
stroke: #f0f0f0;
stroke-width: 3.8;
}
.circle {
fill: none;
stroke-width: 3.8;
stroke-linecap: round;
animation: progress 1s ease-out forwards;
}
/* Define colores distintos para cada partición */
.partition-0 { stroke: #00bfa5; } /* Ejemplo: verde */
.partition-1 { stroke: #ff6f61; } /* Ejemplo: rojo */
.partition-2 { stroke: #ffb400; } /* Ejemplo: amarillo */
.partition-3 { stroke: #3498db; } /* Ejemplo: azul */
/* Texto en el centro del gráfico */
.percentage {
fill: #333;
font-size: 0.7rem;
text-anchor: middle;
}

View File

@ -67,17 +67,20 @@
<div *ngFor="let disk of diskUsageData" class="disk-usage">
<h3>Disco {{ disk.diskNumber }}</h3>
<div class="chart">
<svg viewBox="0 0 36 36" class="circular-chart green">
<path class="circle-bg"
d="M18 2.0845
a 15.9155 15.9155 0 0 1 0 31.831
a 15.9155 15.9155 0 0 1 0 -31.831" />
<path class="circle"
[attr.stroke-dasharray]="disk.percentage + ', 100'"
d="M18 2.0845
a 15.9155 15.9155 0 0 1 0 31.831
a 15.9155 15.9155 0 0 1 0 -31.831" />
<text x="18" y="20.35" class="percentage">{{ disk.percentage }}%</text>
<svg viewBox="0 0 36 36" class="circular-chart">
<path
class="circle-bg"
d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
<ng-container *ngFor="let partition of disk.partitions; let i = index">
<path
class="circle partition-{{ i }}"
[attr.stroke-dasharray]="(partition.size / 1024).toFixed(2) + ', 100'"
[attr.stroke-dashoffset]="getStrokeOffset(disk.partitions, i)"
d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
</ng-container>
<text x="18" y="20.35" class="percentage">{{ (disk.used / disk.total * 100).toFixed(0) }}%</text>
</svg>
</div>
<p>Usado: {{ disk.used }} GB ({{ disk.percentage }}%)</p>
@ -86,4 +89,5 @@
</div>
</ng-container>
</div>
</div>

View File

@ -4,6 +4,7 @@ import {DatePipe} from "@angular/common";
import {MatTableDataSource} from "@angular/material/table";
import {PartitionAssistantComponent} from "./partition-assistant/partition-assistant.component";
import {MatDialog} from "@angular/material/dialog";
import {Router} from "@angular/router";
interface ClientInfo {
property: string;
@ -62,7 +63,11 @@ export class ClientMainViewComponent implements OnInit {
isDiskUsageEmpty: boolean = true;
loading: boolean = true;
constructor(private http: HttpClient, private dialog: MatDialog) {
constructor(
private http: HttpClient,
private dialog: MatDialog,
private router: Router
) {
const url = window.location.href;
const segments = url.split('/');
this.clientUuid = segments[segments.length - 1];
@ -105,12 +110,13 @@ export class ClientMainViewComponent implements OnInit {
}
calculateDiskUsage() {
const diskUsageMap = new Map<number, { total: number, used: number }>();
const diskUsageMap = new Map<number, { total: number, used: number, partitions: any[] }>();
this.partitions.forEach((partition: any) => {
const diskNumber = partition.diskNumber;
if (!diskUsageMap.has(diskNumber)) {
diskUsageMap.set(diskNumber, { total: 0, used: 0 });
diskUsageMap.set(diskNumber, { total: 0, used: 0, partitions: [] });
}
const diskData = diskUsageMap.get(diskNumber);
@ -118,17 +124,28 @@ export class ClientMainViewComponent implements OnInit {
if (partition.partitionNumber === 0) {
diskData!.total = Number((partition.size / 1024).toFixed(2));
} else {
diskData!.used += Number(((partition.size * (partition.memoryUsage / 100))/ 1024).toFixed(2));
diskData!.used += Number(((partition.size * (partition.memoryUsage / 100)) / 1024).toFixed(2));
diskData!.partitions.push(partition);
}
});
this.diskUsageData = Array.from(diskUsageMap.entries()).map(([diskNumber, { total, used }]) => {
this.diskUsageData = Array.from(diskUsageMap.entries()).map(([diskNumber, { total, used, partitions }]) => {
const percentage = total > 0 ? Math.round((used / total) * 100) : 0;
return { diskNumber, total, used, percentage };
return { diskNumber, total, used, percentage, partitions };
});
this.isDiskUsageEmpty = this.diskUsageData.length === 0;
}
getStrokeOffset(partitions: any[], index: number): number {
const totalSize = partitions.reduce((acc, part) => acc + (part.size / 1024), 0);
const offset = partitions.slice(0, index).reduce((acc, part) => acc + (part.size / 1024), 0);
console.log(offset, totalSize)
return totalSize > 0 ? (offset / totalSize) : 0;
}
loadPartitions(): void {
this.http.get<any>(`${this.baseUrl}/partitions?client.id=${this.clientData?.id}`).subscribe({
next: data => {
@ -155,18 +172,14 @@ export class ClientMainViewComponent implements OnInit {
onCommandSelect(command: any): void {
if (command.name === 'Particionar y Formatear') {
this.openPartitionDialog();
this.openPartitionAssistant();
}
}
openPartitionDialog(): void {
const dialogRef = this.dialog.open(PartitionAssistantComponent, {
width: '1000px',
data: this.clientData['@id']
});
dialogRef.afterClosed().subscribe((result: any) => {
console.log('El diálogo se cerró', result);
openPartitionAssistant(): void {
console.log(this.clientData)
this.router.navigate([`/client/${this.clientData.uuid}/partition-assistant`]).then(r => {
console.log('navigated', r);
});
}
}

View File

@ -5,20 +5,12 @@
margin: 20px auto;
}
.header {
.header-container {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 15px;
align-items: center;
height: 100px;
padding: 10px;
background-color: #cecbcb;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.header label {
font-weight: 500;
margin-right: 10px;
}
.disk-size {
@ -44,6 +36,11 @@
font-weight: 500;
font-size: 0.9rem;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);
border-right: 2px solid white; /* Borde de separación */
}
.partition-segment:last-child {
border-right: none;
}
.partition-table {

View File

@ -1,73 +1,72 @@
<h2 mat-dialog-title>Asistente de particionado</h2>
<mat-dialog-content>
<div class="partition-assistant" *ngFor="let disk of disks; let i = index">
<div class="header">
<label for="disk-number-{{i}}">Disco {{ disk.diskNumber }}:</label>
<span class="disk-size">Tamaño: {{ (disk.totalDiskSize / 1024).toFixed(2) }} GB</span>
</div>
<div class="partition-bar">
<div
*ngFor="let partition of disk.partitions"
[ngStyle]="{'width': partition.percentage + '%', 'background-color': partition.color}"
class="partition-segment"
>
{{ partition.type }} ({{ (partition.size / 1024).toFixed(2) }} GB)
</div>
</div>
<button mat-flat-button color="primary" (click)="addPartition(disk.diskNumber)"> + </button>
<table class="partition-table">
<thead>
<tr>
<th>Partición</th>
<th>Tipo partición</th>
<th>Tamaño (MB)</th>
<th>Uso (%)</th>
<th>Formatear</th>
<th>Eliminar</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let partition of disk.partitions; let j = index">
<td>{{ partition.partitionNumber }}</td>
<td>
<select [(ngModel)]="partition.type">
<option value="NTFS">NTFS</option>
<option value="LINUX">LINUX</option>
<option value="CACHE">CACHE</option>
</select>
</td>
<td>
<input
type="number"
[(ngModel)]="partition.size"
(input)="updatePartitionSize(disk.diskNumber, j, partition.size)"
/>
</td>
<td>
<input
type="number"
[(ngModel)]="partition.memoryUsage"
/>
</td>
<td>
<input type="checkbox" [(ngModel)]="partition.format" />
</td>
<td>
<button (click)="removePartition(disk.diskNumber, partition)" class="remove-btn">X</button>
</td>
</tr>
</tbody>
</table>
<div class="header-container">
<h2 class="title" i18n="@@subnetsTitle">Asistente de particionado</h2>
<div class="subnets-button-row">
<button mat-flat-button color="primary" (click)="save()">Guardar</button>
</div>
</mat-dialog-content>
</div>
<mat-divider></mat-divider>
<div class="partition-assistant" *ngFor="let disk of disks; let i = index">
<div>
<label for="disk-number-{{i}}">Disco {{ disk.diskNumber }}:</label>
<span class="disk-size"> Tamaño: {{ (disk.totalDiskSize / 1024).toFixed(2) }} GB</span>
</div>
<div class="partition-bar">
<div
*ngFor="let partition of disk.partitions"
[ngStyle]="{'width': partition.percentage + '%', 'background-color': partition.color}"
class="partition-segment"
>
{{ partition.type }} ({{ (partition.size / 1024).toFixed(2) }} GB)
</div>
</div>
<button mat-flat-button color="primary" (click)="addPartition(disk.diskNumber)"> + </button>
<table class="partition-table">
<thead>
<tr>
<th>Partición</th>
<th>Tipo partición</th>
<th>Tamaño (MB)</th>
<th>Uso (%)</th>
<th>Formatear</th>
<th>Eliminar</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let partition of disk.partitions; let j = index">
<td>{{ partition.partitionNumber }}</td>
<td>
<select [(ngModel)]="partition.type">
<option value="NTFS">NTFS</option>
<option value="LINUX">LINUX</option>
<option value="CACHE">CACHE</option>
</select>
</td>
<td>
<input
type="number"
[(ngModel)]="partition.size"
(input)="updatePartitionSize(disk.diskNumber, j, partition.size)"
/>
</td>
<td>
<input
type="number"
[(ngModel)]="partition.memoryUsage"
/>
</td>
<td>
<input type="checkbox" [(ngModel)]="partition.format" />
</td>
<td>
<button (click)="removePartition(disk.diskNumber, partition)" class="remove-btn">X</button>
</td>
</tr>
</tbody>
</table>
</div>
<div *ngIf="errorMessage" class="error-message">{{ errorMessage }}</div>
<mat-dialog-actions align="end">
<button mat-button (click)="save()">Guardar</button>
</mat-dialog-actions>

View File

@ -2,6 +2,7 @@ import {Component, EventEmitter, Inject, Input, OnInit, Output} from '@angular/c
import { HttpClient } from '@angular/common/http';
import { ToastrService } from 'ngx-toastr';
import {MAT_DIALOG_DATA} from "@angular/material/dialog";
import {ActivatedRoute} from "@angular/router";
interface Partition {
uuid?: string;
@ -26,6 +27,8 @@ export class PartitionAssistantComponent implements OnInit {
errorMessage = '';
originalPartitions: any[] = [];
clientId: string | null = null;
data: any = {};
disks: { diskNumber: number; totalDiskSize: number; partitions: Partition[] }[] = [];
private apiUrl: string = this.baseUrl + '/partitions';
@ -33,15 +36,17 @@ export class PartitionAssistantComponent implements OnInit {
constructor(
private http: HttpClient,
private toastService: ToastrService,
@Inject(MAT_DIALOG_DATA) public data: any
private route: ActivatedRoute
) {}
ngOnInit() {
this.clientId = this.route.snapshot.paramMap.get('id');
this.loadPartitions();
}
loadPartitions() {
const url = `${this.baseUrl}${this.data}`;
const url = `${this.baseUrl}/clients/${this.clientId}`;
this.http.get(url).subscribe(
(response) => {
this.data = response;
@ -76,7 +81,7 @@ export class PartitionAssistantComponent implements OnInit {
type: partition.type || partition.filesystem || 'NTFS',
sizeBytes: partition.size,
format: false,
color: '#' + Math.floor(Math.random() * 16777215).toString(16),
color: '#1f1b91',
percentage: 0
});
}
@ -216,14 +221,13 @@ export class PartitionAssistantComponent implements OnInit {
memoryUsage: partition.memoryUsage,
size: partition.size,
filesystem: partition.type,
client: this.data['@id']
client: `/clients/${this.clientId}`
};
if (isNew) {
this.http.post(this.apiUrl, payload).subscribe(
(response) => {
this.toastService.success('Partición creada exitosamente');
this.loadPartitions();
},
(error) => {
console.error('Error al crear la partición:', error);
@ -235,7 +239,6 @@ export class PartitionAssistantComponent implements OnInit {
this.http.patch(patchUrl, payload).subscribe(
(response) => {
this.toastService.success('Partición actualizada exitosamente');
this.loadPartitions();
},
(error) => {
console.error('Error al actualizar la partición:', error);
@ -261,7 +264,6 @@ export class PartitionAssistantComponent implements OnInit {
this.http.delete(deleteUrl).subscribe(
(response) => {
this.toastService.success('Partición eliminada exitosamente');
this.loadPartitions();
},
(error) => {}
);