ref 3007. Fixed create software profile bug

pull/97/head
Manuel Aranda Rosales 2026-07-13 10:39:53 +02:00
parent dd1b20b9d1
commit aa52c89c52
6 changed files with 74 additions and 44 deletions

View File

@ -63,4 +63,28 @@
justify-content: flex-end;
gap: 1em;
padding: 0em 1.5em 1.5em 1.5em;
}
.software-tab-hint {
color: #666;
font-size: 0.85em;
margin: 0 0 12px 0;
}
.software-list-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 8px;
font-size: 0.85em;
color: #555;
}
.clear-selection-link {
background: none;
border: none;
color: #3f51b5;
cursor: pointer;
text-decoration: underline;
padding: 0;
}

View File

@ -12,14 +12,6 @@
<mat-label>{{ 'labelComments' | translate }}</mat-label>
<input matInput formControlName="comments" [placeholder]="'commandComments' | translate">
</mat-form-field>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'selectOrganizationalUnit' | translate }}</mat-label>
<mat-select formControlName="organizationalUnit" required>
<mat-option *ngFor="let ou of organizationalUnits" [value]="ou['@id']">
{{ ou.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'selectOperativeSystem' | translate }}</mat-label>
<mat-select formControlName="operativeSystem">
@ -33,11 +25,13 @@
<mat-tab label="Seleccionar Software">
<div class="form-group">
<p class="software-tab-hint">{{ 'selectSoftwareHint' | translate }}</p>
<mat-form-field appearance="fill" class="full-width">
<input type="text" matInput [formControl]="softwareControl" [matAutocomplete]="clientAuto"
[placeholder]="'selectSoftwareToAdd' | translate">
<mat-autocomplete #clientAuto="matAutocomplete" [displayWith]="displayFnClient"
<mat-autocomplete #clientAuto="matAutocomplete" [displayWith]="displayFnClient" autoActiveFirstOption
(optionSelected)="onOptionClientSelected($event.option.value)">
<mat-option *ngFor="let software of filteredSoftware | async" [value]="software">
@ -46,9 +40,17 @@
</mat-autocomplete>
</mat-form-field>
<div class="software-list-header">
<span>{{ 'selectedSoftwareCount' | translate: { count: selectedSoftwares.length } }}</span>
<button type="button" class="clear-selection-link" *ngIf="selectedSoftwares.length"
(click)="clearSelectedSoftwares()">
{{ 'clearAll' | translate }}
</button>
</div>
<div class="software-list">
<mat-list>
<mat-list-item *ngFor="let software of softwareCollection">
<mat-list-item *ngFor="let software of selectedSoftwares">
{{ software.name }}
<button mat-icon-button (click)="removeSoftware(software)">
<mat-icon>delete</mat-icon>

View File

@ -1,7 +1,7 @@
import { inject } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Component, Inject, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { ToastrService } from 'ngx-toastr';
@ -21,11 +21,8 @@ export class CreateSoftwareProfileComponent implements OnInit {
baseUrl: string;
private apiUrl: string;
formGroup: FormGroup;
softwareCollection: any[] = [];
organizationalUnits: any[] = [];
operativeSystems: any[] = [];
softwareProfileId: string | null = null;
selectedSoftware: any;
selectedSoftwares: any[] = [];
softwareControl = new FormControl();
filteredSoftware!: Observable<any[]>;
@ -45,7 +42,6 @@ export class CreateSoftwareProfileComponent implements OnInit {
this.formGroup = this.fb.group({
description: [''],
comments: [''],
organizationalUnit: [null, Validators.required],
operativeSystem: [null]
});
}
@ -54,10 +50,9 @@ export class CreateSoftwareProfileComponent implements OnInit {
if (this.data) {
this.softwareProfileId = this.data['@id'];
this.patchFormData();
this.loadSoftware();
}
this.loadSoftware();
this.loadOrganizationalUnits();
this.loadOperativeSystems();
this.filteredSoftware = this.softwareControl.valueChanges.pipe(
@ -71,15 +66,14 @@ export class CreateSoftwareProfileComponent implements OnInit {
this.formGroup.patchValue({
description: this.data.description || '',
comments: this.data.comments || '',
organizationalUnit: this.data.organizationalUnit ? this.data.organizationalUnit['@id'] : null,
operativeSystem: this.data.operativeSystem ? this.data.operativeSystem['@id'] : null,
});
}
loadSoftware() {
this.http.get<any>(`${this.baseUrl}/software?softwareProfileId=${this.data.id}&page=1&itemsPerPage=10`).subscribe(
this.http.get<any>(`${this.baseUrl}/software?softwareProfileId=${this.data.id}&page=1&itemsPerPage=1000`).subscribe(
response => {
this.softwareCollection = response['hydra:member'];
this.selectedSoftwares = response['hydra:member'];
},
error => {
console.error(this.translate.instant('softwareFetchingError'), error);
@ -87,17 +81,6 @@ export class CreateSoftwareProfileComponent implements OnInit {
);
}
loadOrganizationalUnits() {
this.http.get<any>(`${this.baseUrl}/organizational-units?page=1&itemsPerPage=10000`).subscribe(
response => {
this.organizationalUnits = response['hydra:member'];
},
error => {
console.error(this.translate.instant('errorFetchingOrganizationalUnits1'), error);
}
);
}
loadOperativeSystems() {
this.http.get<any>(`${this.baseUrl}/operative-systems?page=1&itemsPerPage=10000`).subscribe(
response => {
@ -110,33 +93,36 @@ export class CreateSoftwareProfileComponent implements OnInit {
}
private _filterSoftware(value: string): Observable<any[]> {
return this.softwareDataService.getSoftwareCollection({ name: value }).pipe(
map(response => response || [])
const filters = { name: value || '', itemsPerPage: '15' };
return this.softwareDataService.getSoftwareCollection(filters).pipe(
map(response => (response || []).filter(software => !this.isSelected(software)))
);
}
isSelected(software: any): boolean {
return this.selectedSoftwares.some(s => s.id === software.id);
}
displayFnClient(client: any): string {
return client && client.name ? client.name : '';
}
onOptionClientSelected(software: any) {
if (!this.selectedSoftwares.find(s => s.id === software.id)) {
if (!this.isSelected(software)) {
this.selectedSoftwares.push(software);
}
this.softwareControl.setValue('');
}
addSoftware() {
const software = this.softwareCollection.find(s => s.id === this.selectedSoftware);
if (software && !this.selectedSoftwares.includes(software)) {
this.selectedSoftwares.push(software);
}
}
removeSoftware(software: any) {
this.selectedSoftwares = this.selectedSoftwares.filter(s => s.id !== software.id);
}
clearSelectedSoftwares(): void {
this.selectedSoftwares = [];
}
onCancel(event: Event): void {
event.preventDefault();
this.dialogRef.close();
@ -148,7 +134,6 @@ export class CreateSoftwareProfileComponent implements OnInit {
description: this.formGroup.value.description,
comments: this.formGroup.value.comments,
softwareCollection: this.selectedSoftwares.map(s => s['@id']),
organizationalUnit: this.formGroup.value.organizationalUnit,
operativeSystem: this.formGroup.value.operativeSystem
};

View File

@ -65,6 +65,7 @@
"advancedParameters": "Paràmetres avançats",
"all": "Tots",
"allowedOrganizationalUnits": "Unitats Organitzacionals Permeses",
"andMoreClients": "i {{count}} més",
"anErrorOccurredWhileLoading": "S'ha produït un error en carregar les unitats organitzatives",
"apiPort": "Port API",
"application": "Aplicació",
@ -211,6 +212,7 @@
"classroomStatusUpdated": "Estat de l'aula actualitzat",
"classroomTitle": "Aula",
"classroomWillBe": "L'aula estarà",
"clearAll": "Treure tots",
"clearClientSearch": "Netejar cerca de client",
"clearInputSearch": "Netejar cerca",
"clearTreeSearch": "Netejar cerca a l'arbre",
@ -235,6 +237,7 @@
"clientOff": "Client apagat",
"clientOgLive": "Client OGLive",
"clientPropertiesTitle": "Propietats del client",
"clients": "Clients",
"clientSelectStepText": "Selecciona un client per veure les traces associades.",
"clientsPerPage": "Clients per pàgina",
"clientsPerPageHint": "Nombre de clients mostrats per pàgina al llistat",
@ -1017,6 +1020,7 @@
"noFilesInDirectory": "No hi ha fitxers en aquest directori",
"noGitInfoForPartition": "No s'ha trobat informació de Git per a aquesta partició",
"noHardwareAssociatedToProfile": "No hi ha maquinari associat a aquest perfil",
"noHardwareProfileAssigned": "Aquest client no té cap perfil de maquinari assignat",
"noInternalElementsMessage": "No hi ha elements interns",
"noLogsAvailable": "noLogsAvailable",
"noOgLivesInServer": "No hi ha OgLives en aquest servidor",
@ -1029,6 +1033,7 @@
"noReposAvailableCreateNew": "No hi ha repositoris disponibles. Crea un de nou per continuar.",
"noResultsMessage": "No hi ha resultats per mostrar.",
"noSavedScripts": "No hi ha scripts desats disponibles",
"noSoftwareProfileAssigned": "Sense perfil de programari assignat",
"notAccessible": "No accessible",
"noTags": "Sense etiquetes",
"notAvailableLowercase": "no disponible",
@ -1266,6 +1271,7 @@
"selectedClients": "Clients seleccionats",
"selectedClientsTitle": "Clients seleccionats:",
"selectedCommandsTitle": "Comandaments Seleccionats",
"selectedSoftwareCount": "{{count}} programari afegit",
"selectGitRepoHint": "Selecciona el repositori git per obtenir les imatges disponibles.",
"selectGitRepoOs": "Seleccionar repositori git / SO",
"selectGitRepository": "Seleccionar repositori Git",
@ -1286,6 +1292,7 @@
"selectRepoToView": "Tria un repositori de la llista per veure el seu estat detallat.",
"selectScriptToRun": "Seleccioni script a executar",
"selectScriptToView": "Tria un script desat de la llista per veure el seu contingut i configurar paràmetres.",
"selectSoftwareHint": "Escriu per cercar i prem Retorn o fes clic per afegir-lo. El camp s'esborra automàticament perquè puguis continuar afegint programari sense interrupcions.",
"selectSoftwareToAdd": "Seleccioni programari per afegir",
"selectTask": "Seleccioni una tasca",
"selectTemplateDescription": "Seleccioni plantilla",

View File

@ -65,6 +65,7 @@
"advancedParameters": "Advanced parameters",
"all": "All",
"allowedOrganizationalUnits": "Allowed Organizational Units",
"andMoreClients": "and {{count}} more",
"anErrorOccurredWhileLoading": "An error occurred while loading the organizational units",
"apiPort": "API Port",
"application": "Application",
@ -211,6 +212,7 @@
"classroomStatusUpdated": "Classroom status updated",
"classroomTitle": "Classroom",
"classroomWillBe": "The classroom will be",
"clearAll": "Clear all",
"clearClientSearch": "Clear client search",
"clearInputSearch": "Clear input search",
"clearTreeSearch": "Clear tree search",
@ -235,6 +237,7 @@
"clientOff": "Client off",
"clientOgLive": "OGLive client",
"clientPropertiesTitle": "Client properties",
"clients": "Clients",
"clientSelectStepText": "Select a client to see the associated traces.",
"clientsPerPage": "Clients per page",
"clientsPerPageHint": "Number of clients shown per page in the list",
@ -1017,7 +1020,7 @@
"noFilesInDirectory": "There are no files in this directory",
"noGitInfoForPartition": "No Git information found for this partition",
"noHardwareAssociatedToProfile": "There is no hardware associated with this profile",
"noHardwareProfileAssigned": "This client does not have its own hardware profile assigned",
"noHardwareProfileAssigned": "This client does not have any hardware profile assigned",
"noInternalElementsMessage": "No internal elements",
"noLogsAvailable": "noLogsAvailable",
"noOgLivesInServer": "There are no OgLives on this server",
@ -1030,6 +1033,7 @@
"noReposAvailableCreateNew": "No repositories available. Create a new one to continue.",
"noResultsMessage": "No results to display.",
"noSavedScripts": "No saved scripts available",
"noSoftwareProfileAssigned": "No software profile assigned",
"notAccessible": "Not accessible",
"noTags": "No tags",
"notAvailableLowercase": "not available",
@ -1267,6 +1271,7 @@
"selectedClients": "Selected clients",
"selectedClientsTitle": "Selected clients:",
"selectedCommandsTitle": "Selected Commands",
"selectedSoftwareCount": "{{count}} software added",
"selectGitRepoHint": "Select the git repository to get available images.",
"selectGitRepoOs": "Select git repository / OS",
"selectGitRepository": "Select Git repository",
@ -1287,6 +1292,7 @@
"selectRepoToView": "Select a repository from the list to view its detailed status.",
"selectScriptToRun": "Select script to run",
"selectScriptToView": "Select a saved script from the list to view its content and configure parameters.",
"selectSoftwareHint": "Type to search and press Enter or click to add it. The field clears automatically so you can keep adding software without interruptions.",
"selectSoftwareToAdd": "Select software to add",
"selectTask": "Select a task",
"selectTemplateDescription": "Select template description",

View File

@ -65,6 +65,7 @@
"advancedParameters": "Parámetros avanzados",
"all": "Todos",
"allowedOrganizationalUnits": "Unidades Organizacionales Permitidas",
"andMoreClients": "y {{count}} más",
"anErrorOccurredWhileLoading": "Ocurrió un error al cargar las unidades organizativas",
"apiPort": "Puerto API",
"application": "Aplicacion",
@ -211,6 +212,7 @@
"classroomStatusUpdated": "Estado del aula actualizado",
"classroomTitle": "Aula",
"classroomWillBe": "El aula estará",
"clearAll": "Quitar todos",
"clearClientSearch": "Limpiar búsqueda de cliente",
"clearInputSearch": "Limpiar búsqueda",
"clearTreeSearch": "Limpiar búsqueda en el árbol",
@ -235,6 +237,7 @@
"clientOff": "Cliente apagado",
"clientOgLive": "Cliente OGLive",
"clientPropertiesTitle": "Propiedades del cliente",
"clients": "Clientes",
"clientSelectStepText": "Selecciona un cliente para ver las trazas asociadas.",
"clientsPerPage": "Clientes por página",
"clientsPerPageHint": "Número de clientes mostrados por página en el listado",
@ -1017,7 +1020,7 @@
"noFilesInDirectory": "No hay archivos en este directorio",
"noGitInfoForPartition": "No se encontró información de Git para esta partición",
"noHardwareAssociatedToProfile": "No hay hardware asociado a este perfil",
"noHardwareProfileAssigned": "Este cliente no tiene un perfil de hardware propio asignado",
"noHardwareProfileAssigned": "Este cliente no tiene ningún perfil de hardware asignado",
"noInternalElementsMessage": "No hay elementos internos",
"noLogsAvailable": "noLogsAvailable",
"noOgLivesInServer": "No hay OgLives en este servidor",
@ -1030,6 +1033,7 @@
"noReposAvailableCreateNew": "No hay repositorios disponibles. Crea uno nuevo para continuar.",
"noResultsMessage": "No hay resultados para mostrar.",
"noSavedScripts": "No hay scripts guardados disponibles",
"noSoftwareProfileAssigned": "Sin perfil de software asignado",
"notAccessible": "No accesible",
"noTags": "Sin tags",
"notAvailableLowercase": "no disponible",
@ -1267,6 +1271,7 @@
"selectedClients": "Clientes seleccionados",
"selectedClientsTitle": "Clientes seleccionados:",
"selectedCommandsTitle": "Comandos Seleccionados",
"selectedSoftwareCount": "{{count}} programas añadidos",
"selectGitRepoHint": "Selecciona el repositorio git para obtener las imágenes disponibles.",
"selectGitRepoOs": "Seleccionar repositorio git / SO",
"selectGitRepository": "Seleccionar repositorio Git",
@ -1287,6 +1292,7 @@
"selectRepoToView": "Elige un repositorio de la lista para ver su estado detallado.",
"selectScriptToRun": "Seleccione script a ejecutar",
"selectScriptToView": "Elige un script guardado de la lista para ver su contenido y configurar parámetros.",
"selectSoftwareHint": "Escribe para buscar y pulsa Enter o haz clic para añadir. El campo se vacía automáticamente para que puedas seguir añadiendo software sin interrupciones.",
"selectSoftwareToAdd": "Seleccione software para añadir",
"selectTask": "Seleccione una tarea",
"selectTemplateDescription": "Seleccione plantilla",