fix(ui): ensure robust IRI extraction for organizationalUnit payloads
oggui-debian-package/pipeline/tag This commit looks good Details
testing/ogGui-multibranch/pipeline/head There was a failure building this commit Details
oggui-debian-package/pipeline/head This commit looks good Details

main 1.14.3
Juan Manuel Bardallo 2026-10-09 10:58:17 +02:00
parent 12bf0eb743
commit a57fa1fcfa
10 changed files with 63 additions and 11 deletions

View File

@ -1,5 +1,10 @@
# Changelog
## [1.14.3] - 2026-10-09
### Fixed
- **UI/UX (Componentes Genéricos)**: Solucionado un problema de regresión introducido en la versión 1.14.2 donde múltiples componentes de creación y edición (Crear/Editar Tarea, Usuarios, Aula, Cliente, Crear Múltiples Clientes y Mover Clientes) enviaban un identificador numérico en el payload en lugar del identificador URI (`@id`) esperado por el backend para las relaciones de `organizationalUnit`, provocando errores al intentar guardar. Ahora, estos componentes detectan automáticamente el identificador devuelto por el selector genérico y construyen la URI correcta antes de realizar la petición HTTP.
## [1.14.2] - 2026-10-06
### Fixed

View File

@ -122,9 +122,17 @@ export class AddUserModalComponent implements OnInit {
onSubmit(): void {
if (this.userForm.valid) {
const mappedOUs = (this.userForm.value.organizationalUnits || []).map((ou: any) => {
if (typeof ou === 'number' || (typeof ou === 'string' && !ou.includes('/'))) {
const selectedUnit = this.organizationalUnits.find((u: any) => u.id === Number(ou));
return selectedUnit ? (selectedUnit['@id'] || `/organizational-units/${selectedUnit.uuid}`) : ou;
}
return ou;
});
const payload: any = {
username: this.userForm.value.username,
allowedOrganizationalUnits: this.userForm.value.organizationalUnits,
allowedOrganizationalUnits: mappedOUs,
enabled: true,
userGroups: [this.userForm.value.role],
groupsView: this.userForm.value.groupsView,

View File

@ -281,7 +281,12 @@ export class CreateTaskComponent implements OnInit {
payload.clients = this.selectedClients.map(client => client['@id'] ? client['@id'] : client.uuid);
payload.organizationalUnit = null;
} else {
payload.organizationalUnit = formData.organizationalUnit;
let ou = formData.organizationalUnit;
if (typeof ou === 'number' || (typeof ou === 'string' && !ou.includes('/'))) {
const selectedUnit = this.availableOrganizationalUnits.find((u: any) => u.id === Number(ou));
ou = selectedUnit ? (selectedUnit['@id'] || `/organizational-units/${selectedUnit.uuid}`) : ou;
}
payload.organizationalUnit = ou;
}
if (this.editing) {

View File

@ -52,8 +52,11 @@ 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);
let unitIri = this.newOU;
if (typeof this.newOU === 'number' || (typeof this.newOU === 'string' && !this.newOU.includes('/'))) {
const selectedUnit = this.units.find(u => u.id === Number(this.newOU));
unitIri = selectedUnit ? (selectedUnit['@id'] || `/organizational-units/${selectedUnit.uuid}`) : this.newOU;
}
this.http.post<any>(`${this.baseUrl}/clients/change-organizational-unit`, {
clients: this.data.clients.map((client: any) => client['@id']),

View File

@ -130,9 +130,15 @@ export class CreateMultipleClientComponent implements OnInit {
let successCount = 0;
let errorMessages: string[] = [];
let ou = this.organizationalUnit;
if (typeof ou === 'number' || (typeof ou === 'string' && !ou.includes('/'))) {
const selectedUnit = this.parentUnits.find((u: any) => u.id === Number(ou));
ou = selectedUnit ? (selectedUnit['@id'] || `/organizational-units/${selectedUnit.uuid}`) : ou;
}
this.uploadedClients.forEach(client => {
const formData = {
organizationalUnit: this.organizationalUnit,
organizationalUnit: ou,
name: client.name || null,
mac: client.mac || null,
ip: client.ip || null,

View File

@ -345,7 +345,14 @@ export class ManageClientComponent implements OnInit {
onSubmit(): void {
if (this.clientForm.valid) {
const formData = this.clientForm.value;
const formData = { ...this.clientForm.value };
let ou = formData.organizationalUnit;
if (typeof ou === 'number' || (typeof ou === 'string' && !ou.includes('/'))) {
const selectedUnit = this.parentUnits.find((u: any) => u.id === Number(ou));
ou = selectedUnit ? (selectedUnit['@id'] || `/organizational-units/${selectedUnit.uuid}`) : ou;
}
formData.organizationalUnit = ou;
if (this.isEditMode) {
const putUrl = `${this.baseUrl}/clients/${this.data.uuid}`;

View File

@ -341,7 +341,11 @@ export class ManageOrganizationalUnitComponent implements OnInit {
}
private submitForm(propagate: boolean) {
const parentValue = this.generalFormGroup.value.parent;
let parentValue = this.generalFormGroup.value.parent;
if (typeof parentValue === 'number' || (typeof parentValue === 'string' && !parentValue.includes('/'))) {
const selectedUnit = this.parentUnits.find(u => u.id === Number(parentValue));
parentValue = selectedUnit ? (selectedUnit['@id'] || `/organizational-units/${selectedUnit.uuid}`) : parentValue;
}
const networkSettings = { ...this.networkSettingsFormGroup.value };

View File

@ -133,7 +133,14 @@ export class PxeBootFilesComponent implements OnInit {
}
loadChildUnits(event: any) {
this.selectedUnit = event.value;
let unitId = event.value;
if (typeof event.value === 'object' && event.value !== null) {
unitId = event.value.id;
} else if (typeof event.value === 'string' && event.value.includes('/')) {
unitId = event.value.split('/').pop();
}
this.selectedUnit = this.units.find(u => u.id == unitId || u['@id'] === event.value) || event.value;
this.refreshClientList();
}

View File

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

View File

@ -69,9 +69,10 @@ 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.path || u.name).join(', ');
} else {
return this.units.find(u => (u['@id'] || u.id) === this.value)?.name || '';
const selectedUnit = this.units.find(u => (u['@id'] || u.id) === this.value);
return selectedUnit ? (selectedUnit.path || selectedUnit.name) : '';
}
}
}