refs #1042 Advanced search size buttons
testing/ogGui-multibranch/pipeline/head This commit looks good
Details
testing/ogGui-multibranch/pipeline/head This commit looks good
Details
commit
07ac93c4af
|
@ -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 },
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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) => {}
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue