diff --git a/demo-shell/resources/i18n/en.json b/demo-shell/resources/i18n/en.json
index 268c079ac3..059f18ce4e 100644
--- a/demo-shell/resources/i18n/en.json
+++ b/demo-shell/resources/i18n/en.json
@@ -308,7 +308,11 @@
"APP_NAME": "Application Name",
"APP_FILTER_MODE": "Filter by application name",
"ROLE_FILTER_MODE": "Filter by role",
- "PRESELECT_VALIDATION": "Preselect validation"
+ "PRESELECT_VALIDATION": "Preselect validation",
+ "ALL_SELECTED_USERS": "All Selected Users",
+ "ALL_SELECTED_GROUPS": "All Selected Groups",
+ "INVALID_USERS": "Invalid Users",
+ "INVALID_GROUPS": "Invalid Groups"
},
"SETTINGS_CLOUD": {
"MULTISELECTION": "Multiselection",
diff --git a/demo-shell/src/app/components/cloud/people-groups-cloud-demo.component.html b/demo-shell/src/app/components/cloud/people-groups-cloud-demo.component.html
index 247bf07f54..b42ad00475 100644
--- a/demo-shell/src/app/components/cloud/people-groups-cloud-demo.component.html
+++ b/demo-shell/src/app/components/cloud/people-groups-cloud-demo.component.html
@@ -40,16 +40,29 @@
[appName]="peopleAppName"
[roles]="peopleRoles"
[title]="'ADF_TASK_LIST.START_TASK.FORM.LABEL.ASSIGNEE'"
- [mode]="peopleMode">
+ [mode]="peopleMode"
+ (selectUser)="onSelectUser($event)"
+ (warning)="onUsersWarning($event)">
+
{{ 'PEOPLE_GROUPS_CLOUD.ALL_SELECTED_USERS' | translate }}
person
- {{ item?.firstName }} {{ item?.lastName }}
+ {{item | fullName}}
+
+
0">
+
{{ 'PEOPLE_GROUPS_CLOUD.INVALID_USERS' | translate }} warning
+
+
+ person
+ {{invalidUser | fullName}}
+
+
+
@@ -86,19 +99,39 @@
Preselect: {{ DEFAULT_GROUP_PLACEHOLDER }}
+ {{
+ 'PEOPLE_GROUPS_CLOUD.PRESELECT_VALIDATION' | translate }}
+
{{ 'PEOPLE_GROUPS_CLOUD.ALL_SELECTED_GROUPS' | translate }}
group
{{ item.name }}
+
+
0">
+
{{ 'PEOPLE_GROUPS_CLOUD.INVALID_GROUPS' | translate }} warning
+
+
+ group
+ {{invalidGroup?.name}}
+
+
+
diff --git a/demo-shell/src/app/components/cloud/people-groups-cloud-demo.component.ts b/demo-shell/src/app/components/cloud/people-groups-cloud-demo.component.ts
index d353e2079d..6dd41084b9 100644
--- a/demo-shell/src/app/components/cloud/people-groups-cloud-demo.component.ts
+++ b/demo-shell/src/app/components/cloud/people-groups-cloud-demo.component.ts
@@ -18,7 +18,7 @@
import { Component, ViewEncapsulation } from '@angular/core';
import { PeopleCloudComponent, GroupCloudComponent } from '@alfresco/adf-process-services-cloud';
import { MatRadioChange, MatCheckboxChange } from '@angular/material';
-import { IdentityGroupModel } from '@alfresco/adf-core';
+import { IdentityGroupModel, IdentityUserModel } from '@alfresco/adf-core';
@Component({
selector: 'app-people-groups-cloud',
@@ -33,14 +33,17 @@ export class PeopleGroupCloudDemoComponent {
DEFAULT_PEOPLE_PLACEHOLDER: string = `[{"id": "1", email": "user@user.com", "firstName":"user", "lastName": "lastName", "username": "user"}]`;
peopleMode: string = PeopleCloudComponent.MODE_SINGLE;
- preSelectUsers: string[] = [];
+ preSelectUsers: IdentityUserModel[] = [];
+ invalidUsers: IdentityGroupModel[] = [];
peopleRoles: string[] = [];
peopleAppName: string;
peopleFilterMode: string = this.DEFAULT_FILTER_MODE;
peoplePreselectValidation: Boolean = false;
+ groupPreselectValidation = false;
groupMode: string = GroupCloudComponent.MODE_SINGLE;
preSelectGroup: IdentityGroupModel[] = [];
+ invalidGroups: IdentityGroupModel[] = [];
selectedGroupList: IdentityGroupModel[] = [];
groupRoles: string[];
groupAppName: string;
@@ -117,6 +120,25 @@ export class PeopleGroupCloudDemoComponent {
onChangePeopleValidation(event: MatCheckboxChange) {
this.peoplePreselectValidation = event.checked;
this.preSelectUsers = [...this.preSelectUsers];
+ if (!this.peoplePreselectValidation) {
+ this.invalidUsers = [];
+ }
+ }
+
+ onChangeGroupValidation(event: MatCheckboxChange) {
+ this.groupPreselectValidation = event.checked;
+ this.preSelectGroup = [...this.preSelectGroup];
+ if (!this.groupPreselectValidation) {
+ this.invalidGroups = [];
+ }
+ }
+
+ onGroupsWarning(warning: any) {
+ this.invalidGroups = warning.groups;
+ }
+
+ onUsersWarning(warning: any) {
+ this.invalidUsers = warning.users;
}
isStringArray(str: string) {
@@ -149,6 +171,12 @@ export class PeopleGroupCloudDemoComponent {
this.preSelectGroup = this.preSelectGroup.filter((value: any) => value.id !== group.id);
}
+ onSelectUser(user: IdentityUserModel) {
+ if (this.peopleMode === PeopleCloudComponent.MODE_MULTIPLE) {
+ this.preSelectUsers.push(user);
+ }
+ }
+
onSelectGroup(group: IdentityGroupModel) {
if (this.groupMode === GroupCloudComponent.MODE_MULTIPLE) {
this.preSelectGroup.push(group);
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 70ad3d966b..b1df775c7b 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
@@ -324,8 +324,8 @@ describe('GroupCloudComponent', () => {
component.preSelectGroups = [];
fixture.detectChanges();
fixture.whenStable().then(() => {
- const selectedUser = component.searchGroupsControl.value;
- expect(selectedUser).toBeNull();
+ const selectedGroup = component.searchGroupsControl.value;
+ expect(selectedGroup).toBeNull();
done();
});
});
@@ -355,7 +355,7 @@ describe('GroupCloudComponent', () => {
it('should pre-select all preSelectGroups when mode=multiple', (done) => {
component.mode = 'multiple';
fixture.detectChanges();
- component.ngOnChanges({ 'preSelectUsers': change });
+ component.ngOnChanges({ 'preSelectGroups': change });
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
@@ -407,7 +407,7 @@ describe('GroupCloudComponent', () => {
});
});
- it('should not filter groups if user does not have any specified role', (done) => {
+ it('should not filter groups if group does not have any specified role', (done) => {
fixture.detectChanges();
checkGroupHasRoleSpy.and.returnValue(of(false));
const inputHTMLElement: HTMLInputElement = element.querySelector('input');
@@ -498,4 +498,64 @@ describe('GroupCloudComponent', () => {
});
});
});
+
+ describe('Multiple Mode and Pre-selected groups with validate flag', () => {
+
+ beforeEach(async(() => {
+ component.mode = 'multiple';
+ component.validate = true;
+ component.preSelectGroups = mockIdentityGroups;
+ element = fixture.nativeElement;
+ alfrescoApiService = TestBed.get(AlfrescoApiService);
+ fixture.detectChanges();
+ }));
+
+ it('should emit warning if are invalid groups', (done) => {
+ findGroupsByNameSpy.and.returnValue(Promise.resolve([]));
+ const warnMessage = { message: 'INVALID_PRESELECTED_GROUPS', groups: [{ name: 'invalidGroupOne' }, { name: 'invalidGroupTwo' }] };
+ component.validate = true;
+ component.preSelectGroups = [{ name: 'invalidGroupOne' }, { name: 'invalidGroupTwo' }];
+ fixture.detectChanges();
+ component.loadSinglePreselectGroup();
+ component.warning.subscribe((response) => {
+ expect(response).toEqual(warnMessage);
+ expect(response.message).toEqual(warnMessage.message);
+ expect(response.groups).toEqual(warnMessage.groups);
+ expect(response.groups[0].name).toEqual('invalidGroupOne');
+ done();
+ });
+ });
+
+ it('should filter group by name if validate true', (done) => {
+ findGroupsByNameSpy.and.returnValue(of(mockIdentityGroups));
+ component.mode = 'multiple';
+ component.validate = true;
+ component.preSelectGroups = [{ name: mockIdentityGroups[1].name }, { name: mockIdentityGroups[2].name }];
+ fixture.detectChanges();
+ fixture.whenStable().then(() => {
+ component.filterPreselectGroups().then((result) => {
+ expect(findGroupsByNameSpy).toHaveBeenCalled();
+ expect(component.groupExists(result[0])).toEqual(true);
+ expect(component.groupExists(result[1])).toEqual(true);
+ done();
+ });
+ });
+ });
+
+ it('should not preselect any group if name is invalid and validation enable', (done) => {
+ findGroupsByNameSpy.and.returnValue(of([]));
+ component.mode = 'single';
+ component.validate = true;
+ component.preSelectGroups = [{ name: 'invalid group' }];
+ fixture.detectChanges();
+ fixture.whenStable().then(() => {
+ component.validatePreselectGroups().then((result) => {
+ fixture.detectChanges();
+ expect(findGroupsByNameSpy).toHaveBeenCalled();
+ expect(result.length).toEqual(0);
+ done();
+ });
+ });
+ });
+ });
});
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 11d48a9130..4b537ce123 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
@@ -27,14 +27,15 @@ import {
SimpleChanges,
OnChanges,
OnDestroy,
- ChangeDetectionStrategy
+ ChangeDetectionStrategy,
+ SimpleChange
} from '@angular/core';
import { FormControl } from '@angular/forms';
import { trigger, state, style, transition, animate } from '@angular/animations';
import { Observable, of, BehaviorSubject, Subject } from 'rxjs';
import { debounceTime } from 'rxjs/internal/operators/debounceTime';
import { distinctUntilChanged, switchMap, mergeMap, filter, tap, map, takeUntil } from 'rxjs/operators';
-import { IdentityGroupModel, IdentityGroupSearchParam, IdentityGroupService } from '@alfresco/adf-core';
+import { IdentityGroupModel, IdentityGroupSearchParam, IdentityGroupService, LogService } from '@alfresco/adf-core';
@Component({
selector: 'adf-cloud-group',
@@ -57,7 +58,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
static MODE_SINGLE = 'single';
static MODE_MULTIPLE = 'multiple';
- /** Name of the application. If specified this shows the users who have access to the app. */
+ /** Name of the application. If specified this shows the groups who have access to the app. */
@Input()
appName: string;
@@ -65,14 +66,21 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
@Input()
title: string;
- /** User selection mode (single/multiple). */
+ /** Group selection mode (single/multiple). */
@Input()
mode: string = GroupCloudComponent.MODE_SINGLE;
- /** Array of users to be pre-selected. This pre-selects all users in multi selection mode and only the first user of the array in single selection mode. */
+ /** Array of groups to be pre-selected. This pre-selects all groups in multi selection mode and only the first group of the array in single selection mode. */
@Input()
preSelectGroups: IdentityGroupModel[] = [];
+ /** This flag enables the validation on the preSelectGroups passed as input.
+ * In case the flag is true the components call the identity service to verify the validity of the information passed as input.
+ * Otherwise, no check will be done.
+ */
+ @Input()
+ validate: Boolean = false;
+
/** Show the info in readonly mode
*/
@Input()
@@ -98,6 +106,10 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
@Output()
changedGroups = new EventEmitter();
+ /** Emitted when an warning occurs. */
+ @Output()
+ warning = new EventEmitter();
+
@ViewChild('groupInput')
private groupInput: ElementRef;
@@ -121,8 +133,12 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
private onDestroy$ = new Subject();
currentTimeout: any;
+ invalidGroups: IdentityGroupModel[] = [];
- constructor(private identityGroupService: IdentityGroupService) { }
+ constructor(
+ private identityGroupService: IdentityGroupService,
+ private logService: LogService
+ ) { }
ngOnInit() {
this.initSearch();
@@ -130,13 +146,15 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
ngOnChanges(changes: SimpleChanges) {
- if (changes.preSelectGroups && this.hasPreSelectGroups()) {
- this.loadPreSelectGroups();
- } else {
- this.searchGroupsControl.setValue('');
+ if (this.isPreselectedGroupsChanged(changes)) {
+ if (this.isValidationEnabled()) {
+ this.loadPreSelectGroups();
+ } else {
+ this.loadNoValidationPreselectGroups();
+ }
}
- if (changes.appName && this.isAppNameChanged(changes.appName)) {
+ if (this.isAppNameChanged(changes.appName)) {
this.disableSearch();
this.loadClientId();
} else {
@@ -144,8 +162,14 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
}
}
- private isAppNameChanged(change): boolean {
- return change.previousValue !== change.currentValue && this.appName && this.appName.length > 0;
+ private isPreselectedGroupsChanged(changes: SimpleChanges): boolean {
+ return changes.preSelectGroups
+ && changes.preSelectGroups.previousValue !== changes.preSelectGroups.currentValue
+ && this.hasPreSelectGroups();
+ }
+
+ private isAppNameChanged(change: SimpleChange): boolean {
+ return change && change.previousValue !== change.currentValue && this.appName && this.appName.length > 0;
}
private async loadClientId() {
@@ -220,20 +244,114 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
return false;
}
- private loadPreSelectGroups() {
- if (this.isMultipleMode()) {
- const groups = this.removeDuplicatedGroups([...this.preSelectGroups]);
+ async searchGroup(groupName: any): Promise {
+ return (await this.identityGroupService.findGroupsByName(this.createSearchParam(groupName)).toPromise())[0];
+ }
+
+ async filterPreselectGroups() {
+ const promiseBatch = this.preSelectGroups.map(async (group: IdentityGroupModel) => {
+ let result: any;
+ try {
+ result = await this.searchGroup(group.name);
+ } catch (error) {
+ result = [];
+ this.logService.error(error);
+ }
+ const isGroupValid: boolean = this.groupExists(result);
+ return isGroupValid ? result : null;
+ });
+ return Promise.all(promiseBatch);
+ }
+
+ public groupExists(result: IdentityGroupModel): boolean {
+ return result
+ && (result.id !== undefined
+ || result.name !== undefined);
+ }
+
+ private isValidGroup(filteredGroups: IdentityGroupModel[], group: IdentityGroupModel): IdentityGroupModel {
+ return filteredGroups.find((filteredGroup: IdentityGroupModel) => {
+ return filteredGroup &&
+ (filteredGroup.id === group.id ||
+ filteredGroup.name === group.name);
+ });
+ }
+
+ async validatePreselectGroups(): Promise {
+ let filteredPreselectGroups: IdentityGroupModel[];
+ let validGroups: IdentityGroupModel[] = [];
+
+ try {
+ filteredPreselectGroups = await this.filterPreselectGroups();
+ } catch (error) {
+ validGroups = [];
+ this.logService.error(error);
+ }
+
+ await this.preSelectGroups.map((group: IdentityGroupModel) => {
+ const validGroup = this.isValidGroup(filteredPreselectGroups, group);
+
+ if (validGroup) {
+ validGroups.push(validGroup);
+ } else {
+ this.invalidGroups.push(group);
+ }
+ });
+ validGroups = this.removeDuplicatedGroups(validGroups);
+ return validGroups;
+ }
+
+ public async loadSinglePreselectGroup() {
+ const groups = await this.validatePreselectGroups();
+ if (groups && groups.length > 0) {
+ this.checkPreselectValidationErrors();
+ this.searchGroupsControl.setValue(groups[0]);
+ } else {
+ this.checkPreselectValidationErrors();
+ }
+ }
+
+ public async loadMultiplePreselectGroups() {
+ const groups = await this.validatePreselectGroups();
+ if (groups && groups.length > 0) {
+ this.checkPreselectValidationErrors();
this.selectedGroups = [...groups];
this.selectedGroups$.next(this.selectedGroups);
} else {
+ this.checkPreselectValidationErrors();
+ }
+ }
+
+ public checkPreselectValidationErrors() {
+ if (this.invalidGroups.length > 0) {
+ this.warning.emit({
+ message: 'INVALID_PRESELECTED_GROUPS',
+ groups: this.invalidGroups
+ });
+ }
+ }
+
+ private loadPreSelectGroups() {
+ if (!this.isMultipleMode()) {
+ this.loadSinglePreselectGroup();
+ } else {
+ this.loadMultiplePreselectGroups();
+ }
+ }
+
+ loadNoValidationPreselectGroups() {
+ this.selectedGroups = [...this.removeDuplicatedGroups([...this.preSelectGroups])];
+ if (this.isMultipleMode()) {
+ this.selectedGroups$.next(this.selectedGroups);
+ } else {
if (this.currentTimeout) {
clearTimeout(this.currentTimeout);
}
this.currentTimeout = setTimeout(() => {
- this.searchGroupsControl.setValue(this.preSelectGroups[0]);
- this.onSelect(this.preSelectGroups[0]);
+ this.searchGroupsControl.setValue(this.selectedGroups[0]);
+ this.onSelect(this.selectedGroups[0]);
}, 0);
}
}
@@ -290,7 +408,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
private removeDuplicatedGroups(groups: IdentityGroupModel[]): IdentityGroupModel[] {
return groups.filter((group, index, self) =>
index === self.findIndex((auxGroup) => {
- return group.id === auxGroup.id;
+ return group.id === auxGroup.id && group.name === auxGroup.name;
}));
}
@@ -333,6 +451,10 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
this.isFocused = isFocused;
}
+ isValidationEnabled() {
+ return this.validate === true;
+ }
+
hasErrorMessage(): boolean {
return !this.isFocused && this.hasError();
}