fix(ui): ensure ou-select globally uses IRIs and harden relational payloads
oggui-debian-package/pipeline/head This commit looks good Details
oggui-debian-package/pipeline/tag This commit looks good Details
testing/ogGui-multibranch/pipeline/head There was a failure building this commit Details

main
Juan Manuel Bardallo 2026-10-06 14:38:29 +02:00
parent 0333a3a894
commit 91429f7b40
5 changed files with 11 additions and 6 deletions

View File

@ -3,6 +3,7 @@
## [1.14.1] - 2026-10-06
### Fixed
- **UI/UX (Componentes Genéricos)**: Refactorizado el comportamiento de `app-ou-select` para que devuelva siempre el identificador URI (`@id`) de la unidad organizativa en lugar de su ID numérico. Esto corrige varios errores críticos en cadena (como el error al mover clientes o añadir clientes a subredes de DHCP) provocados porque la API de Symfony (API Platform) requiere referencias URI (`/api/organizational_units/X`) para mapear entidades relacionales, en vez de identificadores enteros puros.
- **DHCP Subnets**: Solucionado un error al añadir equipos a una subred donde la petición al servidor enviaba la unidad organizativa como "undefined", impidiendo listar los equipos del aula seleccionada.
## [1.14.0] - 2026-10-05

View File

@ -52,9 +52,12 @@ export class ChangeParentComponent implements OnInit {
}
save() {
const selectedUnit = this.units.find(u => u.id === this.newOU || u['@id'] === this.newOU);
const unitIri = selectedUnit ? selectedUnit['@id'] : (typeof this.newOU === 'number' ? `/api/organizational_units/${this.newOU}` : this.newOU);
this.http.post<any>(`${this.baseUrl}/clients/change-organizational-unit`, {
clients: this.data.clients.map((client: any) => client['@id']),
organizationalUnit: this.newOU
organizationalUnit: unitIri
}).subscribe({
next: (response) => {
this.toastService.success(this.translate.instant('parentChangedSuccessfully'));

View File

@ -65,7 +65,8 @@ export class AddClientsToSubnetComponent implements OnInit {
loadChildUnits(event: any) {
this.http.get<any>(`${this.baseUrl}/clients?organizationalUnit.id=${event.value}&exists[subnet]=false`).subscribe(
const unitId = typeof event.value === 'string' && event.value.includes('/') ? event.value.split('/').pop() : event.value;
this.http.get<any>(`${this.baseUrl}/clients?organizationalUnit.id=${unitId}&exists[subnet]=false`).subscribe(
response => {
this.clients = response['hydra:member'];
},

View File

@ -9,8 +9,8 @@
<input type="text" class="dropdown-search-input" [(ngModel)]="searchText" (keydown)="$event.stopPropagation()"
placeholder="{{ 'labelSearch' | translate }}">
</div>
@for (unit of filteredUnits; track (unit.id || unit['@id'])) {
<mat-option [value]="unit.id || unit['@id']">
@for (unit of filteredUnits; track (unit['@id'] || unit.id)) {
<mat-option [value]="unit['@id'] || unit.id">
<div class="unit-name">{{ unit.name }}</div>
@if (unit.path) {
<div style="font-size: smaller; color: gray;">{{ unit.path }}</div>

View File

@ -69,9 +69,9 @@ export class OuSelectComponent implements ControlValueAccessor {
getSelectedName(): string {
if (this.multiple) {
if (!this.value || !Array.isArray(this.value)) return '';
return this.units.filter(u => this.value.includes(u.id || u['@id'])).map(u => u.name).join(', ');
return this.units.filter(u => this.value.includes(u['@id'] || u.id)).map(u => u.name).join(', ');
} else {
return this.units.find(u => (u.id || u['@id']) === this.value)?.name || '';
return this.units.find(u => (u['@id'] || u.id) === this.value)?.name || '';
}
}
}