diff --git a/ogWebconsole/src/app/components/images/create-image/create-image.component.html b/ogWebconsole/src/app/components/images/create-image/create-image.component.html
index 26df815..f43bdc0 100644
--- a/ogWebconsole/src/app/components/images/create-image/create-image.component.html
+++ b/ogWebconsole/src/app/components/images/create-image/create-image.component.html
@@ -32,15 +32,6 @@
-
- {{ 'softwareProfile' | translate }}
-
-
- {{ profile.description }}
-
-
-
-
{{ 'labelRemotePc' | translate }}
diff --git a/ogWebconsole/src/app/components/images/create-image/create-image.component.ts b/ogWebconsole/src/app/components/images/create-image/create-image.component.ts
index 99ff396..ae5600c 100644
--- a/ogWebconsole/src/app/components/images/create-image/create-image.component.ts
+++ b/ogWebconsole/src/app/components/images/create-image/create-image.component.ts
@@ -18,7 +18,6 @@ export class CreateImageComponent implements OnInit {
baseUrl: string;
imageForm: FormGroup;
imageId: string | null = null;
- softwareProfiles: any[] = [];
repositories: any[] = [];
loading: boolean = false;
isEditMode: boolean = false;
@@ -41,7 +40,6 @@ export class CreateImageComponent implements OnInit {
comments: [''],
remotePc: [false],
isGlobal: [false],
- softwareProfile: [''],
imageRepositories: [[], Validators.required],
});
}
@@ -54,7 +52,6 @@ export class CreateImageComponent implements OnInit {
} else {
this.loading = false;
}
- this.fetchSoftwareProfiles();
this.fetchRepositories();
}
@@ -67,7 +64,6 @@ export class CreateImageComponent implements OnInit {
comments: response.comments,
remotePc: response.remotePc,
isGlobal: response.isGlobal,
- softwareProfile: response.softwareProfile ? response.softwareProfile['@id'] : null,
imageRepositories: response.imageRepositories ? response.imageRepositories.map((r: any) => r.imageRepository['@id']) : [],
});
this.imageId = response['@id'];
@@ -85,18 +81,6 @@ export class CreateImageComponent implements OnInit {
this.showWarning = this.imageForm.get('isGlobal')?.value;
}
- fetchSoftwareProfiles() {
- const url = `${this.baseUrl}/software-profiles`;
- this.http.get(url).subscribe({
- next: (response: any) => {
- this.softwareProfiles = response['hydra:member'];
- },
- error: (error) => {
- this.toastService.error(this.translate.instant('errorGettingProfiles'));
- }
- });
- }
-
fetchRepositories() {
const url = `${this.baseUrl}/image-repositories`;
this.http.get(url).subscribe({
@@ -117,7 +101,6 @@ export class CreateImageComponent implements OnInit {
remotePc: this.imageForm.value.remotePc,
isGlobal: this.imageForm.value.isGlobal,
imageRepositories: this.imageForm.value.imageRepositories,
- ...(this.imageForm.value.softwareProfile ? { softwareProfile: this.imageForm.value.softwareProfile } : {}),
};
if (this.imageId) {
diff --git a/ogWebconsole/src/app/components/repositories/show-monolitic-images/show-monolitic-images.component.css b/ogWebconsole/src/app/components/repositories/show-monolitic-images/show-monolitic-images.component.css
index 05c97d3..2f59c42 100644
--- a/ogWebconsole/src/app/components/repositories/show-monolitic-images/show-monolitic-images.component.css
+++ b/ogWebconsole/src/app/components/repositories/show-monolitic-images/show-monolitic-images.component.css
@@ -108,3 +108,36 @@ table {
margin: 0 auto;
align-self: center;
}
+
+.software-profile-select {
+ width: 150px;
+ font-size: 0.8em;
+}
+
+.software-profile-select ::ng-deep .mat-mdc-text-field-wrapper {
+ padding: 0 8px;
+}
+
+.software-profile-select ::ng-deep .mat-mdc-form-field-infix {
+ min-height: unset;
+ padding-top: 8px;
+ padding-bottom: 8px;
+}
+
+.software-profile-caret {
+ cursor: pointer;
+ color: rgba(0, 0, 0, 0.54);
+ font-size: 20px;
+ width: 20px;
+ height: 20px;
+}
+
+::ng-deep .software-profile-panel {
+ max-width: 320px;
+}
+
+::ng-deep .software-profile-panel .mat-mdc-option {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
diff --git a/ogWebconsole/src/app/components/repositories/show-monolitic-images/show-monolitic-images.component.html b/ogWebconsole/src/app/components/repositories/show-monolitic-images/show-monolitic-images.component.html
index df7b830..4e973a5 100644
--- a/ogWebconsole/src/app/components/repositories/show-monolitic-images/show-monolitic-images.component.html
+++ b/ogWebconsole/src/app/components/repositories/show-monolitic-images/show-monolitic-images.component.html
@@ -83,8 +83,25 @@
{{ getStatusLabel(image[column.columnDef]) }}
+
+
+
+
+ arrow_drop_down
+
+ {{ 'noSoftwareProfileAssigned' | translate }}
+
+ {{ profile.description }}
+
+
+
+
+
+ *ngIf="column.columnDef !== 'remotePc' && column.columnDef !== 'status' && column.columnDef !== 'isGlobal' && column.columnDef !== 'name' && column.columnDef !== 'datasize' && column.columnDef !== 'softwareProfile'">
{{ column.cell(image) }}
diff --git a/ogWebconsole/src/app/components/repositories/show-monolitic-images/show-monolitic-images.component.ts b/ogWebconsole/src/app/components/repositories/show-monolitic-images/show-monolitic-images.component.ts
index fa2ba97..8f89564 100644
--- a/ogWebconsole/src/app/components/repositories/show-monolitic-images/show-monolitic-images.component.ts
+++ b/ogWebconsole/src/app/components/repositories/show-monolitic-images/show-monolitic-images.component.ts
@@ -37,6 +37,7 @@ export class ShowMonoliticImagesComponent implements OnInit {
filters: { [key: string]: string } = {};
alertMessage: string | null = null;
repository: any = {};
+ softwareProfiles: any[] = [];
datePipe: DatePipe = new DatePipe('es-ES');
columns = [
{
@@ -70,9 +71,9 @@ export class ShowMonoliticImagesComponent implements OnInit {
cell: (image: any) => this.formatSize(image.datasize)
},
{
- columnDef: 'description',
- header: 'labelDescription',
- cell: (image: any) => image.description
+ columnDef: 'softwareProfile',
+ header: 'softwareProfile',
+ cell: (image: any) => image.softwareProfile ? image.softwareProfile['@id'] : null
},
{
columnDef: 'createdAt',
@@ -100,13 +101,63 @@ export class ShowMonoliticImagesComponent implements OnInit {
if (this.data) {
this.loadData();
}
+ this.loadSoftwareProfiles();
+ }
+
+ loadSoftwareProfiles(): void {
+ this.http.get(`${this.baseUrl}/software-profiles?page=1&itemsPerPage=10000`).subscribe({
+ next: (response) => {
+ this.softwareProfiles = response['hydra:member'];
+ },
+ error: (error) => {
+ console.error(this.translate.instant('errorGettingProfiles'), error);
+ }
+ });
+ }
+
+ filterProfiles(value: any): any[] {
+ const query = typeof value === 'string' ? value : (value?.description || '');
+ const normalized = query.toLowerCase();
+ return this.softwareProfiles.filter(profile => (profile.description || '').toLowerCase().includes(normalized));
+ }
+
+ displayProfile(value: any): string {
+ return value?.description || '';
+ }
+
+ onProfileSelected(image: any, selectedProfile: any | null): void {
+ const previousProfile = image.softwareProfile;
+
+ // Optimistic update: reflect the choice immediately so the blur/reset
+ // handler (which reads image.softwareProfile) doesn't race the PATCH
+ // response and briefly flash back to the old value.
+ image.softwareProfile = selectedProfile;
+ image.profileValue = selectedProfile;
+
+ this.http.patch(`${this.baseUrl}${image['@id']}`, { softwareProfile: selectedProfile ? selectedProfile['@id'] : null }).subscribe({
+ next: () => {
+ this.toastService.success(this.translate.instant('successfullyEditedSoftware'));
+ },
+ error: (error) => {
+ image.softwareProfile = previousProfile;
+ image.profileValue = previousProfile;
+ this.toastService.error(error.error['hydra:description']);
+ }
+ });
+ }
+
+ resetProfileSearchIfInvalid(image: any): void {
+ image.profileValue = image.softwareProfile || null;
}
loadData(): void {
this.loading = true;
this.http.get(`${this.apiUrl}?page=${this.page + 1}&itemsPerPage=${this.itemsPerPage}&repository.id=${this.data.repositoryId}`, { params: this.filters }).subscribe(
data => {
- this.dataSource.data = data['hydra:member'];
+ this.dataSource.data = (data['hydra:member'] || []).map((item: any) => ({
+ ...item,
+ profileValue: item.softwareProfile || null
+ }));
this.length = data['hydra:totalItems'];
this.loading = false;
},