diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html b/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html index ab7ea88705be8d60d991cb9f50736aafc851f1a8..f71da37b73284f6af6c4db060b6fa51ba2cce6f8 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html @@ -10,7 +10,13 @@ <div [formGroupName]="UserFormService.ADMINISTRATION_GROUP" class="flex flex-1 flex-col gap-2"> <h3 class="text-md block font-medium text-text">Administration</h3> <div class="flex items-center gap-2"> - <ods-checkbox-editor [formControlName]="UserFormService.ADMIN" label="Admin" inputId="admin" /> + <ods-checkbox-editor + [formControlName]="UserFormService.ADMIN" + (inputChange)="removeCheckboxError()" + data-test-id="checkbox-admin" + label="Admin" + inputId="admin" + /> <button data-test-id="admin-role-info-button" tooltip="Diese Rolle kann Funktionen der OZG-Cloud konfigurieren, z.B. Benutzer anlegen, Organisationseinheiten hinzufügen und Rollen zuweisen." @@ -21,6 +27,8 @@ <div class="flex items-center gap-2"> <ods-checkbox-editor [formControlName]="UserFormService.DATENBEAUFTRAGUNG" + (inputChange)="removeCheckboxError()" + data-test-id="checkbox-datenbeauftragung" label="Datenbeauftragung" inputId="datenbeauftragung" /> diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.spec.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.spec.ts index a394794c4de41ee105285b9e11c1503ce7864d68..8bd40289a895f00859b5e8e09dacfefa60f08a86 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.spec.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.spec.ts @@ -107,6 +107,14 @@ describe('UserFormRolesComponent', () => { expect(formService.updateAlfaCheckboxes).toHaveBeenCalledWith(formControlName, value); }); }); + + describe('remove checkbox error', () => { + it('should call form service removeCheckboxError', () => { + component.removeCheckboxError(); + + expect(formService.removeCheckboxError).toHaveBeenCalled(); + }); + }); }); describe('template', () => { @@ -129,6 +137,36 @@ describe('UserFormRolesComponent', () => { }); }); + describe('checkbox admin', () => { + it('should call removeCheckboxError on inputChange emit', () => { + component.removeCheckboxError = jest.fn(); + + triggerEvent({ + fixture, + elementSelector: getDataTestIdOf('checkbox-admin'), + name: 'inputChange', + data: true, + }); + + expect(component.removeCheckboxError).toHaveBeenCalled(); + }); + }); + + describe('checkbox datenbeauftragung', () => { + it('should call removeCheckboxError on inputChange emit', () => { + component.removeCheckboxError = jest.fn(); + + triggerEvent({ + fixture, + elementSelector: getDataTestIdOf('checkbox-datenbeauftragung'), + name: 'inputChange', + data: true, + }); + + expect(component.removeCheckboxError).toHaveBeenCalled(); + }); + }); + describe('checkbox loeschen', () => { it('should call updateOtherAlfaCheckboxes on inputChange emit', () => { component.updateAlfaCheckboxes = jest.fn(); diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.ts b/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.ts index 0a0ff53228b6f573bfedf71e388d49677359a061..79e41b9b0e57aefae57261971f34f36f9a74a928 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.ts @@ -43,4 +43,8 @@ export class UserFormRolesComponent implements OnInit { updateAlfaCheckboxes(formControlName: string, value: boolean) { this.formService.updateAlfaCheckboxes(formControlName, value); } + + removeCheckboxError() { + this.formService.removeCheckboxError(); + } } diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts index 71f4fffde321b879a76111d565f31e603d623d5c..73e57e188c214681d27323a19d7d63f1ec8bddb1 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts @@ -229,18 +229,18 @@ describe('UserFormService', () => { describe('handleAlfaGroupChange', () => { it('should call disableUncheckedCheckboxes if any checkbox is checked', () => { - service._isAnyChecked = jest.fn().mockReturnValue(true); - service._disableUncheckedCheckboxes = jest.fn(); + service._isAnyAlfaCheckboxChecked = jest.fn().mockReturnValue(true); + service._disableUncheckedAlfaCheckboxes = jest.fn(); service._disableAlfaCheckboxes(); - expect(service._disableUncheckedCheckboxes).toHaveBeenCalled(); + expect(service._disableUncheckedAlfaCheckboxes).toHaveBeenCalled(); }); }); - describe('isAnyChecked', () => { + describe('isAnyAlfaCheckboxChecked', () => { it('should return false if no checkbox is checked', () => { - const result = service._isAnyChecked(alfaGroup); + const result = service._isAnyAlfaCheckboxChecked(); expect(result).toBe(false); }); @@ -248,18 +248,18 @@ describe('UserFormService', () => { it('should return true if any checkbox is checked', () => { alfaGroup.get(UserFormService.LOESCHEN).setValue(true); - const result = service._isAnyChecked(alfaGroup); + const result = service._isAnyAlfaCheckboxChecked(); expect(result).toBe(true); }); }); - describe('disableUncheckedCheckboxes', () => { + describe('disableUncheckedAlfaCheckboxes', () => { it('if control value is false then control should be disabled', () => { const control: AbstractControl = alfaGroup.get(UserFormService.LOESCHEN); control.setValue(false); - service._disableUncheckedCheckboxes(alfaGroup); + service._disableUncheckedAlfaCheckboxes(); expect(control.disabled).toBe(true); }); @@ -268,7 +268,7 @@ describe('UserFormService', () => { const control: AbstractControl = alfaGroup.get(UserFormService.LOESCHEN); control.setValue(true); - service._disableUncheckedCheckboxes(alfaGroup); + service._disableUncheckedAlfaCheckboxes(); expect(control.disabled).toBe(false); }); @@ -279,7 +279,7 @@ describe('UserFormService', () => { const control: AbstractControl = alfaGroup.get(UserFormService.LOESCHEN); control.setValue(false); - service._disableUncheckedCheckboxes(alfaGroup); + service._disableUncheckedAlfaCheckboxes(); expect(control.disabled).toBe(true); }); @@ -294,22 +294,30 @@ describe('UserFormService', () => { expect(control.value).toBe(true); }); - it('should call disableUncheckedCheckboxes', () => { - service._disableUncheckedCheckboxes = jest.fn(); + it('should call removeCheckboxError', () => { + service.removeCheckboxError = jest.fn(); service.updateAlfaCheckboxes(UserFormService.LOESCHEN, true); - expect(service._disableUncheckedCheckboxes).toHaveBeenCalledWith( - service.form.get(UserFormService.CLIENT_ROLES).get(UserFormService.ALFA_GROUP), - ); + expect(service.removeCheckboxError).toHaveBeenCalled(); + }); + + it('should call disableAlfaCheckboxes', () => { + service._disableAlfaCheckboxes = jest.fn(); + + service.updateAlfaCheckboxes(UserFormService.LOESCHEN, true); + + expect(service._disableAlfaCheckboxes).toHaveBeenCalled(); }); + }); - it('should call enableAllAlfaCheckboxes if value is false', () => { - service._enableAllAlfaCheckboxes = jest.fn(); + describe('removeCheckboxError', () => { + it('should remove error on clientRoles group', () => { + roleGroup.setErrors({ error: 'Client Roles Error' }); - service.updateAlfaCheckboxes(UserFormService.LOESCHEN, false); + service.removeCheckboxError(); - expect(service._enableAllAlfaCheckboxes).toHaveBeenCalled(); + expect(roleGroup.errors).toBeNull(); }); }); @@ -361,7 +369,7 @@ describe('UserFormService', () => { userService.create.mockReturnValue(of(createEmptyStateResource(true))); const handleOnCreateUserSuccessSpy: SpyInstance = jest.spyOn(service, 'handleOnCreateUserSuccess'); - service.submit().subscribe(); + service._doSubmit().subscribe(); tick(); expect(handleOnCreateUserSuccessSpy).not.toHaveBeenCalled(); diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts index 0e89e82cec35b44a352c32da15c82a23631ca0a0..e7795f858b47a1b4d3b1d8fd4724c709e7030e2f 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts @@ -162,33 +162,37 @@ export class UserFormService extends KeycloakFormService<User> implements OnDest }); } - _disableAlfaCheckboxes(): void { - const alfaGroup: UntypedFormGroup = this.getRoleGroup(UserFormService.ALFA_GROUP); - const anyChecked: boolean = this._isAnyChecked(alfaGroup); - if (anyChecked) { - this._disableUncheckedCheckboxes(alfaGroup); - } + updateAlfaCheckboxes(formControlName: string, value: boolean) { + this.setControlValueInAlfa(formControlName, value); + this.removeCheckboxError(); + this._disableAlfaCheckboxes(); } - _isAnyChecked(group: UntypedFormGroup): boolean { - return Object.keys(group.controls).some((key) => group.controls[key].value); + private setControlValueInAlfa(formControlName: string, value: boolean): void { + this.getRoleGroup(UserFormService.ALFA_GROUP).get(formControlName).setValue(value, { emitEvent: false }); } - _disableUncheckedCheckboxes(alfaGroup: UntypedFormGroup): void { - for (const control of Object.values<AbstractControl>(alfaGroup.controls)) { - if (!control.value) this.disableCheckbox(control); + removeCheckboxError() { + this.form.get(UserFormService.CLIENT_ROLES).setErrors(null); + } + + _disableAlfaCheckboxes(): void { + if (this._isAnyAlfaCheckboxChecked()) { + this._disableUncheckedAlfaCheckboxes(); + } else { + this._enableAllAlfaCheckboxes(); } } - updateAlfaCheckboxes(formControlName: string, value: boolean) { + _isAnyAlfaCheckboxChecked(): boolean { const alfaGroup: UntypedFormGroup = this.getRoleGroup(UserFormService.ALFA_GROUP); - this.setControlValueInGroup(alfaGroup, formControlName, value); - this._disableUncheckedCheckboxes(alfaGroup); - if (!value) this._enableAllAlfaCheckboxes(); + return Object.keys(alfaGroup.controls).some((key) => alfaGroup.controls[key].value); } - private setControlValueInGroup(group: UntypedFormGroup, formControlName: string, value: boolean): void { - group.get(formControlName).setValue(value, { emitEvent: false }); + _disableUncheckedAlfaCheckboxes(): void { + for (const control of Object.values<AbstractControl>(this.getRoleGroup(UserFormService.ALFA_GROUP).controls)) { + if (!control.value) this.disableCheckbox(control); + } } _enableAllAlfaCheckboxes() { diff --git a/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.spec.ts b/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.spec.ts index e14da6e4b83e4d1960ad1af78c6c13a6eb381b73..c12275820fa45999a9674b1cb5d811c81dd94e22 100644 --- a/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.spec.ts +++ b/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.spec.ts @@ -1,14 +1,7 @@ import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - FormGroup, - FormGroupDirective, - ReactiveFormsModule, - UntypedFormControl, - UntypedFormGroup, - ValidationErrors, -} from '@angular/forms'; +import { FormGroupDirective, ReactiveFormsModule, ValidationErrors } from '@angular/forms'; import { FormControlEditorAbstractComponent } from '@ods/component'; import { MockNgControl } from '../../../test/form/MockNgControl'; @@ -104,43 +97,6 @@ describe('FormControlEditorAbstractComponent', () => { expect(component._updateInvalidParams).toHaveBeenCalled(); }); - - it('should call clear all parent controls', () => { - component._clearAllParentErrors = jest.fn(); - - component._removeErrors(); - - expect(component._clearAllParentErrors).toHaveBeenCalledWith(component.control.control); - }); - }); - - describe('clear all parent errors', () => { - const parentControl: UntypedFormGroup = new FormGroup({ child: new UntypedFormControl() }); - const childControl: UntypedFormControl = <UntypedFormControl>parentControl.get('child'); - - it('should set errors to null on parent control if parent exists', () => { - const setErrorsSpy: jest.SpyInstance = jest.spyOn(parentControl, 'setErrors'); - - component._clearAllParentErrors(childControl); - - expect(setErrorsSpy).toHaveBeenCalledWith(null); - }); - - it('should call clear all parent errors if parent exists', () => { - const clearAllParentsSpy: jest.SpyInstance = jest.spyOn(component, '_clearAllParentErrors'); - - component._clearAllParentErrors(childControl); - - expect(clearAllParentsSpy).toHaveBeenCalledWith(parentControl); - }); - - it('should not call clear all parent errors again if parent does not exist', () => { - const clearAllParentsSpy: jest.SpyInstance = jest.spyOn(component, '_clearAllParentErrors'); - - component._clearAllParentErrors(parentControl); - - expect(clearAllParentsSpy).toHaveBeenCalledTimes(1); - }); }); }); diff --git a/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.ts b/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.ts index 3e91b04d688d9969bdb842218e83b9af8a64e9fc..17f8e719998fe87a809421fe13d2680361ed3d07 100644 --- a/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.ts +++ b/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.ts @@ -23,7 +23,7 @@ */ import { InvalidParam } from '@alfa-client/tech-shared'; import { Component, OnDestroy, OnInit, Optional, Self } from '@angular/core'; -import { AbstractControl, ControlValueAccessor, NgControl, UntypedFormControl } from '@angular/forms'; +import { ControlValueAccessor, NgControl, UntypedFormControl } from '@angular/forms'; import { Subscription } from 'rxjs'; @Component({ @@ -45,7 +45,7 @@ export abstract class FormControlEditorAbstractComponent implements ControlValue } ngOnInit(): void { - this._changesSubscr = this.fieldControl.valueChanges.subscribe(this._fieldControlOnChangeHandler); + this._changesSubscr = this.fieldControl.valueChanges.subscribe((value: unknown) => this._fieldControlOnChangeHandler(value)); if (this.control) { this._statusSubscr = this.control.statusChanges.subscribe(() => { @@ -96,16 +96,6 @@ export abstract class FormControlEditorAbstractComponent implements ControlValue this.fieldControl.setErrors(null); this._updateInvalidParams(); - this._clearAllParentErrors(this.control.control); - } - - _clearAllParentErrors(control: AbstractControl): void { - const parent: AbstractControl = control?.parent; - - if (!parent) return; - - parent.setErrors(null); - this._clearAllParentErrors(parent); } _updateInvalidParams(): void {