refs #1654. Refactor create image component for improved UX and loading state management
testing/ogGui-multibranch/pipeline/head This commit looks good Details

pull/18/head
Lucas Lara García 2025-03-07 09:27:37 +01:00
parent 83c3b3caed
commit 9ab68cc6e2
3 changed files with 99 additions and 77 deletions

View File

@ -1,8 +1,25 @@
.dialog-content { .create-image-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16px; padding: 1rem;
/* Espacio entre los elementos del formulario */ }
.loading-spinner {
display: block;
margin: 0 auto;
}
.mat-dialog-content.loading {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
}
.mat-dialog-content {
padding-left: 1.5em;
padding-right: 1.5em;
padding-top: 1em;
} }
.image-form { .image-form {

View File

@ -1,72 +1,72 @@
<app-loading [isLoading]="loading"></app-loading> <div class="create-image-container">
<h2 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Crear' }} imagen</h2>
<div class="mat-dialog-content" [ngClass]="{'loading': loading}">
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
<form *ngIf="!loading" [formGroup]="imageForm" (ngSubmit)="saveImage()" class="image-form">
<mat-card *ngIf="showWarning" class="warning-card">
<mat-card-content>
<mat-icon color="warn">warning</mat-icon>
Ha marcado la casilla <strong>"Imagen Global"</strong>. Se transferirá la imagen al resto de repositorios en
el
caso de que no exista previamente.
</mat-card-content>
</mat-card>
<mat-form-field appearance="fill" class="form-field">
<mat-label>{{ 'imageNameLabel' | translate }}</mat-label>
<input matInput formControlName="name" required>
</mat-form-field>
<h2 mat-dialog-title>{{ imageId ? 'Editar' : 'Crear' }} imagen</h2> <mat-form-field appearance="fill" class="form-field" *ngIf="!imageId">
<mat-label>{{ 'repositoryLabel' | translate }}</mat-label>
<mat-select formControlName="imageRepositories" required multiple>
<mat-option *ngFor="let imageRepository of repositories" [value]="imageRepository['@id']">
{{ imageRepository.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-dialog-content class="dialog-content"> <mat-form-field appearance="fill" class="form-field">
<form [formGroup]="imageForm" (ngSubmit)="saveImage()" class="image-form"> <mat-label>{{ 'descriptionLabel' | translate }}</mat-label>
<mat-card *ngIf="showWarning" class="warning-card"> <input matInput formControlName="description" name="description">
<mat-card-content> </mat-form-field>
<mat-icon color="warn">warning</mat-icon>
Ha marcado la casilla <strong>"Imagen Global"</strong>. Se transferirá la imagen al resto de repositorios en el
caso de que no exista previamente.
</mat-card-content>
</mat-card>
<mat-form-field appearance="fill" class="form-field">
<mat-label>{{ 'imageNameLabel' | translate }}</mat-label>
<input matInput formControlName="name" required>
</mat-form-field>
<mat-form-field appearance="fill" class="form-field" *ngIf="!imageId"> <mat-form-field appearance="fill" class="form-field">
<mat-label>{{ 'repositoryLabel' | translate }}</mat-label> <mat-label>{{ 'commentsLabel' | translate }}</mat-label>
<mat-select formControlName="imageRepositories" required multiple> <input matInput formControlName="comments" name="comments">
<mat-option *ngFor="let imageRepository of repositories" [value]="imageRepository['@id']"> </mat-form-field>
{{ imageRepository.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill" class="form-field"> <mat-form-field appearance="fill" class="form-field">
<mat-label>{{ 'descriptionLabel' | translate }}</mat-label> <mat-label>Perfil de software</mat-label>
<input matInput formControlName="description" name="description"> <mat-select formControlName="softwareProfile">
</mat-form-field> <mat-option *ngFor="let profile of softwareProfiles" [value]="profile['@id']">
{{ profile.description }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill" class="form-field"> <mat-checkbox formControlName="remotePc">
<mat-label>{{ 'commentsLabel' | translate }}</mat-label> {{ 'remotePcLabel' | translate }}
<input matInput formControlName="comments" name="comments"> </mat-checkbox>
</mat-form-field>
<mat-form-field appearance="fill" class="form-field"> <mat-checkbox formControlName="isGlobal" (click)="changeIsGlobal()">
<mat-label>Perfil de software</mat-label> {{ 'globalImageLabel' | translate }}
<mat-select formControlName="softwareProfile"> </mat-checkbox>
<mat-option *ngFor="let profile of softwareProfiles" [value]="profile['@id']">
{{ profile.description }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-checkbox formControlName="remotePc"> <mat-divider *ngIf="imageId && partitionInfo"></mat-divider>
{{ 'remotePcLabel' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="isGlobal" (click)="changeIsGlobal()"> <div *ngIf="imageId && partitionInfo" class="partition-info-container">
{{ 'globalImageLabel' | translate }} <h3>Información de Partición de origen</h3>
</mat-checkbox> <p>Sistema de archivos: {{ partitionInfo['filesystem'] }}</p>
<p>Disco: {{ partitionInfo['numDisk'] }}</p>
<p>Particion: {{ partitionInfo['numPartition'] }}</p>
<p>Nombre del SO: {{ partitionInfo['osName'] }}</p>
<p>Código de partición: {{ partitionInfo['partitionCode'] }}</p>
</div>
</form>
</div>
<mat-divider *ngIf="imageId && partitionInfo"></mat-divider> <mat-dialog-actions class="action-container">
<button class="ordinary-button" (click)="close()">{{ 'cancelButton' | translate }}</button>
<div *ngIf="imageId && partitionInfo" class="partition-info-container"> <button class="submit-button" (click)="saveImage()" [disabled]="loading">{{ 'saveButton' | translate }}</button>
<h3>Información de Partición de origen</h3> </mat-dialog-actions>
<p>Sistema de archivos: {{ partitionInfo['filesystem'] }}</p> </div>
<p>Disco: {{ partitionInfo['numDisk'] }}</p>
<p>Particion: {{ partitionInfo['numPartition'] }}</p>
<p>Nombre del SO: {{ partitionInfo['osName'] }}</p>
<p>Código de partición: {{ partitionInfo['partitionCode'] }}</p>
</div>
</form>
</mat-dialog-content>
<mat-dialog-actions class="action-container">
<button class="ordinary-button" (click)="close()">{{ 'cancelButton' | translate }}</button>
<button class="submit-button" (click)="saveImage()">{{ 'saveButton' | translate }}</button>
</mat-dialog-actions>

View File

@ -17,6 +17,7 @@ export class CreateImageComponent implements OnInit {
softwareProfiles: any[] = []; softwareProfiles: any[] = [];
repositories: any[] = []; repositories: any[] = [];
loading: boolean = false; loading: boolean = false;
isEditMode: boolean = false;
partitionInfo: { [key: string]: string } = {}; partitionInfo: { [key: string]: string } = {};
showWarning: boolean = false; showWarning: boolean = false;
@ -42,30 +43,34 @@ export class CreateImageComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.loading = true; this.loading = true;
if (this.data) { if (this.data) {
this.load() this.isEditMode = true;
this.load();
} else {
this.loading = false;
} }
this.fetchSoftwareProfiles(); this.fetchSoftwareProfiles();
this.fetchRepositories(); this.fetchRepositories();
this.loading = false;
} }
load(): void { load(): void {
this.dataService.getImage(this.data).subscribe({ this.dataService.getImage(this.data).subscribe({
next: (response) => { next: (response) => {
this.imageForm = this.fb.group({ this.imageForm.patchValue({
name: [response.name, Validators.required], name: response.name,
description: [response.description], description: response.description,
comments: [response.comments], comments: response.comments,
remotePc: [response.remotePc], remotePc: response.remotePc,
isGlobal: [response.isGlobal], isGlobal: response.isGlobal,
softwareProfile: [response.softwareProfile ? response.softwareProfile['@id'] : null, Validators.required], softwareProfile: response.softwareProfile ? response.softwareProfile['@id'] : null,
imageRepositories: [response.imageRepositories ? response.imageRepositories.map((r: any) => r.imageRepository['@id']) : [], Validators.required], imageRepositories: response.imageRepositories ? response.imageRepositories.map((r: any) => r.imageRepository['@id']) : [],
}); });
this.imageId = response['@id']; this.imageId = response['@id'];
this.partitionInfo = response.partitionInfo; this.partitionInfo = response.partitionInfo;
this.loading = false;
}, },
error: (err) => { error: (err) => {
console.error('Error fetching remote calendar:', err); console.error('Error fetching remote calendar:', err);
this.loading = false;
} }
}); });
} }
@ -135,4 +140,4 @@ export class CreateImageComponent implements OnInit {
close(): void { close(): void {
this.dialogRef.close(); this.dialogRef.close();
} }
} }