Updated partition assistant
parent
f3ccdd9498
commit
4c9757a7c2
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -1,4 +1,18 @@
|
|||
# Changelog
|
||||
## [0.26.0] - 2025-10-09
|
||||
### Improved
|
||||
- Se han eliminado campos redudantes en la creacion/edicion de cliente
|
||||
- En el particionador, ahora el despleagble del disco se autocompleta en caso de ser 1.
|
||||
|
||||
---
|
||||
## [0.25.0] - 2025-10-08
|
||||
### Added
|
||||
- Se ha añadido una logica en el particionador, el cual filtra las opciones del sistema de ficheros, segun el tipo de particion seleccionado.
|
||||
|
||||
### Fixed
|
||||
- Se ha corregido el componente "estado global" ya que no funcionaba correctamente para el repositorio-
|
||||
|
||||
---
|
||||
## [0.24.1] - 2025-10-06
|
||||
### Fixed
|
||||
- Se ha corregido un error en los casos de 2 discos o mas en el asistente de particionado.
|
||||
|
|
|
@ -210,21 +210,32 @@ export class GlobalStatusComponent implements OnInit {
|
|||
this.loading = true;
|
||||
}
|
||||
this.errorRepositories = {};
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (showLoading) {
|
||||
this.loading = false;
|
||||
}
|
||||
this.repositories.forEach(repository => {
|
||||
if (!(repository.uuid in this.errorRepositories)) {
|
||||
this.errorRepositories[repository.uuid] = true;
|
||||
}
|
||||
});
|
||||
}, 5000);
|
||||
|
||||
|
||||
this.http.get<any>(`${this.repositoriesUrl}?page=1&itemsPerPage=10`).subscribe(
|
||||
data => {
|
||||
this.repositories = data['hydra:member'];
|
||||
console.log('Respuesta de repositorios:', data); // Debug log
|
||||
this.repositories = data['hydra:member'] || [];
|
||||
console.log('Repositorios cargados:', this.repositories); // Debug log
|
||||
|
||||
if (this.repositories.length === 0) {
|
||||
if (showLoading) {
|
||||
this.loading = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let remainingRepositories = this.repositories.length;
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (showLoading) {
|
||||
this.loading = false;
|
||||
}
|
||||
// Marcar como error los repositorios que no han respondido
|
||||
this.repositories.forEach(repository => {
|
||||
if (!(repository.uuid in this.errorRepositories)) {
|
||||
this.errorRepositories[repository.uuid] = true;
|
||||
}
|
||||
});
|
||||
}, 5000);
|
||||
|
||||
this.repositories.forEach(repository => {
|
||||
this.loadRepositoryStatus(repository.uuid, (errorOccurred: boolean) => {
|
||||
|
@ -242,39 +253,61 @@ export class GlobalStatusComponent implements OnInit {
|
|||
});
|
||||
},
|
||||
error => {
|
||||
console.error('Error al cargar repositorios:', error); // Debug log
|
||||
this.loading = false;
|
||||
this.repositories.forEach(repository => {
|
||||
this.errorRepositories[repository.uuid] = true;
|
||||
});
|
||||
clearTimeout(timeoutId);
|
||||
this.repositories = [];
|
||||
this.toastService.error('Error al cargar la lista de repositorios');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
loadRepositoryStatus(repositoryUuid: string, callback: (errorOccurred: boolean) => void): void {
|
||||
console.log(`Cargando estado del repositorio: ${repositoryUuid}`); // Debug log
|
||||
const timeoutId = setTimeout(() => {
|
||||
console.log(`Timeout al cargar estado del repositorio: ${repositoryUuid}`); // Debug log
|
||||
callback(true);
|
||||
}, 5000);
|
||||
|
||||
this.http.get<any>(`${this.baseUrl}/image-repositories/server/${repositoryUuid}/status`).subscribe(
|
||||
data => {
|
||||
const output = data.output;
|
||||
console.log(`Estado del repositorio ${repositoryUuid}:`, data); // Debug log
|
||||
|
||||
if (!data.success) {
|
||||
console.error(`Error en la respuesta del repositorio ${repositoryUuid}:`, data);
|
||||
clearTimeout(timeoutId);
|
||||
callback(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const details = data.details;
|
||||
const { disk, services, ram, cpu, processes } = details;
|
||||
|
||||
this.repositoryStatuses[repositoryUuid] = {
|
||||
...output,
|
||||
disk: {
|
||||
...output.disk,
|
||||
used: parseFloat(output.disk.used),
|
||||
available: parseFloat(output.disk.available)
|
||||
...disk,
|
||||
used: parseFloat(disk.used.replace('GB', '')),
|
||||
available: parseFloat(disk.available.replace('GB', '')),
|
||||
total: parseFloat(disk.total.replace('GB', '')),
|
||||
percentage: disk.used_percentage
|
||||
},
|
||||
ram: {
|
||||
...output.ram,
|
||||
used: parseFloat(output.ram.used),
|
||||
available: parseFloat(output.ram.available)
|
||||
}
|
||||
...ram,
|
||||
used: parseFloat(ram.used.replace('GB', '')),
|
||||
available: parseFloat(ram.available.replace('GB', '')),
|
||||
total: parseFloat(ram.total.replace('GB', '')),
|
||||
percentage: ram.used_percentage
|
||||
},
|
||||
cpu: {
|
||||
used_percentage: cpu.used_percentage
|
||||
},
|
||||
services: services,
|
||||
processes: processes
|
||||
};
|
||||
clearTimeout(timeoutId);
|
||||
callback(false);
|
||||
},
|
||||
error => {
|
||||
console.error(`Error al cargar estado del repositorio ${repositoryUuid}:`, error); // Debug log
|
||||
this.toastService.error(error.error['hydra:description'] || 'Error al cargar el estado del repositorio');
|
||||
clearTimeout(timeoutId);
|
||||
callback(true);
|
||||
|
|
|
@ -63,16 +63,13 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
partitionCode: string = '';
|
||||
generatedInstructions: string = '';
|
||||
|
||||
// Propiedades para validación de particiones
|
||||
partitionValidationStatus: 'idle' | 'loading' | 'success' | 'error' = 'idle';
|
||||
partitionValidationMessage: string = '';
|
||||
private validationDebounceTime = 500; // ms
|
||||
private validationDebounceTime = 500;
|
||||
private validationSubject = new Subject<void>();
|
||||
|
||||
// Columnas para mat-table
|
||||
displayedColumns: string[] = ['partitionNumber', 'partitionCode', 'filesystem', 'size', 'percentage', 'format', 'actions'];
|
||||
|
||||
// Paleta de colores para las particiones
|
||||
private partitionColors = [
|
||||
'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
|
||||
'#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9',
|
||||
|
@ -304,6 +301,11 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
this.disks.forEach((disk) => {
|
||||
this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize);
|
||||
});
|
||||
|
||||
if (this.disks.length === 1) {
|
||||
this.selectedDiskNumber = this.disks[0].diskNumber;
|
||||
this.onDiskSelectionChange();
|
||||
}
|
||||
}
|
||||
|
||||
convertBytesToGB(bytes: number): number {
|
||||
|
@ -855,7 +857,6 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
return this.partitionColors[(partitionNumber - 1) % this.partitionColors.length];
|
||||
}
|
||||
|
||||
|
||||
private validatePartitionCode(partitionCode: string | undefined | null): string {
|
||||
if (!partitionCode || partitionCode.trim() === '') {
|
||||
return 'EMPTY';
|
||||
|
|
|
@ -44,15 +44,6 @@
|
|||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'netDriverLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="netDriver">
|
||||
<mat-option *ngFor="let type of netDriverTypes" [value]="type.value">
|
||||
{{ type.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'macLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="mac" required>
|
||||
|
@ -74,15 +65,6 @@
|
|||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'hardwareProfileLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="hardwareProfile">
|
||||
<mat-option *ngFor="let profile of hardwareProfiles" [value]="profile['@id']">
|
||||
{{ profile.description }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'repositoryLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="repository">
|
||||
|
|
|
@ -16,7 +16,6 @@ export class ManageClientComponent implements OnInit {
|
|||
clientForm!: FormGroup;
|
||||
parentUnits: any[] = [];
|
||||
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
||||
hardwareProfiles: any[] = [];
|
||||
ogLives: any[] = [];
|
||||
menus: any[] = [];
|
||||
templates: any[] = [];
|
||||
|
@ -29,9 +28,6 @@ export class ManageClientComponent implements OnInit {
|
|||
{ name: 'Eth1', value: 'eth1' },
|
||||
{ name: 'Eth2', value: 'eth2' }
|
||||
];
|
||||
protected netDriverTypes = [
|
||||
{ name: 'Generic', value: 'generic' }
|
||||
];
|
||||
isEditMode: boolean;
|
||||
|
||||
constructor(
|
||||
|
@ -53,7 +49,6 @@ export class ManageClientComponent implements OnInit {
|
|||
this.initForm();
|
||||
const observables = [
|
||||
this.loadParentUnits(),
|
||||
this.loadHardwareProfiles(),
|
||||
this.loadOgLives(),
|
||||
this.loadPxeTemplates(),
|
||||
this.loadRepositories(),
|
||||
|
@ -83,11 +78,10 @@ export class ManageClientComponent implements OnInit {
|
|||
name: ['', Validators.required],
|
||||
serialNumber: [''],
|
||||
netiface: null,
|
||||
netDriver: null,
|
||||
netDriver: 'generic',
|
||||
mac: ['', Validators.pattern(/^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$/)],
|
||||
ip: ['', Validators.required],
|
||||
pxeTemplate: [null],
|
||||
hardwareProfile: [null],
|
||||
ogLive: [null],
|
||||
repository: [null],
|
||||
menu: [null],
|
||||
|
@ -108,7 +102,6 @@ export class ManageClientComponent implements OnInit {
|
|||
netiface: unit.networkSettings?.netiface,
|
||||
path: this.dataService.getOrganizationalUnitPath(unit, this.parentUnits),
|
||||
repository: unit.networkSettings?.repository?.['@id'],
|
||||
hardwareProfile: unit.networkSettings?.hardwareProfile?.['@id'],
|
||||
ogLive: unit.networkSettings?.ogLive?.['@id'],
|
||||
menu: unit.networkSettings?.menu?.['@id'],
|
||||
pxeTemplate: unit.networkSettings?.pxeTemplate?.['@id'],
|
||||
|
@ -134,21 +127,6 @@ export class ManageClientComponent implements OnInit {
|
|||
return this.parentUnitsWithPaths.find(unit => unit.id === parentId)?.name;
|
||||
}
|
||||
|
||||
loadHardwareProfiles(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.dataService.getHardwareProfiles().subscribe(
|
||||
(data: any[]) => {
|
||||
this.hardwareProfiles = data;
|
||||
resolve();
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching hardware profiles:', error);
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
loadOgLives(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const url = `${this.baseUrl}/og-lives?page=1&itemsPerPage=30`;
|
||||
|
@ -210,7 +188,7 @@ export class ManageClientComponent implements OnInit {
|
|||
resolve();
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching ogLives:', error);
|
||||
console.error('Error fetching repositories:', error);
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
|
@ -226,7 +204,6 @@ export class ManageClientComponent implements OnInit {
|
|||
if (selectedUnit) {
|
||||
this.clientForm.patchValue({
|
||||
repository: selectedUnit.repository || null,
|
||||
hardwareProfile: selectedUnit.hardwareProfile || null,
|
||||
ogLive: selectedUnit.ogLive || null,
|
||||
menu: selectedUnit.menu || null,
|
||||
netiface: selectedUnit.netiface || null,
|
||||
|
@ -246,9 +223,8 @@ export class ManageClientComponent implements OnInit {
|
|||
ip: data.ip,
|
||||
mac: data.mac,
|
||||
netiface: data.netiface,
|
||||
netDriver: data.netDriver,
|
||||
netDriver: 'generic',
|
||||
serialNumber: data.serialNumber,
|
||||
hardwareProfile: data.hardwareProfile ? data.hardwareProfile['@id'] : null,
|
||||
organizationalUnit: data.organizationalUnit ? data.organizationalUnit['@id'] : null,
|
||||
repository: data.repository ? data.repository['@id'] : null,
|
||||
ogLive: data.ogLive ? data.ogLive['@id'] : null,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
<div class="images-button-row">
|
||||
<button class="action-button" (click)="openImageInfoDialog()">Ver Información</button>
|
||||
<button class="action-button" (click)="openBackupDialog()">Crear Backup</button>
|
||||
<button class="action-button" style="background-color: #f44336; color: white;" (click)="deleteRepository()" [disabled]="!selectedRepository">Eliminar Repositorio</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -100,10 +101,6 @@
|
|||
<button mat-icon-button color="accent" (click)="toggleAction(commit, 'create-tag')" matTooltip="Crear tag">
|
||||
<mat-icon>local_offer</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button color="warn" (click)="toggleAction(commit, 'create-branch')" matTooltip="Crear rama">
|
||||
<mat-icon>account_tree</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
|
|
@ -11,6 +11,7 @@ import {ServerInfoDialogComponent} from "../../ogdhcp/server-info-dialog/server-
|
|||
import {CreateTagModalComponent} from "./create-tag-modal/create-tag-modal.component";
|
||||
import {CreateBranchModalComponent} from "./create-branch-modal/create-branch-modal.component";
|
||||
import { BackupRepositoryModalComponent } from './backup-repository-modal/backup-repository-modal.component';
|
||||
import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component";
|
||||
|
||||
@Component({
|
||||
selector: 'app-show-git-commits',
|
||||
|
@ -317,6 +318,40 @@ export class ShowGitCommitsComponent implements OnInit{
|
|||
window.open(`http://localhost:3100/oggit/${this.selectedRepository}/commit/${commit.hexsha}`, '_blank');
|
||||
}
|
||||
|
||||
deleteRepository(): void {
|
||||
if (!this.selectedRepository) {
|
||||
this.toastService.warning('Por favor, selecciona un repositorio primero');
|
||||
return;
|
||||
}
|
||||
|
||||
const dialogRef = this.dialog.open(DeleteModalComponent, {
|
||||
width: '400px',
|
||||
data: {
|
||||
name: this.selectedRepository,
|
||||
title: 'Eliminar Repositorio',
|
||||
message: '¿Estás seguro que deseas eliminar este repositorio? Esta acción no se puede deshacer.',
|
||||
confirmText: 'Eliminar',
|
||||
cancelText: 'Cancelar'
|
||||
}
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
const payload = { repositoryName: this.selectedRepository };
|
||||
this.http.post(`${this.baseUrl}/image-repositories/server/git/${this.data.repositoryUuid}/delete`, payload).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Repositorio eliminado con éxito');
|
||||
this.dialogRef.close(true);
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al eliminar el repositorio:', error);
|
||||
this.toastService.error('Error al eliminar el repositorio');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onNoClick(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue