diff --git a/lib/process-services-cloud/src/lib/group/components/group-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/group/components/group-cloud.component.spec.ts index 288f4986e9..2e4ce75776 100644 --- a/lib/process-services-cloud/src/lib/group/components/group-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/group/components/group-cloud.component.spec.ts @@ -102,6 +102,26 @@ describe('GroupCloudComponent', () => { }); }); + it('should not be able to search for a group that its name matches one of the preselected groups name', (done) => { + component.preSelectGroups = [{ name: mockIdentityGroups[0].name }]; + const changes = new SimpleChange(null, [{ name: mockIdentityGroups[0].name }], false); + component.ngOnChanges({ 'preSelectGroups': changes }); + fixture.detectChanges(); + + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'mock-group'; + inputHTMLElement.dispatchEvent(new Event('keyup')); + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(4); + done(); + }); + }); + it('should hide result list if input is empty', (done) => { fixture.detectChanges(); const inputHTMLElement: HTMLInputElement = element.querySelector('input'); diff --git a/lib/process-services-cloud/src/lib/group/components/group-cloud.component.ts b/lib/process-services-cloud/src/lib/group/components/group-cloud.component.ts index a611f895a0..0281a71326 100644 --- a/lib/process-services-cloud/src/lib/group/components/group-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/group/components/group-cloud.component.ts @@ -190,9 +190,12 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy { return typeof value === 'string'; }), tap((value) => { - this.searchedValue = value; - if (value) { + if (value.trim()) { + this.searchedValue = value; this.setTypingError(); + } else { + this.searchGroupsControl.markAsPristine(); + this.searchGroupsControl.markAsUntouched(); } }), tap(() => { @@ -238,7 +241,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy { } private isGroupAlreadySelected(group: IdentityGroupModel): boolean { - if (this.selectedGroups && this.selectedGroups.length > 0 && this.isMultipleMode()) { + if (this.selectedGroups && this.selectedGroups.length > 0) { const result = this.selectedGroups.find((selectedGroup: IdentityGroupModel) => { return selectedGroup.name === group.name; }); @@ -440,7 +443,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy { } private createSearchParam(value: string): IdentityGroupSearchParam { - const queryParams: IdentityGroupSearchParam = { name: value }; + const queryParams: IdentityGroupSearchParam = { name: value.trim() }; return queryParams; } diff --git a/lib/process-services-cloud/src/lib/people/components/people-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/people/components/people-cloud.component.spec.ts index 04e200295f..761116c76e 100644 --- a/lib/process-services-cloud/src/lib/people/components/people-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/people/components/people-cloud.component.spec.ts @@ -116,6 +116,66 @@ describe('PeopleCloudComponent', () => { }); }); + it('should not be able to search for a user that his username matches one of the preselected users username', (done) => { + component.preSelectUsers = [{ username: mockUsers[0].username }]; + const changes = new SimpleChange(null, [{ username: mockUsers[0].username }], false); + component.ngOnChanges({ 'preSelectUsers': changes }); + fixture.detectChanges(); + + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'first-name'; + inputHTMLElement.dispatchEvent(new Event('keyup')); + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(2); + done(); + }); + }); + + it('should not be able to search for a user that his id matches one of the preselected users id', (done) => { + component.preSelectUsers = [{ id: mockUsers[0].id }]; + const changes = new SimpleChange(null, [{ id: mockUsers[0].id }], false); + component.ngOnChanges({ 'preSelectUsers': changes }); + fixture.detectChanges(); + + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'first-name'; + inputHTMLElement.dispatchEvent(new Event('keyup')); + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(2); + done(); + }); + }); + + it('should not be able to search for a user that his email matches one of the preselected users email', (done) => { + component.preSelectUsers = [{ email: mockUsers[0].email }]; + const changes = new SimpleChange(null, [{ email: mockUsers[0].email }], false); + component.ngOnChanges({ 'preSelectUsers': changes }); + fixture.detectChanges(); + + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'first-name'; + inputHTMLElement.dispatchEvent(new Event('keyup')); + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(2); + done(); + }); + }); + it('should hide result list if input is empty', (done) => { fixture.detectChanges(); const inputHTMLElement: HTMLInputElement = element.querySelector('input'); @@ -133,7 +193,6 @@ describe('PeopleCloudComponent', () => { it('should selectedUser and changedUsers emit, update selected users when a user is selected', (done) => { const user = { username: 'username' }; fixture.detectChanges(); - spyOn(component, 'isPreselectedUserValid').and.returnValue(true); const selectEmitSpy = spyOn(component.selectUser, 'emit'); const changedUsersSpy = spyOn(component.changedUsers, 'emit'); component.onSelect(user); @@ -514,8 +573,6 @@ describe('PeopleCloudComponent', () => { it('should check validation only for the first user and emit warning when user is invalid - single mode', (done) => { spyOn(identityService, 'findUserById').and.returnValue(Promise.resolve([])); - spyOn(component, 'isPreselectedUserValid').and.returnValue(false); - const expectedWarning = { message: 'INVALID_PRESELECTED_USERS', users: [{ diff --git a/lib/process-services-cloud/src/lib/people/components/people-cloud.component.ts b/lib/process-services-cloud/src/lib/people/components/people-cloud.component.ts index 95ba2c5048..e97dbdf4c6 100644 --- a/lib/process-services-cloud/src/lib/people/components/people-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/people/components/people-cloud.component.ts @@ -189,16 +189,20 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy { filter((value) => { return typeof value === 'string'; }), - tap((value) => { - this.searchedValue = value; - if (value) { + tap((value: string) => { + if (value.trim()) { + this.searchedValue = value; this.setTypingError(); + } else { + this.searchUserCtrl.markAsPristine(); + this.searchUserCtrl.markAsUntouched(); } }), tap(() => { this.resetSearchUsers(); }), - switchMap((search) => this.identityUserService.findUsersByName(search)), + switchMap((search) => + this.identityUserService.findUsersByName(search.trim())), mergeMap((users) => { this.resetSearchUsers(); return users; @@ -259,10 +263,10 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy { map((filteredUser: { hasRole: boolean, user: IdentityUserModel }) => filteredUser.user)); } - private isUserAlreadySelected(user: IdentityUserModel): boolean { + private isUserAlreadySelected(searchUser: IdentityUserModel): boolean { if (this.selectedUsers && this.selectedUsers.length > 0) { const result = this.selectedUsers.find((selectedUser) => { - return selectedUser.id === user.id || selectedUser.email === user.email || selectedUser.username === user.username; + return this.compare(selectedUser, searchUser); }); return !!result; @@ -297,17 +301,17 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy { preselectedUsersToValidate = this.removeDuplicatedUsers(this.preSelectUsers); } - await Promise.all(preselectedUsersToValidate.map(async (user: IdentityUserModel) => { + await Promise.all(preselectedUsersToValidate.map(async (preselectedUser: IdentityUserModel) => { try { - const validationResult: IdentityUserModel = await this.searchUser(user); - if (this.isPreselectedUserValid(user, validationResult)) { - validationResult.readonly = user.readonly; - validUsers.push(validationResult); + const userValidationResult: IdentityUserModel = await this.searchUser(preselectedUser); + if (this.compare(preselectedUser, userValidationResult)) { + userValidationResult.readonly = preselectedUser.readonly; + validUsers.push(userValidationResult); } else { - this.invalidUsers.push(user); + this.invalidUsers.push(preselectedUser); } } catch (error) { - this.invalidUsers.push(user); + this.invalidUsers.push(preselectedUser); this.logService.error(error); } })); @@ -316,12 +320,16 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy { this.isLoading = false; } - isPreselectedUserValid(preselectedUser: IdentityUserModel, validatedUser: IdentityUserModel) { - if (validatedUser && (validatedUser.id !== undefined || validatedUser.username !== undefined || validatedUser.email !== undefined)) { - return preselectedUser.id === validatedUser.id || preselectedUser.username === validatedUser.username || preselectedUser.email === validatedUser.email; - } else { - return false; + compare(preselectedUser: IdentityUserModel, identityUser: IdentityUserModel): boolean { + if (preselectedUser && identityUser) { + const uniquePropertyIdentifiers = ['id', 'username', 'email']; + for (const property of Object.keys(preselectedUser)) { + if (preselectedUser[property] !== undefined && uniquePropertyIdentifiers.includes(property)) { + return preselectedUser[property] === identityUser[property]; + } + } } + return false; } async searchUser(user: IdentityUserModel) {