refs #918 update client-main-view component
parent
0276c92680
commit
33525f1163
|
@ -89,7 +89,6 @@ import { CalendarComponent } from './components/calendar/calendar.component';
|
|||
import { CreateCalendarComponent } from './components/calendar/create-calendar/create-calendar.component';
|
||||
import {MatRadioButton, MatRadioGroup} from "@angular/material/radio";
|
||||
import { CreateCalendarRuleComponent } from './components/calendar/create-calendar-rule/create-calendar-rule.component';
|
||||
|
||||
import { CommandsGroupsComponent } from './components/commands/commands-groups/commands-groups.component';
|
||||
import { CommandsTaskComponent } from './components/commands/commands-task/commands-task.component';
|
||||
import { CreateCommandGroupComponent } from './components/commands/commands-groups/create-command-group/create-command-group.component';
|
||||
|
@ -106,6 +105,7 @@ import {MatSliderModule} from '@angular/material/slider';
|
|||
import { ClientMainViewComponent } from './components/groups/components/client-main-view/client-main-view.component';
|
||||
import { ImagesComponent } from './components/images/images.component';
|
||||
import { CreateImageComponent } from './components/images/create-image/create-image.component';
|
||||
import { PartitionAssistantComponent } from './components/groups/components/client-main-view/partition-assistant/partition-assistant.component';
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
|
@ -167,7 +167,8 @@ import { CreateImageComponent } from './components/images/create-image/create-im
|
|||
StatusComponent,
|
||||
ClientMainViewComponent,
|
||||
ImagesComponent,
|
||||
CreateImageComponent
|
||||
CreateImageComponent,
|
||||
PartitionAssistantComponent,
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
imports: [BrowserModule,
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
<div class="header-container">
|
||||
<h2 class="title">Asistente de Particionado de Disco</h2>
|
||||
</div>
|
||||
<mat-divider class="divider"></mat-divider>
|
||||
|
||||
<!-- Lista de particiones añadidas -->
|
||||
<h3>Particiones actuales</h3>
|
||||
<mat-list>
|
||||
<mat-list-item *ngFor="let partition of partitions">
|
||||
{{ partition.name }} - {{ partition.size }} GB - {{ partition.type }}
|
||||
<button mat-icon-button color="warn" (click)="removePartition(partition)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
|
||||
<!-- Añadir nueva partición -->
|
||||
<h3>Añadir Partición</h3>
|
||||
<div class="partition-form">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Nombre</mat-label>
|
||||
<input matInput placeholder="Nombre de la partición" [(ngModel)]="newPartition.name">
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Tamaño (GB)</mat-label>
|
||||
<input matInput type="number" placeholder="Tamaño" [(ngModel)]="newPartition.size">
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Tipo</mat-label>
|
||||
<mat-select [(ngModel)]="newPartition.type">
|
||||
<mat-option *ngFor="let type of partitionTypes" [value]="type">{{ type }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Nuevo campo para seleccionar imagen -->
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Imagen</mat-label>
|
||||
<mat-select [(ngModel)]="selectedImageUuid">
|
||||
<mat-option *ngFor="let image of images" [value]="image.uuid">
|
||||
{{ image.name }} - {{ image.description }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Botón para añadir partición -->
|
||||
<button mat-raised-button color="primary" (click)="addPartition()">Añadir Partición</button>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
|
||||
interface ClientInfo {
|
||||
name: string;
|
||||
type: string;
|
||||
ip: string;
|
||||
mac: string;
|
||||
serialNumber: string;
|
||||
netiface: string;
|
||||
netDriver: string;
|
||||
}
|
||||
|
||||
interface Partition {
|
||||
name: string;
|
||||
size: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface Disk {
|
||||
name: string;
|
||||
size: number;
|
||||
}
|
||||
|
||||
interface ImageData {
|
||||
name: string;
|
||||
uuid: string; // Usaremos el UUID como valor
|
||||
description: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-partition-assistant',
|
||||
templateUrl: './partition-assistant.component.html',
|
||||
styleUrls: ['./partition-assistant.component.css']
|
||||
})
|
||||
export class PartitionAssistantComponent implements OnInit {
|
||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||
|
||||
@Input() clientUuid!: string;
|
||||
clientInfo: ClientInfo | undefined;
|
||||
availableDisks: Disk[] = [];
|
||||
selectedDisk: Disk | undefined;
|
||||
partitions: Partition[] = [];
|
||||
images: ImageData[] = []; // Lista para almacenar las imágenes cargadas
|
||||
selectedImageUuid: string = ''; // Variable para almacenar la imagen seleccionada
|
||||
|
||||
newPartition: Partition = { name: '', size: 0, type: '' };
|
||||
partitionTypes: string[] = ['NTFS', 'FAT32', 'EXT4'];
|
||||
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
private toastService: ToastrService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.clientUuid) {
|
||||
this.getClientInfo(this.clientUuid);
|
||||
} else {
|
||||
console.error('No client UUID provided!');
|
||||
}
|
||||
|
||||
// Llamada a la API para obtener las imágenes
|
||||
this.getImages();
|
||||
}
|
||||
|
||||
getClientInfo(uuid: string): void {
|
||||
this.http.get<ClientInfo>(`${this.baseUrl}/clients/${uuid}`)
|
||||
.subscribe(
|
||||
(response: ClientInfo) => {
|
||||
this.clientInfo = response;
|
||||
console.log('Client info:', this.clientInfo);
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching client info:', error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Método para obtener las imágenes desde la API
|
||||
getImages(): void {
|
||||
this.http.get<any>('http://127.0.0.1:8001/images?page=1&itemsPerPage=30')
|
||||
.subscribe(
|
||||
(response) => {
|
||||
this.images = response['hydra:member'];
|
||||
console.log('Images loaded:', this.images);
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching images:', error);
|
||||
this.toastService.error('Error al cargar las imágenes.');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
addPartition(): void {
|
||||
if (this.newPartition.name && this.newPartition.size > 0 && this.newPartition.type) {
|
||||
// Añadir la partición solo si todos los campos son válidos
|
||||
this.partitions.push({ ...this.newPartition });
|
||||
this.newPartition = { name: '', size: 0, type: '' };
|
||||
} else {
|
||||
this.toastService.error('Por favor, complete todos los campos correctamente.');
|
||||
}
|
||||
}
|
||||
|
||||
removePartition(partition: Partition): void {
|
||||
this.partitions = this.partitions.filter(p => p !== partition);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
.client-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 40px;
|
||||
margin-bottom: 10px;
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
|
@ -41,7 +41,7 @@
|
|||
.client-info {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 40px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.info-section {
|
||||
|
@ -103,12 +103,18 @@
|
|||
text-anchor: middle;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.client-footer {
|
||||
margin-top: 40px;
|
||||
text-align: center;
|
||||
font-size: 1rem;
|
||||
color: #555;
|
||||
.assistants-container{
|
||||
background-color: #fff;
|
||||
margin-top: 10px;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.buttons-row{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@keyframes progress {
|
||||
|
@ -116,4 +122,3 @@
|
|||
stroke-dasharray: 0, 100;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,26 +5,30 @@
|
|||
<div class="client-title">
|
||||
<h1>{{ clientData?.name }}</h1>
|
||||
<p><strong>UUID:</strong> {{ clientData?.uuid }}</p>
|
||||
<p><strong>IP Address:</strong> {{ clientData?.ip }}</p>
|
||||
<p><strong>IP:</strong> {{ clientData?.ip }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="client-info">
|
||||
<!-- General Information -->
|
||||
<!-- Información General -->
|
||||
<div class="info-section">
|
||||
<h2>General Information</h2>
|
||||
<p><strong>Type:</strong> {{ clientData?.type }}</p>
|
||||
<p><strong>MAC Address:</strong> {{ clientData?.mac }}</p>
|
||||
<p><strong>Serial Number:</strong> {{ clientData?.serialNumber }}</p>
|
||||
<h2>Organizational Unit</h2>
|
||||
<p><strong>Name:</strong> {{ clientData?.organizationalUnit?.name }}</p>
|
||||
<p><strong>Type:</strong> {{ clientData?.organizationalUnit?.type }}</p>
|
||||
<button mat-icon-button (click)="toggleGeneralInfo()" aria-label="Minimizar/Expandir información general">
|
||||
<mat-icon>{{ isGeneralInfoVisible ? 'expand_less' : 'expand_more' }}</mat-icon>
|
||||
</button>
|
||||
<h2 *ngIf="isGeneralInfoVisible">Información General</h2>
|
||||
<p *ngIf="isGeneralInfoVisible"><strong>MAC:</strong> {{ clientData?.mac }}</p>
|
||||
<p *ngIf="isGeneralInfoVisible"><strong>Número de serie:</strong> {{ clientData?.serialNumber }}</p>
|
||||
<h2 *ngIf="isGeneralInfoVisible">Unidad Organizativa</h2>
|
||||
<p *ngIf="isGeneralInfoVisible">{{ clientData?.organizationalUnit?.name }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Disk Space Usage -->
|
||||
<!-- Uso del Espacio en Disco -->
|
||||
<div class="info-section">
|
||||
<h2>Disk Space</h2>
|
||||
<div class="disk-usage">
|
||||
<button mat-icon-button (click)="toggleDiskUsage()" aria-label="Minimizar/Expandir uso de disco">
|
||||
<mat-icon>{{ isDiskUsageVisible ? 'expand_less' : 'expand_more' }}</mat-icon>
|
||||
</button>
|
||||
<h2 *ngIf="isDiskUsageVisible">Disco</h2>
|
||||
<div class="disk-usage" *ngIf="isDiskUsageVisible">
|
||||
<div class="chart-container">
|
||||
<svg viewBox="0 0 36 36" class="circular-chart green">
|
||||
<path class="circle-bg"
|
||||
|
@ -39,9 +43,17 @@
|
|||
<text x="18" y="20.35" class="percentage">75%</text>
|
||||
</svg>
|
||||
</div>
|
||||
<p>Used: 75% (375GB)</p>
|
||||
<p>Usado: 75% (375GB)</p>
|
||||
<p>Total: 500GB</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="buttons-row">
|
||||
<button mat-flat-button color="primary" (click)="togglePartitionAssistant()">Asistente a particionado</button>
|
||||
<button mat-flat-button color="primary" (click)="showBootImage()">Asignar imagen de arranque</button>
|
||||
</div>
|
||||
|
||||
<div class="assistants-container" *ngIf="isPartitionAssistantVisible">
|
||||
<app-partition-assistant></app-partition-assistant>
|
||||
</div>
|
|
@ -1,23 +0,0 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ClientMainViewComponent } from './client-main-view.component';
|
||||
|
||||
describe('ClientMainViewComponent', () => {
|
||||
let component: ClientMainViewComponent;
|
||||
let fixture: ComponentFixture<ClientMainViewComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ClientMainViewComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ClientMainViewComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -10,6 +10,10 @@ export class ClientMainViewComponent implements OnInit {
|
|||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||
clientUuid: string;
|
||||
clientData: any;
|
||||
isPartitionAssistantVisible: boolean = false;
|
||||
isBootImageVisible: boolean = false;
|
||||
isGeneralInfoVisible: boolean = true;
|
||||
isDiskUsageVisible: boolean = true;
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
const url = window.location.href;
|
||||
|
@ -32,5 +36,21 @@ export class ClientMainViewComponent implements OnInit {
|
|||
);
|
||||
}
|
||||
|
||||
togglePartitionAssistant() {
|
||||
this.isPartitionAssistantVisible = !this.isPartitionAssistantVisible;
|
||||
}
|
||||
|
||||
toggleGeneralInfo() {
|
||||
this.isGeneralInfoVisible = !this.isGeneralInfoVisible;
|
||||
}
|
||||
|
||||
toggleDiskUsage() {
|
||||
this.isDiskUsageVisible = !this.isDiskUsageVisible;
|
||||
}
|
||||
|
||||
showBootImage() {
|
||||
this.isPartitionAssistantVisible = false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
margin: 10px 0;
|
||||
height: 30px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #c5c5c5;
|
||||
}
|
||||
|
||||
.partition-segment {
|
||||
|
@ -36,7 +37,7 @@
|
|||
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
|
@ -46,3 +47,8 @@
|
|||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: red;
|
||||
margin-top: 10px;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<div class="partition-assistant">
|
||||
<div class="header">
|
||||
<label for="disk-number">Num. disco:</label>
|
||||
<input id="disk-number" type="number" [(ngModel)]="diskNumber" />
|
||||
<label for="partition-table">Tabla particiones:</label>
|
||||
<select id="partition-table" [(ngModel)]="partitionTable">
|
||||
<option value="MSDOS">MSDOS</option>
|
||||
<option value="GPT">GPT</option>
|
||||
</select>
|
||||
<span class="disk-size">Tamaño: {{ totalDiskSize }} GB</span>
|
||||
</div>
|
||||
|
||||
<!-- Barra visual de particiones -->
|
||||
<div class="partition-bar">
|
||||
<div
|
||||
*ngFor="let partition of partitions"
|
||||
[ngStyle]="{'width': partition.percentage + '%', 'background-color': partition.color}"
|
||||
class="partition-segment"
|
||||
>
|
||||
{{ partition.type }} ({{ partition.size }} GB)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button mat-button (click)="addPartition()">Añadir</button>
|
||||
|
||||
<!-- Tabla de particiones (simplificada) -->
|
||||
<table class="partition-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Partición</th>
|
||||
<th>Tipo partición</th>
|
||||
<th>Tamaño (GB)</th>
|
||||
<th>Formatear</th>
|
||||
<th>Eliminar</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let partition of partitions; let i = index">
|
||||
<td>{{ i + 1 }}</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(i, 'gb')"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" [(ngModel)]="partition.format" />
|
||||
</td>
|
||||
<td>
|
||||
<button (click)="removePartition(i)" class="remove-btn">X</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div *ngIf="errorMessage" class="error-message">{{ errorMessage }}</div>
|
||||
|
||||
<!-- Solo el botón de Guardar -->
|
||||
<div class="actions">
|
||||
<button mat-button (click)="save()">Guardar</button>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,107 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
interface Partition {
|
||||
size: number;
|
||||
type: string;
|
||||
sizeBytes: number;
|
||||
format: boolean;
|
||||
color: string;
|
||||
percentage: number;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-partition-assistant',
|
||||
templateUrl: './partition-assistant.component.html',
|
||||
styleUrls: ['./partition-assistant.component.css']
|
||||
})
|
||||
export class PartitionAssistantComponent {
|
||||
diskNumber = 1;
|
||||
partitionTable = 'MSDOS';
|
||||
totalDiskSize = 100;
|
||||
errorMessage = '';
|
||||
|
||||
partitions: Partition[] = [
|
||||
{ size: 17.96, type: 'NTFS', sizeBytes: 17.96 * 1024 * 1024 * 1024, format: false, color: '#00a2e8', percentage: 17.96 },
|
||||
{ size: 17.29, type: 'LINUX', sizeBytes: 17.29 * 1024 * 1024 * 1024, format: false, color: '#6a5acd', percentage: 17.29 },
|
||||
{ size: 12.64, type: 'CACHE', sizeBytes: 12.64 * 1024 * 1024 * 1024, format: false, color: '#ff0000', percentage: 12.64 }
|
||||
];
|
||||
|
||||
addPartition() {
|
||||
const remainingGB = this.getRemainingGB();
|
||||
if (remainingGB > 0) {
|
||||
this.partitions.push({
|
||||
size: 0,
|
||||
type: 'NTFS',
|
||||
sizeBytes: 0,
|
||||
format: false,
|
||||
color: '#cccccc',
|
||||
percentage: 0
|
||||
});
|
||||
} else {
|
||||
this.errorMessage = 'No hay suficiente espacio libre en el disco para crear una nueva partición.';
|
||||
}
|
||||
}
|
||||
|
||||
removePartition(index: number) {
|
||||
this.partitions.splice(index, 1);
|
||||
this.updatePartitionPercentages();
|
||||
}
|
||||
|
||||
updatePartitionSize(index: number, type: 'gb') {
|
||||
const partition = this.partitions[index];
|
||||
const remainingGB = this.getRemainingGB() + partition.size;
|
||||
|
||||
if (partition.size > remainingGB) {
|
||||
this.errorMessage = `El tamaño de la partición no puede superar el espacio libre (${remainingGB.toFixed(2)} GB).`;
|
||||
partition.size = 0;
|
||||
} else {
|
||||
this.errorMessage = '';
|
||||
partition.sizeBytes = partition.size * 1024 * 1024 * 1024;
|
||||
this.updatePartitionPercentages();
|
||||
}
|
||||
}
|
||||
|
||||
updatePartitionPercentages() {
|
||||
const totalUsedGB = this.partitions.reduce((acc, partition) => acc + partition.size, 0);
|
||||
const remainingGB = this.totalDiskSize - totalUsedGB;
|
||||
|
||||
this.partitions.forEach(partition => {
|
||||
partition.percentage = (partition.size / this.totalDiskSize) * 100;
|
||||
});
|
||||
|
||||
if (remainingGB > 0) {
|
||||
const freeSpaceIndex = this.partitions.findIndex(partition => partition.type === 'LIBRE');
|
||||
|
||||
if (freeSpaceIndex > -1) {
|
||||
this.partitions[freeSpaceIndex].size = remainingGB;
|
||||
this.partitions[freeSpaceIndex].percentage = (remainingGB / this.totalDiskSize) * 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getRemainingGB(): number {
|
||||
const totalUsedGB = this.partitions.reduce((acc, partition) => acc + partition.size, 0);
|
||||
return Math.max(0, this.totalDiskSize - totalUsedGB);
|
||||
}
|
||||
|
||||
save() {
|
||||
const totalSize = this.partitions.reduce((acc, partition) => acc + partition.size, 0);
|
||||
|
||||
if (totalSize > this.totalDiskSize) {
|
||||
this.errorMessage = `El tamaño total de las particiones (${totalSize} GB) supera el tamaño total del disco (${this.totalDiskSize} GB).`;
|
||||
return;
|
||||
} else {
|
||||
this.errorMessage = '';
|
||||
}
|
||||
|
||||
const payload = this.partitions.map((partition, index) => ({
|
||||
diskNumber: this.diskNumber,
|
||||
partitionNumber: index + 1,
|
||||
size: partition.size,
|
||||
filesystem: partition.type,
|
||||
format: partition.format
|
||||
}));
|
||||
|
||||
console.log('Payload:', JSON.stringify(payload, null, 2));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue