refs #917 Update client-main-view.component.html and create-image.component.html
parent
0d0ab87c35
commit
bf376b8f7b
|
@ -63,7 +63,7 @@
|
|||
|
||||
|
||||
<div class="assistants-container" *ngIf="isPartitionAssistantVisible">
|
||||
<app-partition-assistant [data]="clientData"></app-partition-assistant>
|
||||
<app-partition-assistant [data]="clientData" [clientUuid]="clientUuid"></app-partition-assistant>
|
||||
</div>
|
||||
<div class="assistants-container" *ngIf="isBootImageVisible">
|
||||
<app-restore-image [data]="clientData"></app-restore-image>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let partition of disk.partitions; let j = index">
|
||||
<td>{{ j + 1 }}</td>
|
||||
<td>{{ partition.partitionNumber }}</td>
|
||||
<td>
|
||||
<select [(ngModel)]="partition.type">
|
||||
<option value="NTFS">NTFS</option>
|
||||
|
@ -47,7 +47,7 @@
|
|||
<input type="checkbox" [(ngModel)]="partition.format" />
|
||||
</td>
|
||||
<td>
|
||||
<button (click)="removePartition(disk.diskNumber, j)" class="remove-btn">X</button>
|
||||
<button (click)="removePartition(disk.diskNumber, partition)" class="remove-btn">X</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -2,6 +2,7 @@ import { Component, Input, OnInit } from '@angular/core';
|
|||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
interface Partition {
|
||||
uuid?: string; // Agregamos uuid opcional
|
||||
partitionNumber: number;
|
||||
size: number;
|
||||
type: string;
|
||||
|
@ -48,6 +49,7 @@ export class PartitionAssistantComponent implements OnInit {
|
|||
disk!.totalDiskSize = this.convertBytesToGB(partition.size);
|
||||
} else {
|
||||
disk!.partitions.push({
|
||||
uuid: partition.uuid, // Incluimos el uuid
|
||||
partitionNumber: partition.partitionNumber,
|
||||
size: this.convertBytesToGB(partition.size),
|
||||
type: partition.type,
|
||||
|
@ -146,16 +148,20 @@ export class PartitionAssistantComponent implements OnInit {
|
|||
);
|
||||
|
||||
if (!originalPartition) {
|
||||
// Es una nueva partición
|
||||
modifiedPartitions.push({
|
||||
partition,
|
||||
diskNumber: disk.diskNumber,
|
||||
partitionNumber: partition.partitionNumber
|
||||
partitionNumber: partition.partitionNumber,
|
||||
isNew: true
|
||||
});
|
||||
} else if (this.isPartitionModified(originalPartition, partition)) {
|
||||
// La partición ha sido modificada
|
||||
modifiedPartitions.push({
|
||||
partition,
|
||||
diskNumber: disk.diskNumber,
|
||||
partitionNumber: partition.partitionNumber
|
||||
partitionNumber: partition.partitionNumber,
|
||||
isNew: false
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -172,32 +178,62 @@ export class PartitionAssistantComponent implements OnInit {
|
|||
return;
|
||||
}
|
||||
|
||||
modifiedPartitions.forEach(({ partition, diskNumber, partitionNumber }) => {
|
||||
modifiedPartitions.forEach(({ partition, diskNumber, partitionNumber, isNew }) => {
|
||||
const payload = {
|
||||
diskNumber: diskNumber,
|
||||
partitionNumber: partitionNumber,
|
||||
size: partition.size,
|
||||
filesystem: partition.type,
|
||||
client: `https://example.com/${this.clientUuid}`
|
||||
client: `/clients/${this.clientUuid}`
|
||||
};
|
||||
|
||||
this.http.post(this.apiUrl, payload).subscribe(
|
||||
(response) => {
|
||||
console.log('Partición guardada exitosamente:', response);
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al guardar la partición:', error);
|
||||
}
|
||||
);
|
||||
if (isNew) {
|
||||
// Es una nueva partición, usamos POST
|
||||
this.http.post(this.apiUrl, payload).subscribe(
|
||||
(response) => {
|
||||
console.log('Partición creada exitosamente:', response);
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al crear la partición:', error);
|
||||
}
|
||||
);
|
||||
} else if (partition.uuid) {
|
||||
// Es una partición existente modificada, usamos PATCH
|
||||
const patchUrl = `${this.apiUrl}/${partition.uuid}`;
|
||||
this.http.patch(patchUrl, payload).subscribe(
|
||||
(response) => {
|
||||
console.log('Partición actualizada exitosamente:', response);
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al actualizar la partición:', error);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
removePartition(diskNumber: number, index: number) {
|
||||
removePartition(diskNumber: number, partition: Partition) {
|
||||
const disk = this.disks.find((d) => d.diskNumber === diskNumber);
|
||||
|
||||
if (disk) {
|
||||
disk.partitions.splice(index, 1);
|
||||
this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize);
|
||||
const index = disk.partitions.indexOf(partition);
|
||||
if (index !== -1) {
|
||||
disk.partitions.splice(index, 1);
|
||||
this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize);
|
||||
|
||||
if (partition.uuid) {
|
||||
// La partición existía originalmente, enviamos DELETE
|
||||
const deleteUrl = `${this.apiUrl}/${partition.uuid}`;
|
||||
this.http.delete(deleteUrl).subscribe(
|
||||
(response) => {
|
||||
console.log('Partición eliminada exitosamente:', response);
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al eliminar la partición:', error);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,38 @@
|
|||
<div *ngFor="let disk of disks" class="partition-assistant">
|
||||
<div class="header">
|
||||
<label>Disco {{ disk.diskNumber }}</label>
|
||||
</div>
|
||||
|
||||
<table class="partition-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Partición</th>
|
||||
<th>Imagen ISO</th>
|
||||
<th>OgLive</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let partition of disk.partitions">
|
||||
<td>{{ partition.partitionNumber }}</td>
|
||||
<td>
|
||||
<select (change)="onImageSelected(partition, $event)">
|
||||
<option value="">Seleccionar imagen</option>
|
||||
<option *ngFor="let image of availableImages" [value]="image">{{ image }}</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select (change)="onOgLiveSelected(partition, $event)">
|
||||
<option value="">Seleccionar OgLive</option>
|
||||
<option *ngFor="let ogLive of availableOgLives" [value]="ogLive">{{ ogLive }}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="header">
|
||||
<label>Disco {{ disk.diskNumber }}</label>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button mat-flat-button color="primary" (click)="saveAssociations()">Guardar Asociaciones</button>
|
||||
</div>
|
||||
|
||||
|
||||
<table class="partition-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Partición</th>
|
||||
<th>Imagen ISO</th>
|
||||
<th>OgLive</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let partition of disk.partitions">
|
||||
<td>{{ partition.partitionNumber }}</td>
|
||||
<td>
|
||||
<select [(ngModel)]="partition.associatedImageId" (change)="onImageSelected(partition, $event)" name="associatedImage-{{partition.partitionNumber}}">
|
||||
<option value="">Seleccionar imagen</option>
|
||||
<option *ngFor="let image of availableImages" [value]="image['@id']">
|
||||
{{ image.name }}
|
||||
</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select (change)="onOgLiveSelected(partition, $event)">
|
||||
<option value="">Seleccionar OgLive</option>
|
||||
<option *ngFor="let ogLive of availableOgLives" [value]="ogLive">{{ ogLive }}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button mat-flat-button color="primary" (click)="saveAssociations()">Guardar Asociaciones</button>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,20 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
interface Image {
|
||||
'@id': string;
|
||||
'@type': string;
|
||||
name: string;
|
||||
description: string;
|
||||
comments: string;
|
||||
uuid: string;
|
||||
id: number;
|
||||
}
|
||||
|
||||
interface Partition {
|
||||
diskNumber: number;
|
||||
partitionNumber: number;
|
||||
associatedImage?: string;
|
||||
associatedImageId?: string;
|
||||
associatedOgLive?: string;
|
||||
}
|
||||
|
||||
|
@ -16,12 +27,14 @@ export class RestoreImageComponent implements OnInit {
|
|||
@Input() data: any;
|
||||
|
||||
disks: { diskNumber: number; partitions: Partition[] }[] = [];
|
||||
availableImages: string[] = [];
|
||||
availableImages: Image[] = [];
|
||||
availableOgLives: string[] = [];
|
||||
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.initializeDisks();
|
||||
this.availableImages = ['Windows10.iso', 'Ubuntu.iso', 'macOS.iso'];
|
||||
this.fetchAvailableImages();
|
||||
this.availableOgLives = ['LiveCD1', 'LiveCD2', 'LiveCD3'];
|
||||
}
|
||||
|
||||
|
@ -45,9 +58,21 @@ export class RestoreImageComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
fetchAvailableImages() {
|
||||
const url = 'http://127.0.0.1:8001/images?page=1&itemsPerPage=30';
|
||||
this.http.get(url).subscribe(
|
||||
(response: any) => {
|
||||
this.availableImages = response['hydra:member'];
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al obtener las imágenes:', error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
onImageSelected(partition: Partition, event: Event) {
|
||||
const selectElement = event.target as HTMLSelectElement;
|
||||
partition.associatedImage = selectElement.value;
|
||||
partition.associatedImageId = selectElement.value;
|
||||
}
|
||||
|
||||
onOgLiveSelected(partition: Partition, event: Event) {
|
||||
|
@ -58,9 +83,11 @@ export class RestoreImageComponent implements OnInit {
|
|||
saveAssociations() {
|
||||
this.disks.forEach(disk => {
|
||||
disk.partitions.forEach(partition => {
|
||||
if (partition.associatedImage || partition.associatedOgLive) {
|
||||
console.log(`Guardando para disco ${partition.diskNumber}, partición ${partition.partitionNumber}, Imagen: ${partition.associatedImage}, OgLive: ${partition.associatedOgLive}`);
|
||||
|
||||
if (partition.associatedImageId || partition.associatedOgLive) {
|
||||
console.log(
|
||||
`Guardando para disco ${partition.diskNumber}, partición ${partition.partitionNumber}, ` +
|
||||
`Imagen ID: ${partition.associatedImageId}, OgLive: ${partition.associatedOgLive}`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,7 +19,11 @@
|
|||
|
||||
<mat-form-field appearance="fill" class="form-field">
|
||||
<mat-label>Perfil de software</mat-label>
|
||||
<input matInput [(ngModel)]="imagePayload.softwareProfile" name="softwareProfile">
|
||||
<mat-select [(ngModel)]="imagePayload.softwareProfile" name="softwareProfile">
|
||||
<mat-option *ngFor="let profile of softwareProfiles" [value]="profile['@id']">
|
||||
{{ profile.description }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
|
|
|
@ -1,16 +1,30 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
|
||||
interface ImagePayload {
|
||||
[key: string]: any;
|
||||
name: string | null;
|
||||
description: string | null;
|
||||
comments: string | null;
|
||||
type: string | null;
|
||||
path: string | null;
|
||||
revision: string | null;
|
||||
info: string | null;
|
||||
size: number | null;
|
||||
client: string | null;
|
||||
softwareProfile: string | null;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-image',
|
||||
templateUrl: './create-image.component.html',
|
||||
styleUrls: ['./create-image.component.css']
|
||||
})
|
||||
export class CreateImageComponent {
|
||||
export class CreateImageComponent implements OnInit {
|
||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||
imagePayload = {
|
||||
imagePayload: ImagePayload = {
|
||||
name: null,
|
||||
description: null,
|
||||
comments: null,
|
||||
|
@ -23,21 +37,44 @@ export class CreateImageComponent {
|
|||
softwareProfile: null
|
||||
};
|
||||
|
||||
softwareProfiles: any[] = [];
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<CreateImageComponent>,
|
||||
private http: HttpClient,
|
||||
private toastService: ToastrService
|
||||
) {}
|
||||
|
||||
saveImage(): void {
|
||||
// Remover propiedades que son null antes de enviar la solicitud
|
||||
const payload = { ...this.imagePayload };
|
||||
ngOnInit() {
|
||||
this.fetchSoftwareProfiles();
|
||||
}
|
||||
|
||||
// Enviar la solicitud POST al servidor
|
||||
fetchSoftwareProfiles() {
|
||||
const url = 'http://127.0.0.1:8001/software-profiles?page=1&itemsPerPage=30';
|
||||
this.http.get(url).subscribe({
|
||||
next: (response: any) => {
|
||||
this.softwareProfiles = response['hydra:member'];
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al obtener los perfiles de software:', error);
|
||||
this.toastService.error('Error al obtener los perfiles de software');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
saveImage(): void {
|
||||
const payload = { ...this.imagePayload };
|
||||
Object.keys(payload).forEach(key => {
|
||||
if (payload[key] == null) {
|
||||
delete payload[key];
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Payload:', payload);
|
||||
this.http.post(`${this.baseUrl}/images`, payload).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Imagen creada con éxito');
|
||||
this.dialogRef.close(true); // Cierra el diálogo y retorna true
|
||||
this.dialogRef.close(true);
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al crear la imagen:', error);
|
||||
|
@ -47,6 +84,6 @@ export class CreateImageComponent {
|
|||
}
|
||||
|
||||
close(): void {
|
||||
this.dialogRef.close(); // Cierra el diálogo sin retorno
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue