refs #1090. PartitionAssistant changes
testing/ogGui-multibranch/pipeline/head This commit is unstable Details

pull/10/head
Manuel Aranda Rosales 2024-12-11 08:46:17 +01:00
parent 4f905778f8
commit 016e5a821a
8 changed files with 96 additions and 76 deletions

View File

@ -198,7 +198,7 @@ export class ClientMainViewComponent implements OnInit {
}
loadPartitions(): void {
this.http.get<any>(`${this.baseUrl}/partitions?client.id=${this.clientData?.id}&order[partitionNumber]=ASC`).subscribe({
this.http.get<any>(`${this.baseUrl}/partitions?client.id=${this.clientData?.id}&order[diskNumber, partitionNumber]=ASC`).subscribe({
next: data => {
this.dataSource = data['hydra:member'];
this.partitions = data['hydra:member'];

View File

@ -54,9 +54,9 @@
</table>
<mat-divider></mat-divider>
<h3 *ngIf="isMethod('multicast')" class="input-group">Opciones multicast</h3>
<h3 *ngIf="isMethod('torrent')" class="input-group">Opciones torrent</h3>
<div *ngIf="isMethod('multicast')" class="input-group">
<h3 *ngIf="isMethod('udpcast') || isMethod('uftp')" class="input-group">Opciones multicast</h3>
<h3 *ngIf="isMethod('p2p')" class="input-group">Opciones torrent</h3>
<div *ngIf="isMethod('udpcast') || isMethod('uftp')" class="input-group">
<mat-form-field appearance="fill" class="input-field">
<mat-label>Puerto</mat-label>
<input matInput [(ngModel)]="mcastPort" name="mcastPort">

View File

@ -39,22 +39,25 @@ export class DeployImageComponent {
{ name: 'Seeder', value: 'p2p-mode-seeder' },
];
protected multicastModeOptions = [
{"name": 'Half duplex', "value": "half-duplex"},
{"name": 'Full duplex', "value": "full-duplex"},
{ name: 'Half duplex', value: "half"},
{ name: 'Full duplex', value: "full"},
];
allMethods = [
'multicast',
'uftp',
'udpcast',
'multicast-direct',
'unicast',
'unicast-direct',
'torrent'
'p2p'
];
updateCacheMethods = [
'uftp',
'udpcast',
'multicast',
'unicast',
'torrent'
'p2p'
];
dataSource = new MatTableDataSource<any>();
@ -177,8 +180,8 @@ export class DeployImageComponent {
this.http.post(`${this.baseUrl}${this.selectedImage}/deploy-image`, payload)
.subscribe({
next: (response) => {
this.toastService.success('Imagen creada exitosamente');
this.router.navigate(['/commmands-logs'])
this.toastService.success('Petición de despliegue enviada correctamente');
this.router.navigate(['/commands-logs'])
},
error: (error) => {
console.error('Error:', error);

View File

@ -162,3 +162,8 @@ button.remove-btn:hover {
align-content: center;
justify-self: center;
}
.disk-select {
padding: 20px;
margin: 10px auto;
}

View File

@ -1,21 +1,27 @@
<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()">Ejecutar</button>
<button mat-flat-button color="primary" [disabled]="data.status === 'busy'" (click)="save()">Ejecutar</button>
</div>
</div>
<mat-divider></mat-divider>
<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="disk-select">
<mat-form-field appearance="fill">
<mat-label>Seleccionar disco</mat-label>
<mat-select [(ngModel)]="selectedDiskNumber">
<mat-option *ngFor="let disk of disks" [value]="disk.diskNumber">
Disco {{ disk.diskNumber }} ({{ (disk.totalDiskSize / 1024).toFixed(2) }} GB)
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="partition-assistant" *ngIf="selectedDisk">
<div class="partition-bar">
<div
*ngFor="let partition of activePartitions(disk.diskNumber)"
*ngFor="let partition of activePartitions(selectedDisk.diskNumber)"
[ngStyle]="{'width': partition.percentage + '%', 'background-color': partition.color}"
class="partition-segment"
>
@ -23,7 +29,7 @@
</div>
</div>
<div class="row">
<button mat-flat-button color="primary" (click)="addPartition(disk.diskNumber)">Añadir partición</button>
<button mat-flat-button color="primary" (click)="addPartition(selectedDisk.diskNumber)">Añadir partición</button>
</div>
<div class="row">
@ -41,7 +47,7 @@
</tr>
</thead>
<tbody>
<ng-container *ngFor="let partition of disk.partitions; let j = index">
<ng-container *ngFor="let partition of selectedDisk.partitions; let j = index">
<tr *ngIf="!partition.removed">
<td>{{ partition.partitionNumber }}</td>
<td>
@ -62,21 +68,21 @@
<input
type="number"
[(ngModel)]="partition.size" required
(input)="updatePartitionSize(disk.diskNumber, j, partition.size)"
(input)="updatePartitionSize(selectedDisk.diskNumber, j, partition.size)"
/>
</td>
<td>
<input
type="number"
[(ngModel)]="partition.percentage"
(input)="updatePartitionSizeFromPercentage(disk.diskNumber, j, partition.percentage)"
(input)="updatePartitionSizeFromPercentage(selectedDisk.diskNumber, j, partition.percentage)"
/>
</td>
<td>
<input type="checkbox" [(ngModel)]="partition.format" />
</td>
<td>
<button (click)="removePartition(disk.diskNumber, partition)" class="remove-btn">X</button>
<button (click)="removePartition(selectedDisk.diskNumber, partition)" class="remove-btn">X</button>
</td>
</tr>
</ng-container>
@ -87,7 +93,7 @@
<div class="chart-container">
<ngx-charts-pie-chart
[view]="view"
[results]="disk.chartData"
[results]="selectedDisk.chartData"
[doughnut]="true"
>
</ngx-charts-pie-chart>
@ -96,5 +102,4 @@
</div>
</mat-dialog-content>
<div *ngIf="errorMessage" class="error-message">{{ errorMessage }}</div>

View File

@ -35,6 +35,7 @@ export class PartitionAssistantComponent implements OnInit {
originalPartitions: any[] = [];
clientId: string | null = null;
newPartitions: any[] = [];
selectedDiskNumber: number | null = null;
updateRequests: any[] = [];
data: any = {};
disks: { diskNumber: number; totalDiskSize: number; partitions: Partition[]; chartData: any[]; used: number; percentage: number }[] = [];
@ -57,6 +58,10 @@ export class PartitionAssistantComponent implements OnInit {
this.loadPartitions();
}
get selectedDisk():any {
return this.disks.find(disk => disk.diskNumber === this.selectedDiskNumber) || null;
}
loadPartitions() {
const url = `${this.baseUrl}/clients/${this.clientId}`;
this.http.get(url).subscribe(
@ -246,59 +251,57 @@ export class PartitionAssistantComponent implements OnInit {
}
save() {
const invalidDisks = this.disks.filter(disk => {
const totalPartitionSize = disk.partitions.reduce((sum, partition) => sum + partition.size, 0);
return totalPartitionSize > disk.totalDiskSize;
});
if (!this.selectedDisk) {
this.errorMessage = 'Por favor selecciona un disco antes de guardar.';
return;
}
console.log(invalidDisks);
if (invalidDisks.length > 0) {
this.errorMessage = 'El tamaño total de las particiones en uno o más discos excede el tamaño total del disco.';
const totalPartitionSize = this.selectedDisk.partitions.reduce((sum: any, partition: { size: any; }) => sum + partition.size, 0);
if (totalPartitionSize > this.selectedDisk.totalDiskSize) {
this.errorMessage = 'El tamaño total de las particiones en el disco seleccionado excede el tamaño total del disco.';
return;
} else {
this.errorMessage = '';
}
const modifiedPartitions = this.getModifiedOrNewPartitions();
const modifiedPartitions = this.selectedDisk.partitions.filter((partition: { removed: any; format: any; }) => !partition.removed || partition.format);
if (modifiedPartitions.length === 0) {
this.errorMessage = 'No hay cambios para guardar.';
this.errorMessage = 'No hay cambios para guardar en el disco seleccionado.';
return;
}
modifiedPartitions.forEach(({ partition, diskNumber, partitionNumber }) => {
const payload = {
diskNumber: diskNumber,
partitionNumber: partitionNumber,
memoryUsage: partition.memoryUsage,
size: partition.size,
partitionCode: partition.partitionCode,
filesystem: partition.filesystem,
client: `/clients/${this.clientId}`,
uuid: partition.uuid,
removed: partition.removed || false,
format: partition.format || false,
};
const newPartitions = modifiedPartitions.map((partition: { partitionNumber: any; memoryUsage: any; size: any; partitionCode: any; filesystem: any; uuid: any; removed: any; format: any; }) => ({
diskNumber: this.selectedDisk.diskNumber,
partitionNumber: partition.partitionNumber,
memoryUsage: partition.memoryUsage,
size: partition.size,
partitionCode: partition.partitionCode,
filesystem: partition.filesystem,
client: `/clients/${this.clientId}`,
uuid: partition.uuid,
removed: partition.removed || false,
format: partition.format || false,
}));
this.newPartitions.push(payload);
});
if (this.newPartitions.length > 0) {
const bulkPayload = { partitions: this.newPartitions };
if (newPartitions.length > 0) {
const bulkPayload = { partitions: newPartitions };
this.http.post(this.apiUrl, bulkPayload).subscribe(
(response) => {
this.toastService.success('Particiones creadas exitosamente');
this.toastService.success('Particiones creadas exitosamente para el disco seleccionado.');
this.router.navigate(['/commands-logs']);
},
(error) => {
console.error('Error al crear las particiones:', error);
this.toastService.error('Error al crear las particiones');
this.toastService.error('Error al crear las particiones.');
}
);
}
}
removePartition(diskNumber: number, partition: Partition) {
const disk = this.disks.find((d) => d.diskNumber === diskNumber);
if (disk) {

View File

@ -220,7 +220,7 @@
<button
*ngIf="(!syncStatus || syncingClientId !== client.uuid)"
mat-icon-button color="primary"
(click)="getStatus(client)">
(click)="getStatus(client, selectedNode)">
<mat-icon>sync</mat-icon>
</button>
@ -251,6 +251,23 @@
</div>
<div class="clients-table" *ngIf="currentView === 'list'">
<table mat-table matSort [dataSource]="selectedClients" class="mat-elevation-z8">
<ng-container matColumnDef="sync">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'sync' | translate }} </th>
<td mat-cell *matCellDef="let client">
<button
*ngIf="(!syncStatus || syncingClientId !== client.uuid)"
mat-icon-button color="primary"
(click)="getStatus(client, selectedNode)">
<mat-icon>sync</mat-icon>
</button>
<button
*ngIf="syncStatus && syncingClientId === client.uuid"
mat-icon-button color="primary">
<mat-spinner diameter="24"></mat-spinner>
</button>
</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'name' | translate }} </th>
<td mat-cell *matCellDef="let client">
@ -263,7 +280,7 @@
</ng-container>
<ng-container matColumnDef="oglive">
<th mat-header-cell *matHeaderCellDef mat-sort-header> OG Live </th>
<td mat-cell *matCellDef="let client"> {{ client.ogLive?.name }} </td>
<td mat-cell *matCellDef="let client"> {{ (client.ogLive?.name || '').slice(0, 15) }}{{ (client.ogLive?.name?.length > 15) ? '...' : '' }} </td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'status' | translate }} </th>
@ -279,23 +296,9 @@
{{ client.status || 'off' }}
</mat-chip>
<button
*ngIf="(!syncStatus || syncingClientId !== client.uuid)"
mat-icon-button color="primary"
(click)="getStatus(client)">
<mat-icon>sync</mat-icon>
</button>
<button
*ngIf="syncStatus && syncingClientId === client.uuid"
mat-icon-button color="primary">
<mat-spinner diameter="24"></mat-spinner>
</button>
</td>
</ng-container>
<ng-container matColumnDef="maintenace">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'maintenance' | translate }} </th>
<td mat-cell *matCellDef="let client"> {{ client.maintenance }} </td>
@ -320,8 +323,8 @@
<button mat-icon-button [matMenuTriggerFor]="clientMenu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #clientMenu="matMenu">
@ -330,7 +333,7 @@
<span>{{ command.name }}</span>
</button>
</mat-menu>
<button mat-menu-item [matMenuTriggerFor]="commandMenu" (click)="fetchCommands()">
<mat-icon>play_arrow</mat-icon>
<span>{{ 'executeCommand' | translate }}</span>

View File

@ -63,7 +63,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
syncingClientId: string | null = null;
private originalTreeData: TreeNode[] = [];
displayedColumns: string[] = ['name', 'oglive', 'status', 'maintenace', 'subnet', 'pxeTemplate', 'parentName', 'actions'];
displayedColumns: string[] = ['sync', 'name', 'oglive', 'status', 'subnet', 'pxeTemplate', 'parentName', 'actions'];
private _sort!: MatSort;
private _paginator!: MatPaginator;
@ -563,7 +563,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
this.selectedNode = node;
}
getStatus(client: Client): void {
getStatus(client: Client, node: any): void {
if (!client.uuid || !client['@id']) return;
this.syncingClientId = client.uuid;
@ -573,14 +573,15 @@ export class GroupsComponent implements OnInit, OnDestroy {
this.http.post(`${this.baseUrl}${client['@id']}/agent/status`, {}).subscribe(
() => {
this.toastr.success('Cliente actualizado correctamente');
this.search();
this.syncStatus = false;
this.syncingClientId = null;
this.onNodeClick(node);
},
() => {
this.toastr.error('Error de conexión con el cliente');
this.syncStatus = false;
this.syncingClientId = null;
this.onNodeClick(node);
}
)
);