mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
[AAE-1372] Refactor People/Group cloud component (#5355)
* [AAE-1372] Fix read-only preselected users can be deleted * [AAE-1372] Fix people/group cloud component readonly mode * [AAE-1372] Refactor People/Group Cloud components * [AAE-1372] Refactor People/Group Cloud components * [AAE-1372] Clear invalid user in single mode after replacing with a valid user * [AAE-1372] Add progress bar while validation loading. When user gets removed remove from validation * [AAE-1372] Fix lint errors * [AAE-1372] Fix single selection e2e * [AAE-1372] Fix unit tests - people/group cloud components * [AAE-1372] Fix e2e, set People/Group formControls invalid when has preselect errors * [AAE-1372] Fix invalid form control bug
This commit is contained in:
parent
91abe87ccc
commit
3c3aa7599a
@ -309,10 +309,11 @@
|
|||||||
"APP_FILTER_MODE": "Filter by application name",
|
"APP_FILTER_MODE": "Filter by application name",
|
||||||
"ROLE_FILTER_MODE": "Filter by role",
|
"ROLE_FILTER_MODE": "Filter by role",
|
||||||
"PRESELECT_VALIDATION": "Preselect validation",
|
"PRESELECT_VALIDATION": "Preselect validation",
|
||||||
"ALL_SELECTED_USERS": "All Selected Users",
|
"ALL_PRESELECTED_USERS": "All Pre-selected Users",
|
||||||
"ALL_SELECTED_GROUPS": "All Selected Groups",
|
"ALL_PRESELECTED_GROUPS": "All Pre-selected Groups",
|
||||||
"INVALID_USERS": "Invalid Users",
|
"INVALID_USERS": "Invalid Users",
|
||||||
"INVALID_GROUPS": "Invalid Groups"
|
"INVALID_GROUPS": "Invalid Groups",
|
||||||
|
"READONLY_MODE": "Readonly Mode"
|
||||||
},
|
},
|
||||||
"SETTINGS_CLOUD": {
|
"SETTINGS_CLOUD": {
|
||||||
"MULTISELECTION": "Multiselection",
|
"MULTISELECTION": "Multiselection",
|
||||||
|
@ -32,21 +32,23 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-checkbox class="app-preselect-value" (change)="onChangePeopleValidation($event)">{{
|
<mat-checkbox class="app-preselect-value" (change)="onChangePeopleValidation($event)">{{
|
||||||
'PEOPLE_GROUPS_CLOUD.PRESELECT_VALIDATION' | translate }}</mat-checkbox>
|
'PEOPLE_GROUPS_CLOUD.PRESELECT_VALIDATION' | translate }}</mat-checkbox>
|
||||||
|
<mat-checkbox data-automation-id="app-people-readonly" value="{{ peopleReadonly }}" (change)="onChangePeopleReadonly($event)">{{
|
||||||
|
'PEOPLE_GROUPS_CLOUD.READONLY_MODE' | translate }}</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<adf-cloud-people
|
<adf-cloud-people
|
||||||
[preSelectUsers]="preSelectUsers"
|
[preSelectUsers]="preSelectUsers"
|
||||||
|
[readOnly]="peopleReadonly"
|
||||||
[validate]="peoplePreselectValidation"
|
[validate]="peoplePreselectValidation"
|
||||||
[appName]="peopleAppName"
|
[appName]="peopleAppName"
|
||||||
[roles]="peopleRoles"
|
[roles]="peopleRoles"
|
||||||
[title]="'ADF_TASK_LIST.START_TASK.FORM.LABEL.ASSIGNEE'"
|
[title]="'ADF_TASK_LIST.START_TASK.FORM.LABEL.ASSIGNEE'"
|
||||||
[mode]="peopleMode"
|
[mode]="peopleMode"
|
||||||
(selectUser)="onSelectUser($event)"
|
|
||||||
(warning)="onUsersWarning($event)"></adf-cloud-people>
|
(warning)="onUsersWarning($event)"></adf-cloud-people>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="app-people-list" *ngIf="canShowPeopleList()">
|
<div class="app-people-list" *ngIf="canShowPeopleList()">
|
||||||
<h4>{{ 'PEOPLE_GROUPS_CLOUD.ALL_SELECTED_USERS' | translate }}</h4>
|
<h4>{{ 'PEOPLE_GROUPS_CLOUD.ALL_PRESELECTED_USERS' | translate }}</h4>
|
||||||
<mat-list role="list">
|
<mat-list role="list">
|
||||||
<mat-list-item *ngFor="let item of preSelectUsers" role="listitem">
|
<mat-list-item *ngFor="let item of preSelectUsers" role="listitem">
|
||||||
<mat-icon mat-list-icon>person</mat-icon>
|
<mat-icon mat-list-icon>person</mat-icon>
|
||||||
@ -99,23 +101,24 @@
|
|||||||
<mat-label>Preselect: {{ DEFAULT_GROUP_PLACEHOLDER }}</mat-label>
|
<mat-label>Preselect: {{ DEFAULT_GROUP_PLACEHOLDER }}</mat-label>
|
||||||
<input matInput (input)="setGroupsPreselectValue($event)" data-automation-id="app-group-preselect-input" />
|
<input matInput (input)="setGroupsPreselectValue($event)" data-automation-id="app-group-preselect-input" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-checkbox class="app-group-preselect-validation" (change)="onChangeGroupValidation($event)">{{
|
<mat-checkbox class="app-preselect-value" (change)="onChangeGroupValidation($event)">{{
|
||||||
'PEOPLE_GROUPS_CLOUD.PRESELECT_VALIDATION' | translate }}</mat-checkbox>
|
'PEOPLE_GROUPS_CLOUD.PRESELECT_VALIDATION' | translate }}</mat-checkbox>
|
||||||
|
<mat-checkbox data-automation-id="app-group-readonly" value="{{ groupReadonly }}" (change)="onChangeGroupReadonly($event)">{{
|
||||||
|
'PEOPLE_GROUPS_CLOUD.READONLY_MODE' | translate }}</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<adf-cloud-group
|
<adf-cloud-group
|
||||||
[mode]="groupMode"
|
[mode]="groupMode"
|
||||||
|
[readOnly]="groupReadonly"
|
||||||
[validate]="groupPreselectValidation"
|
[validate]="groupPreselectValidation"
|
||||||
[roles]="groupRoles"
|
[roles]="groupRoles"
|
||||||
[appName]="groupAppName"
|
[appName]="groupAppName"
|
||||||
[preSelectGroups]="preSelectGroup"
|
[preSelectGroups]="preSelectGroup"
|
||||||
(selectGroup)="onSelectGroup($event)"
|
|
||||||
(removeGroup)="onRemoveGroup($event)"
|
|
||||||
(warning)="onGroupsWarning($event)"></adf-cloud-group>
|
(warning)="onGroupsWarning($event)"></adf-cloud-group>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="app-group-list" *ngIf="canShowGroupList()">
|
<div class="app-group-list" *ngIf="canShowGroupList()">
|
||||||
<h4>{{ 'PEOPLE_GROUPS_CLOUD.ALL_SELECTED_GROUPS' | translate }}</h4>
|
<h4>{{ 'PEOPLE_GROUPS_CLOUD.ALL_PRESELECTED_GROUPS' | translate }}</h4>
|
||||||
<mat-list role="list">
|
<mat-list role="list">
|
||||||
<mat-list-item *ngFor="let item of preSelectGroup" role="listitem">
|
<mat-list-item *ngFor="let item of preSelectGroup" role="listitem">
|
||||||
<mat-icon mat-list-icon>group</mat-icon>
|
<mat-icon mat-list-icon>group</mat-icon>
|
||||||
|
@ -34,17 +34,18 @@ export class PeopleGroupCloudDemoComponent {
|
|||||||
|
|
||||||
peopleMode: string = PeopleCloudComponent.MODE_SINGLE;
|
peopleMode: string = PeopleCloudComponent.MODE_SINGLE;
|
||||||
preSelectUsers: IdentityUserModel[] = [];
|
preSelectUsers: IdentityUserModel[] = [];
|
||||||
invalidUsers: IdentityGroupModel[] = [];
|
invalidUsers: IdentityUserModel[] = [];
|
||||||
peopleRoles: string[] = [];
|
peopleRoles: string[] = [];
|
||||||
peopleAppName: string;
|
peopleAppName: string;
|
||||||
peopleFilterMode: string = this.DEFAULT_FILTER_MODE;
|
peopleFilterMode: string = this.DEFAULT_FILTER_MODE;
|
||||||
peoplePreselectValidation: Boolean = false;
|
peoplePreselectValidation: Boolean = false;
|
||||||
groupPreselectValidation = false;
|
groupPreselectValidation = false;
|
||||||
|
peopleReadonly = false;
|
||||||
|
groupReadonly = false;
|
||||||
|
|
||||||
groupMode: string = GroupCloudComponent.MODE_SINGLE;
|
groupMode: string = GroupCloudComponent.MODE_SINGLE;
|
||||||
preSelectGroup: IdentityGroupModel[] = [];
|
preSelectGroup: IdentityGroupModel[] = [];
|
||||||
invalidGroups: IdentityGroupModel[] = [];
|
invalidGroups: IdentityGroupModel[] = [];
|
||||||
selectedGroupList: IdentityGroupModel[] = [];
|
|
||||||
groupRoles: string[];
|
groupRoles: string[];
|
||||||
groupAppName: string;
|
groupAppName: string;
|
||||||
groupFilterMode: string = this.DEFAULT_FILTER_MODE;
|
groupFilterMode: string = this.DEFAULT_FILTER_MODE;
|
||||||
@ -75,12 +76,18 @@ export class PeopleGroupCloudDemoComponent {
|
|||||||
|
|
||||||
onChangePeopleMode(event: MatRadioChange) {
|
onChangePeopleMode(event: MatRadioChange) {
|
||||||
this.peopleMode = event.value;
|
this.peopleMode = event.value;
|
||||||
this.preSelectUsers = [...this.preSelectUsers];
|
}
|
||||||
|
|
||||||
|
onChangePeopleReadonly(event: MatCheckboxChange) {
|
||||||
|
this.peopleReadonly = event.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeGroupReadonly(event: MatCheckboxChange) {
|
||||||
|
this.groupReadonly = event.checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeGroupsMode(event: MatRadioChange) {
|
onChangeGroupsMode(event: MatRadioChange) {
|
||||||
this.groupMode = event.value;
|
this.groupMode = event.value;
|
||||||
this.preSelectGroup = [...this.preSelectGroup];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangePeopleFilterMode(event: MatRadioChange) {
|
onChangePeopleFilterMode(event: MatRadioChange) {
|
||||||
@ -119,18 +126,10 @@ export class PeopleGroupCloudDemoComponent {
|
|||||||
|
|
||||||
onChangePeopleValidation(event: MatCheckboxChange) {
|
onChangePeopleValidation(event: MatCheckboxChange) {
|
||||||
this.peoplePreselectValidation = event.checked;
|
this.peoplePreselectValidation = event.checked;
|
||||||
this.preSelectUsers = [...this.preSelectUsers];
|
|
||||||
if (!this.peoplePreselectValidation) {
|
|
||||||
this.invalidUsers = [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeGroupValidation(event: MatCheckboxChange) {
|
onChangeGroupValidation(event: MatCheckboxChange) {
|
||||||
this.groupPreselectValidation = event.checked;
|
this.groupPreselectValidation = event.checked;
|
||||||
this.preSelectGroup = [...this.preSelectGroup];
|
|
||||||
if (!this.groupPreselectValidation) {
|
|
||||||
this.invalidGroups = [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupsWarning(warning: any) {
|
onGroupsWarning(warning: any) {
|
||||||
@ -167,22 +166,6 @@ export class PeopleGroupCloudDemoComponent {
|
|||||||
return this.groupMode === GroupCloudComponent.MODE_MULTIPLE;
|
return this.groupMode === GroupCloudComponent.MODE_MULTIPLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemoveGroup(group: IdentityGroupModel) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get peopleSingleMode() {
|
get peopleSingleMode() {
|
||||||
return PeopleCloudComponent.MODE_SINGLE;
|
return PeopleCloudComponent.MODE_SINGLE;
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,10 @@ Searches Groups.
|
|||||||
|
|
||||||
| Name | Type | Default value | Description |
|
| Name | Type | Default value | Description |
|
||||||
| ---- | ---- | ------------- | ----------- |
|
| ---- | ---- | ------------- | ----------- |
|
||||||
| appName | `string` | | Name of the application. If specified this shows the users who have access to the app. |
|
| appName | `string` | | Name of the application. If specified this shows the groups who have access to the app. |
|
||||||
|
| readOnly | `boolean` | false | readOnly mode (true/false). |
|
||||||
| mode | `string` | | User selection mode (single/multiple). |
|
| mode | `string` | | User selection mode (single/multiple). |
|
||||||
| preSelectGroups | [`IdentityGroupModel`](../../../lib/core/models/identity-group.model.ts)`[]` | \[] | 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. |
|
| preSelectGroups | [`IdentityGroupModel`](../../../lib/core/models/identity-group.model.ts)`[]` | \[] | 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. |
|
||||||
| roles | `string[]` | \[] | Role names of the groups to be listed. |
|
| roles | `string[]` | \[] | Role names of the groups to be listed. |
|
||||||
| searchGroupsControl | `FormControl` | new FormControl() | FormControl to search the group |
|
| searchGroupsControl | `FormControl` | new FormControl() | FormControl to search the group |
|
||||||
| title | `string` | | Title of the field |
|
| title | `string` | | Title of the field |
|
||||||
@ -95,6 +96,20 @@ export class MyComponent {
|
|||||||
|
|
||||||
### Read-only
|
### Read-only
|
||||||
|
|
||||||
|
You can use `readonly` property to set the component in `readonly` mode. Readonly mode will disable any interaction with the component.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<adf-cloud-group
|
||||||
|
[appName]="'simple-app'"
|
||||||
|
[mode]="'multiple'"
|
||||||
|
[preSelectGroups]="groups"
|
||||||
|
[readOnly]="true">
|
||||||
|
</adf-cloud-group>
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to manage each group seperately you can set their readonly property at your preference.
|
||||||
|
You need to have component's readonly property set to false. Component's readonly mode overwrites groups level.
|
||||||
|
|
||||||
You can use `readonly` property to make preselected groups read-only in `multiple` mode.
|
You can use `readonly` property to make preselected groups read-only in `multiple` mode.
|
||||||
|
|
||||||
Usage example:
|
Usage example:
|
||||||
|
@ -25,6 +25,7 @@ Allows one or more users to be selected (with auto-suggestion) based on the inpu
|
|||||||
| Name | Type | Default value | Description |
|
| Name | Type | Default value | Description |
|
||||||
| ---- | ---- | ------------- | ----------- |
|
| ---- | ---- | ------------- | ----------- |
|
||||||
| appName | `string` | | Name of the application. If specified, this shows the users who have access to the app. |
|
| appName | `string` | | Name of the application. If specified, this shows the users who have access to the app. |
|
||||||
|
| readOnly | `boolean` | false | readOnly mode (true/false). |
|
||||||
| mode | `string` | | User selection mode (single/multiple). |
|
| mode | `string` | | User selection mode (single/multiple). |
|
||||||
| preSelectUsers | [`IdentityUserModel`](../../../lib/core/models/identity-user.model.ts)`[]` | | Array of users to be pre-selected. All users in the array are pre-selected in multi selection mode, but only the first user is pre-selected in single selection mode. Mandatory properties are: id, email, username |
|
| preSelectUsers | [`IdentityUserModel`](../../../lib/core/models/identity-user.model.ts)`[]` | | Array of users to be pre-selected. All users in the array are pre-selected in multi selection mode, but only the first user is pre-selected in single selection mode. Mandatory properties are: id, email, username |
|
||||||
| roles | `string[]` | | Role names of the users to be listed. |
|
| roles | `string[]` | | Role names of the users to be listed. |
|
||||||
@ -44,7 +45,19 @@ Allows one or more users to be selected (with auto-suggestion) based on the inpu
|
|||||||
|
|
||||||
### Read-only
|
### Read-only
|
||||||
|
|
||||||
You can use `readonly` property to make preselected users read-only in `multiple` mode.
|
You can use `readonly` property to set the component in `readonly` mode. Readonly mode will disable any interaction with the component.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<adf-cloud-people
|
||||||
|
[appName]="'simple-app'"
|
||||||
|
[mode]="'multiple'"
|
||||||
|
[preSelectUsers]="preSelectUsers"
|
||||||
|
[readOnly]="true">
|
||||||
|
</adf-cloud-people>
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to manage each user seperately you can set their readonly property at your preference.
|
||||||
|
You need to have component's readonly property set to false. Component's readonly mode overwrites users level.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const preSelectUsers = [
|
const preSelectUsers = [
|
||||||
@ -55,7 +68,7 @@ const preSelectUsers = [
|
|||||||
```
|
```
|
||||||
```html
|
```html
|
||||||
<adf-cloud-people
|
<adf-cloud-people
|
||||||
[mode]="'multiple'",
|
[mode]="'multiple'"
|
||||||
[preSelectUsers]="preSelectUsers">
|
[preSelectUsers]="preSelectUsers">
|
||||||
</adf-cloud-people>
|
</adf-cloud-people>
|
||||||
```
|
```
|
||||||
|
@ -193,21 +193,22 @@ describe('People Groups Cloud Component', () => {
|
|||||||
|
|
||||||
await peopleGroupCloudComponentPage.clickPeopleCloudSingleSelection();
|
await peopleGroupCloudComponentPage.clickPeopleCloudSingleSelection();
|
||||||
await peopleGroupCloudComponentPage.checkPeopleCloudSingleSelectionIsSelected();
|
await peopleGroupCloudComponentPage.checkPeopleCloudSingleSelectionIsSelected();
|
||||||
|
|
||||||
|
await peopleGroupCloudComponentPage.enterPeoplePreselect('[{"id":"12345","username":"someUsername","email":"someEmail"}]');
|
||||||
|
await expect(await peopleCloudComponent.checkSelectedPeople('someUsername'));
|
||||||
|
|
||||||
await peopleGroupCloudComponentPage.clickPreselectValidation();
|
await peopleGroupCloudComponentPage.clickPreselectValidation();
|
||||||
await expect(await peopleGroupCloudComponentPage.getPreselectValidationStatus()).toBe('true');
|
await expect(await peopleGroupCloudComponentPage.getPreselectValidationStatus()).toBe('true');
|
||||||
|
|
||||||
await peopleGroupCloudComponentPage.enterPeoplePreselect('[{"id":"12345","username":"someUsername","email":"someEmail"}]');
|
|
||||||
await expect(await peopleCloudComponent.getAssigneeFieldContent()).toBe('');
|
|
||||||
|
|
||||||
await expect(await peopleGroupCloudComponentPage.getPreselectValidationStatus()).toBe('true');
|
await expect(await peopleGroupCloudComponentPage.getPreselectValidationStatus()).toBe('true');
|
||||||
await peopleGroupCloudComponentPage.enterPeoplePreselect(`[{"id":"${noRoleUser.idIdentityService}"}]`);
|
await peopleGroupCloudComponentPage.enterPeoplePreselect(`[{"id":"${noRoleUser.idIdentityService}"}]`);
|
||||||
await expect(await peopleCloudComponent.getAssigneeFieldContent()).toBe(`${noRoleUser.firstName} ${noRoleUser.lastName}`);
|
await expect(await peopleCloudComponent.checkSelectedPeople(`${noRoleUser.firstName} ${noRoleUser.lastName}`));
|
||||||
|
|
||||||
await peopleGroupCloudComponentPage.enterPeoplePreselect(`[{"email":"${apsUser.email}"}]`);
|
await peopleGroupCloudComponentPage.enterPeoplePreselect(`[{"email":"${apsUser.email}"}]`);
|
||||||
await expect(await peopleCloudComponent.getAssigneeFieldContent()).toBe(`${apsUser.firstName} ${apsUser.lastName}`);
|
await expect(await peopleCloudComponent.checkSelectedPeople(`${apsUser.firstName} ${apsUser.lastName}`));
|
||||||
|
|
||||||
await peopleGroupCloudComponentPage.enterPeoplePreselect(`[{"username":"${testUser.username}"}]`);
|
await peopleGroupCloudComponentPage.enterPeoplePreselect(`[{"username":"${testUser.username}"}]`);
|
||||||
await expect(await peopleCloudComponent.getAssigneeFieldContent()).toBe(`${testUser.firstName} ${testUser.lastName}`);
|
await expect(await peopleCloudComponent.checkSelectedPeople(`${testUser.firstName} ${testUser.lastName}`));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('[C309676] Should fetch the preselect users based on the Validate flag set to True in Multiple mode selection', async () => {
|
it('[C309676] Should fetch the preselect users based on the Validate flag set to True in Multiple mode selection', async () => {
|
||||||
@ -254,18 +255,6 @@ describe('People Groups Cloud Component', () => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('[C309678] Should not fetch the preselect users when mandatory parameters Id, Email and username are missing', async () => {
|
|
||||||
await peopleGroupCloudComponentPage.clickPeopleCloudMultipleSelection();
|
|
||||||
await peopleGroupCloudComponentPage.checkPeopleCloudMultipleSelectionIsSelected();
|
|
||||||
await peopleGroupCloudComponentPage.clickPreselectValidation();
|
|
||||||
await expect(await peopleGroupCloudComponentPage.getPreselectValidationStatus()).toBe('true');
|
|
||||||
|
|
||||||
await peopleGroupCloudComponentPage.enterPeoplePreselect(`[{"firstName":"${apsUser.firstName}","lastName":"${apsUser.lastName},"` +
|
|
||||||
`{"firstName":"${testUser.firstName}","lastName":"${testUser.lastName}",{"firstName":"${noRoleUser.firstName}","lastName":"${noRoleUser.lastName}"]`);
|
|
||||||
await browser.sleep(200);
|
|
||||||
await expect(await peopleCloudComponent.getAssigneeFieldContent()).toBe('');
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -90,7 +90,7 @@ describe('People Groups Cloud Component', () => {
|
|||||||
await peopleCloudComponent.checkUserIsDisplayed(`${testUser.firstName} ${testUser.lastName}`);
|
await peopleCloudComponent.checkUserIsDisplayed(`${testUser.firstName} ${testUser.lastName}`);
|
||||||
await peopleCloudComponent.selectAssigneeFromList(`${testUser.firstName} ${testUser.lastName}`);
|
await peopleCloudComponent.selectAssigneeFromList(`${testUser.firstName} ${testUser.lastName}`);
|
||||||
await browser.sleep(100);
|
await browser.sleep(100);
|
||||||
await expect(await peopleCloudComponent.getAssigneeFieldContent()).toBe(`${testUser.firstName} ${testUser.lastName}`);
|
await expect(await peopleCloudComponent.checkSelectedPeople(`${testUser.firstName} ${testUser.lastName}`));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('[C305041] Should filter the People Multiple Selection with the Application name filter', async () => {
|
it('[C305041] Should filter the People Multiple Selection with the Application name filter', async () => {
|
||||||
@ -118,7 +118,7 @@ describe('People Groups Cloud Component', () => {
|
|||||||
await groupCloudComponentPage.searchGroups(hrGroup.name);
|
await groupCloudComponentPage.searchGroups(hrGroup.name);
|
||||||
await groupCloudComponentPage.checkGroupIsDisplayed(hrGroup.name);
|
await groupCloudComponentPage.checkGroupIsDisplayed(hrGroup.name);
|
||||||
await groupCloudComponentPage.selectGroupFromList(hrGroup.name);
|
await groupCloudComponentPage.selectGroupFromList(hrGroup.name);
|
||||||
await expect(await groupCloudComponentPage.getGroupsFieldContent()).toBe(hrGroup.name);
|
await expect(await groupCloudComponentPage.checkSelectedGroup(hrGroup.name));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('[C305041] Should filter the Groups Multiple Selection with the Application name filter', async () => {
|
it('[C305041] Should filter the Groups Multiple Selection with the Application name filter', async () => {
|
||||||
|
@ -106,7 +106,7 @@ describe('Start Task', () => {
|
|||||||
it('[C297675] Should create a task unassigned when assignee field is empty in Start Task form', async () => {
|
it('[C297675] Should create a task unassigned when assignee field is empty in Start Task form', async () => {
|
||||||
await tasksCloudDemoPage.openNewTaskForm();
|
await tasksCloudDemoPage.openNewTaskForm();
|
||||||
await startTask.checkFormIsDisplayed();
|
await startTask.checkFormIsDisplayed();
|
||||||
await peopleCloudComponent.clearAssignee();
|
await peopleCloudComponent.clearAssigneeFromChip(testUser.username);
|
||||||
await startTask.addName(unassignedTaskName);
|
await startTask.addName(unassignedTaskName);
|
||||||
await startTask.clickStartButton();
|
await startTask.clickStartButton();
|
||||||
await tasksCloudDemoPage.editTaskFilterCloudComponent();
|
await tasksCloudDemoPage.editTaskFilterCloudComponent();
|
||||||
@ -125,7 +125,7 @@ describe('Start Task', () => {
|
|||||||
it('[C291956] Should be able to create a new standalone task without assignee', async () => {
|
it('[C291956] Should be able to create a new standalone task without assignee', async () => {
|
||||||
await tasksCloudDemoPage.openNewTaskForm();
|
await tasksCloudDemoPage.openNewTaskForm();
|
||||||
await startTask.checkFormIsDisplayed();
|
await startTask.checkFormIsDisplayed();
|
||||||
await peopleCloudComponent.clearAssignee();
|
await peopleCloudComponent.clearAssigneeFromChip(testUser.username);
|
||||||
await startTask.addName(unassignedTaskName);
|
await startTask.addName(unassignedTaskName);
|
||||||
await startTask.checkStartButtonIsEnabled();
|
await startTask.checkStartButtonIsEnabled();
|
||||||
await startTask.clickStartButton();
|
await startTask.clickStartButton();
|
||||||
@ -203,7 +203,7 @@ describe('Start Task', () => {
|
|||||||
it('[C291953] Assignee field should display the logged user as default', async () => {
|
it('[C291953] Assignee field should display the logged user as default', async () => {
|
||||||
await tasksCloudDemoPage.openNewTaskForm();
|
await tasksCloudDemoPage.openNewTaskForm();
|
||||||
await startTask.checkFormIsDisplayed();
|
await startTask.checkFormIsDisplayed();
|
||||||
await expect(await peopleCloudComponent.getAssignee()).toContain(testUser.firstName, 'does not contain Admin');
|
await expect(await peopleCloudComponent.checkSelectedPeople(testUser.firstName));
|
||||||
await startTask.clickCancelButton();
|
await startTask.clickCancelButton();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -212,7 +212,7 @@ describe('Start Task', () => {
|
|||||||
await startTask.checkFormIsDisplayed();
|
await startTask.checkFormIsDisplayed();
|
||||||
await startTask.addName(reassignTaskName);
|
await startTask.addName(reassignTaskName);
|
||||||
|
|
||||||
await expect(await peopleCloudComponent.getAssignee()).toBe(`${testUser.firstName} ${testUser.lastName}`);
|
await peopleCloudComponent.checkSelectedPeople(`${testUser.firstName} ${testUser.lastName}`);
|
||||||
await peopleCloudComponent.searchAssignee(apsUser.username);
|
await peopleCloudComponent.searchAssignee(apsUser.username);
|
||||||
await peopleCloudComponent.checkUserIsDisplayed(`${apsUser.firstName} ${apsUser.lastName}`);
|
await peopleCloudComponent.checkUserIsDisplayed(`${apsUser.firstName} ${apsUser.lastName}`);
|
||||||
await peopleCloudComponent.selectAssigneeFromList(`${apsUser.firstName} ${apsUser.lastName}`);
|
await peopleCloudComponent.selectAssigneeFromList(`${apsUser.firstName} ${apsUser.lastName}`);
|
||||||
|
@ -1,61 +1,71 @@
|
|||||||
<div class="adf-cloud-group">
|
<form>
|
||||||
<mat-form-field>
|
<mat-form-field class="adf-cloud-group">
|
||||||
<mat-label id="adf-group-cloud-title-id">{{ (title || 'ADF_CLOUD_GROUPS.SEARCH-GROUP') | translate }}</mat-label>
|
<mat-label
|
||||||
<mat-chip-list #groupChipList *ngIf="isMultipleMode()" [disabled]="isDisabled" data-automation-id="adf-cloud-group-chip-list" class="apa-group-chip-list">
|
id="adf-group-cloud-title-id">{{ (title || 'ADF_CLOUD_GROUPS.SEARCH-GROUP') | translate }}</mat-label>
|
||||||
<mat-chip
|
<mat-chip-list #groupChipList [disabled]="isReadonly() || isValidationLoading()" data-automation-id="adf-cloud-group-chip-list" class="apa-group-chip-list">
|
||||||
*ngFor="let group of selectedGroups$ | async"
|
<mat-chip
|
||||||
[removable]="!(group.readonly)"
|
*ngFor="let group of selectedGroups"
|
||||||
(removed)="onRemove(group)"
|
[removable]="!(group.readonly)"
|
||||||
matTooltip="{{ (group.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}"
|
[attr.data-automation-id]="'adf-cloud-group-chip-' + group.name"
|
||||||
[attr.data-automation-id]="'adf-cloud-group-chip-' + group.name">
|
(removed)="onRemove(group)"
|
||||||
{{group.name}}
|
matTooltip="{{ (group.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}">
|
||||||
<mat-icon
|
{{group.name}}
|
||||||
*ngIf="!(group.readonly || readOnly)"
|
<mat-icon
|
||||||
matChipRemove [attr.data-automation-id]="'adf-cloud-group-chip-remove-icon-' + group.name">
|
*ngIf="!(group.readonly || readOnly)"
|
||||||
cancel
|
matChipRemove [attr.data-automation-id]="'adf-cloud-group-chip-remove-icon-' + group.name">
|
||||||
</mat-icon>
|
cancel
|
||||||
</mat-chip>
|
</mat-icon>
|
||||||
<input matInput
|
</mat-chip>
|
||||||
[formControl]="searchGroupsControl"
|
<input matInput
|
||||||
class="adf-group-input"
|
[formControl]="searchGroupsControl"
|
||||||
id="group-name"
|
[matAutocomplete]="auto"
|
||||||
[attr.disabled]="isDisabled"
|
[matChipInputFor]="groupChipList"
|
||||||
data-automation-id="adf-cloud-group-search-input"
|
(focus)="setFocus(true)"
|
||||||
(focus)="setFocus(true)"
|
(blur)="setFocus(false)"
|
||||||
(blur)="setFocus(false)"
|
class="adf-group-input"
|
||||||
[matAutocomplete]="auto"
|
id="group-name"
|
||||||
[matChipInputFor]="groupChipList" #groupInput>
|
data-automation-id="adf-cloud-group-search-input" #groupInput>
|
||||||
</mat-chip-list>
|
</mat-chip-list>
|
||||||
|
|
||||||
<input *ngIf="!isMultipleMode()"
|
<mat-autocomplete
|
||||||
matInput
|
autoActiveFirstOption
|
||||||
class="adf-group-input"
|
#auto="matAutocomplete"
|
||||||
data-automation-id="adf-cloud-group-search-input"
|
class="adf-cloud-group-list"
|
||||||
(focus)="setFocus(true)"
|
(optionSelected)="onSelect($event.option.value)"
|
||||||
(blur)="setFocus(false)"
|
[displayWith]="getDisplayName"
|
||||||
[formControl]="searchGroupsControl"
|
data-automation-id="adf-cloud-group-autocomplete">
|
||||||
[matAutocomplete]="auto">
|
<mat-option *ngFor="let group of searchGroups$ | async; let i = index" [value]="group"
|
||||||
|
[attr.data-automation-id]="'adf-cloud-group-chip-' + group.name">
|
||||||
|
<div class="adf-cloud-group-row" id="adf-group-{{i}}" fxLayout="row" fxLayoutAlign="start center"
|
||||||
|
fxLayoutGap="20px">
|
||||||
|
<button class="adf-group-short-name" mat-fab>{{group | groupNameInitial }}</button>
|
||||||
|
<span>{{group.name}}</span>
|
||||||
|
</div>
|
||||||
|
</mat-option>
|
||||||
|
</mat-autocomplete>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-progress-bar
|
||||||
|
*ngIf="isLoading"
|
||||||
|
mode="indeterminate">
|
||||||
|
</mat-progress-bar>
|
||||||
|
|
||||||
<mat-autocomplete
|
<mat-error *ngIf="hasPreselectError() && !isValidationLoading()">
|
||||||
#auto="matAutocomplete"
|
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
||||||
class="adf-cloud-group-list"
|
{{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate : { groupName : validateGroupsMessage } }}</mat-error>
|
||||||
(optionSelected)="onSelect($event.option.value)"
|
<mat-error *ngIf="searchGroupsControl.hasError('pattern')">
|
||||||
[displayWith]="getDisplayName"
|
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
||||||
data-automation-id="adf-cloud-group-autocomplete">
|
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_PATTERN' | translate: { pattern: getValidationPattern() } }}</mat-error>
|
||||||
<mat-option *ngFor="let group of searchGroups$ | async; let i = index" [value]="group" [attr.data-automation-id]="'adf-cloud-group-chip-' + group.name">
|
<mat-error *ngIf="searchGroupsControl.hasError('maxlength')">
|
||||||
<div class="adf-cloud-group-row" id="adf-group-{{i}}" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="20px">
|
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
||||||
<button class="adf-group-short-name" mat-fab>{{group | groupNameInitial }}</button>
|
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MAX_LENGTH' | translate: { requiredLength: getValidationMaxLength() } }}
|
||||||
<span>{{group.name}}</span>
|
</mat-error>
|
||||||
</div>
|
<mat-error *ngIf="searchGroupsControl.hasError('minlength')">
|
||||||
</mat-option>
|
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
||||||
</mat-autocomplete>
|
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MIN_LENGTH' | translate: { requiredLength: getValidationMinLength() } }}</mat-error>
|
||||||
</mat-form-field>
|
<mat-error *ngIf="searchGroupsControl.hasError('required')">
|
||||||
<div class="adf-cloud-group-error" *ngIf="hasErrorMessage()">
|
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
||||||
<div fxLayout="row" fxLayoutAlign="start start" [@transitionMessages]="_subscriptAnimationState">
|
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.REQUIRED' | translate }} </mat-error>
|
||||||
<div class="adf-cloud-group-error-message">
|
<mat-error *ngIf="searchGroupsControl.hasError('searchTypingError') && !this.isFocused" data-automation-id="invalid-groups-typing-error">
|
||||||
{{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate : { groupName : searchedValue } }}
|
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
||||||
</div>
|
{{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate : { groupName : searchedValue } }}</mat-error>
|
||||||
<mat-icon class="adf-cloud-group-error-icon">warning</mat-icon>
|
</form>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
@ -6,7 +6,14 @@
|
|||||||
$foreground: map-get($theme, foreground);
|
$foreground: map-get($theme, foreground);
|
||||||
|
|
||||||
.adf {
|
.adf {
|
||||||
|
&-cloud-group-list {
|
||||||
|
margin: 5px 0;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
&-cloud-group {
|
&-cloud-group {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
.mat-form-field {
|
.mat-form-field {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ describe('GroupCloudComponent', () => {
|
|||||||
component.title = 'TITLE_KEY';
|
component.title = 'TITLE_KEY';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const matLabel: HTMLInputElement = <HTMLInputElement> element.querySelector('#adf-group-cloud-title-id');
|
const matLabel: HTMLInputElement = <HTMLInputElement> element.querySelector('#adf-group-cloud-title-id');
|
||||||
fixture.whenStable().then( () => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(matLabel.textContent).toEqual('TITLE_KEY');
|
expect(matLabel.textContent).toEqual('TITLE_KEY');
|
||||||
});
|
});
|
||||||
@ -86,14 +86,14 @@ describe('GroupCloudComponent', () => {
|
|||||||
findGroupsByNameSpy = spyOn(identityGroupService, 'findGroupsByName').and.returnValue(of(mockIdentityGroups));
|
findGroupsByNameSpy = spyOn(identityGroupService, 'findGroupsByName').and.returnValue(of(mockIdentityGroups));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should list the group if the typed result match', (done) => {
|
it('should list the groups as dropdown options if the search term has results', (done) => {
|
||||||
findGroupsByNameSpy.and.returnValue(of(mockIdentityGroups));
|
|
||||||
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
|
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
|
||||||
inputHTMLElement.focus();
|
inputHTMLElement.focus();
|
||||||
inputHTMLElement.value = 'Mock';
|
inputHTMLElement.value = 'Mock';
|
||||||
inputHTMLElement.dispatchEvent(new Event('keyup'));
|
inputHTMLElement.dispatchEvent(new Event('keyup'));
|
||||||
inputHTMLElement.dispatchEvent(new Event('input'));
|
inputHTMLElement.dispatchEvent(new Event('input'));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(5);
|
expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(5);
|
||||||
@ -116,13 +116,19 @@ describe('GroupCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit selectedGroup if option is valid', (done) => {
|
it('should selectedGroup and groupsChanged emit, update selected groups when a group is selected', (done) => {
|
||||||
|
const group = { name: 'groupname' };
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
spyOn(component, 'hasGroupIdOrName').and.returnValue(true);
|
||||||
const selectEmitSpy = spyOn(component.selectGroup, 'emit');
|
const selectEmitSpy = spyOn(component.selectGroup, 'emit');
|
||||||
component.onSelect({ name: 'groupname' });
|
const changedGroupsSpy = spyOn(component.changedGroups, 'emit');
|
||||||
|
component.onSelect(group);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
expect(selectEmitSpy).toHaveBeenCalled();
|
expect(selectEmitSpy).toHaveBeenCalledWith(group);
|
||||||
|
expect(changedGroupsSpy).toHaveBeenCalledWith([group]);
|
||||||
|
expect(component.getSelectedGroups()[0]).toEqual(group);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -139,9 +145,9 @@ describe('GroupCloudComponent', () => {
|
|||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
inputHTMLElement.blur();
|
inputHTMLElement.blur();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const errorMessage = element.querySelector('.adf-cloud-group-error-message');
|
const errorMessage = element.querySelector('[data-automation-id="invalid-groups-typing-error"]');
|
||||||
expect(errorMessage).not.toBeNull();
|
expect(errorMessage).not.toBeNull();
|
||||||
expect(errorMessage.textContent).toContain(' ADF_CLOUD_GROUPS.ERROR.NOT_FOUND ');
|
expect(errorMessage.textContent).toContain('ADF_CLOUD_GROUPS.ERROR.NOT_FOUND');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -162,13 +168,13 @@ describe('GroupCloudComponent', () => {
|
|||||||
element = fixture.nativeElement;
|
element = fixture.nativeElement;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should fetch the client ID if appName specified', async(() => {
|
it('should fetch the client ID if appName specified', async (() => {
|
||||||
const getClientIdByApplicationNameSpy = spyOn(identityGroupService, 'getClientIdByApplicationName').and.callThrough();
|
const getClientIdByApplicationNameSpy = spyOn(identityGroupService, 'getClientIdByApplicationName').and.callThrough();
|
||||||
component.appName = 'mock-app-name';
|
component.appName = 'mock-app-name';
|
||||||
const change = new SimpleChange(null, 'mock-app-name', false);
|
const change = new SimpleChange(null, 'mock-app-name', false);
|
||||||
component.ngOnChanges({ 'appName': change });
|
component.ngOnChanges({ 'appName': change });
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable().then( () => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getClientIdByApplicationNameSpy).toHaveBeenCalled();
|
expect(getClientIdByApplicationNameSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@ -294,89 +300,31 @@ describe('GroupCloudComponent', () => {
|
|||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
inputHTMLElement.blur();
|
inputHTMLElement.blur();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const errorMessage = element.querySelector('.adf-cloud-group-error-message');
|
const errorMessage = element.querySelector('[data-automation-id="invalid-groups-typing-error"]');
|
||||||
expect(errorMessage).not.toBeNull();
|
expect(errorMessage).not.toBeNull();
|
||||||
expect(errorMessage.textContent).toContain(' ADF_CLOUD_GROUPS.ERROR.NOT_FOUND ');
|
expect(errorMessage.textContent).toContain('ADF_CLOUD_GROUPS.ERROR.NOT_FOUND');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Single Mode and Pre-selected groups', () => {
|
describe('No preselected groups', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
beforeEach(async(() => {
|
it('should not pre-select any group when preSelectGroups is empty - single mode', () => {
|
||||||
component.mode = 'single';
|
component.mode = 'single';
|
||||||
component.preSelectGroups = <any> mockIdentityGroups;
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
element = fixture.nativeElement;
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
}));
|
expect(chips.length).toEqual(0);
|
||||||
|
|
||||||
it('should not show chip list when mode=single', (done) => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
const chip = element.querySelector('mat-chip-list');
|
|
||||||
expect(chip).toBeNull();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not pre-select any group when preSelectGroups is empty and mode=single', (done) => {
|
it('should not pre-select any group when preSelectGroups is empty - multiple mode', () => {
|
||||||
component.preSelectGroups = [];
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
const selectedGroup = component.searchGroupsControl.value;
|
|
||||||
expect(selectedGroup).toBeNull();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Multiple Mode and Pre-selected groups', () => {
|
|
||||||
|
|
||||||
const change = new SimpleChange(null, mockIdentityGroups, false);
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
component.mode = 'multiple';
|
|
||||||
component.preSelectGroups = <any> mockIdentityGroups;
|
|
||||||
component.ngOnChanges({ 'preSelectGroups': change });
|
|
||||||
fixture.detectChanges();
|
|
||||||
element = fixture.nativeElement;
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should show chip list when mode=multiple', (done) => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
const chip = element.querySelector('mat-chip-list');
|
|
||||||
expect(chip).toBeDefined();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should pre-select all preSelectGroups when mode=multiple', (done) => {
|
|
||||||
component.mode = 'multiple';
|
component.mode = 'multiple';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
component.ngOnChanges({ 'preSelectGroups': change });
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
fixture.detectChanges();
|
expect(chips.length).toEqual(0);
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
|
||||||
expect(chips.length).toBe(5);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should emit removeGroup when a selected group is removed', (done) => {
|
|
||||||
const removeSpy = spyOn(component.removeGroup, 'emit');
|
|
||||||
component.mode = 'multiple';
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
const removeIcon = fixture.debugElement.query(By.css('mat-chip mat-icon'));
|
|
||||||
removeIcon.nativeElement.click();
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(removeSpy).toHaveBeenCalled();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -439,57 +387,114 @@ describe('GroupCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Single Mode with pre-selected groups', () => {
|
||||||
|
|
||||||
|
const changes = new SimpleChange(null, mockIdentityGroups, false);
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
component.mode = 'single';
|
||||||
|
component.preSelectGroups = <any> mockIdentityGroups;
|
||||||
|
component.ngOnChanges({ 'preSelectGroups': changes });
|
||||||
|
fixture.detectChanges();
|
||||||
|
element = fixture.nativeElement;
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should show only one mat chip with the first preSelectedGroup', () => {
|
||||||
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
|
expect(chips.length).toEqual(1);
|
||||||
|
expect(chips[0].attributes['data-automation-id']).toEqual(`adf-cloud-group-chip-${mockIdentityGroups[0].name}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Multiple Mode with pre-selected groups', () => {
|
||||||
|
|
||||||
|
const change = new SimpleChange(null, mockIdentityGroups, false);
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
component.mode = 'multiple';
|
||||||
|
component.preSelectGroups = <any> mockIdentityGroups;
|
||||||
|
component.ngOnChanges({ 'preSelectGroups': change });
|
||||||
|
fixture.detectChanges();
|
||||||
|
element = fixture.nativeElement;
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should pre-select all preSelectGroups', () => {
|
||||||
|
component.mode = 'multiple';
|
||||||
|
fixture.detectChanges();
|
||||||
|
component.ngOnChanges({ 'preSelectGroups': change });
|
||||||
|
fixture.detectChanges();
|
||||||
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
|
expect(chips.length).toBe(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should removeGroup and changedGroups emit when a selected group is removed', (done) => {
|
||||||
|
const removeGroupEmitterSpy = spyOn(component.removeGroup, 'emit');
|
||||||
|
const changedGroupsEmitterSpy = spyOn(component.changedGroups, 'emit');
|
||||||
|
const groupToRemove = mockIdentityGroups[0];
|
||||||
|
component.mode = 'multiple';
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const removeIcon = fixture.debugElement.query(By.css('mat-chip mat-icon'));
|
||||||
|
removeIcon.nativeElement.click();
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(removeGroupEmitterSpy).toHaveBeenCalledWith(groupToRemove);
|
||||||
|
expect(changedGroupsEmitterSpy).toHaveBeenCalledWith([mockIdentityGroups[1], mockIdentityGroups[2], mockIdentityGroups[3], mockIdentityGroups[4]]);
|
||||||
|
expect(component.getSelectedGroups().indexOf({
|
||||||
|
id: groupToRemove.id,
|
||||||
|
name: groupToRemove.name,
|
||||||
|
path: groupToRemove.path
|
||||||
|
})).toEqual(-1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe('Multiple Mode with read-only', () => {
|
describe('Multiple Mode with read-only', () => {
|
||||||
|
|
||||||
it('Should not show remove icon for pre-selected groups if readonly property set to true', (done) => {
|
it('Should not show remove icon for pre-selected groups if readonly property set to true', (done) => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const preselectedGroups = [
|
component.preSelectGroups = [
|
||||||
{ id: mockIdentityGroups[0].id, name: mockIdentityGroups[0].name, readonly: true },
|
{ id: mockIdentityGroups[0].id, name: mockIdentityGroups[0].name, readonly: true },
|
||||||
{ id: mockIdentityGroups[1].id, name: mockIdentityGroups[1].name, readonly: true }
|
{ id: mockIdentityGroups[1].id, name: mockIdentityGroups[1].name, readonly: true }
|
||||||
];
|
];
|
||||||
component.preSelectGroups = preselectedGroups;
|
const change = new SimpleChange(null, component.preSelectGroups, false);
|
||||||
const change = new SimpleChange(null, preselectedGroups, false);
|
|
||||||
component.mode = 'multiple';
|
component.mode = 'multiple';
|
||||||
component.ngOnChanges({ 'preSelectGroups': change });
|
component.ngOnChanges({ 'preSelectGroups': change });
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const chipList = fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip');
|
|
||||||
const removeIcon = <HTMLElement> fixture.nativeElement.querySelector('[data-automation-id="adf-cloud-group-chip-remove-icon-Mock Group 1"]');
|
|
||||||
expect(chipList.length).toBe(2);
|
|
||||||
expect(component.preSelectGroups[0].readonly).toBeTruthy();
|
|
||||||
expect(component.preSelectGroups[1].readonly).toBeTruthy();
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
const chipList = fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip');
|
||||||
|
const removeIcon = <HTMLElement> fixture.nativeElement.querySelector('[data-automation-id="adf-cloud-group-chip-remove-icon-Mock Group 1"]');
|
||||||
|
expect(chipList.length).toBe(2);
|
||||||
|
expect(component.preSelectGroups[0].readonly).toBeTruthy();
|
||||||
|
expect(component.preSelectGroups[1].readonly).toBeTruthy();
|
||||||
expect(removeIcon).toBeNull();
|
expect(removeIcon).toBeNull();
|
||||||
expect(component.preSelectGroups.length).toBe(2);
|
|
||||||
expect(component.preSelectGroups[0].readonly).toBe(true, 'Not removable');
|
|
||||||
expect(component.preSelectGroups[1].readonly).toBe(true, 'Not removable');
|
|
||||||
expect(fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip').length).toBe(2);
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to remove preselected groups if readonly property set to false', (done) => {
|
it('Should be able to remove preselected groups if readonly property set to false', (done) => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const preselectedGroups = [
|
component.preSelectGroups = [
|
||||||
{ id: mockIdentityGroups[0].id, name: mockIdentityGroups[0].name, readonly: false },
|
{ id: mockIdentityGroups[0].id, name: mockIdentityGroups[0].name, readonly: false },
|
||||||
{ id: mockIdentityGroups[1].id, name: mockIdentityGroups[1].name, readonly: false }
|
{ id: mockIdentityGroups[1].id, name: mockIdentityGroups[1].name, readonly: false }
|
||||||
];
|
];
|
||||||
component.preSelectGroups = preselectedGroups;
|
const change = new SimpleChange(null, component.preSelectGroups, false);
|
||||||
const change = new SimpleChange(null, preselectedGroups, false);
|
|
||||||
component.mode = 'multiple';
|
component.mode = 'multiple';
|
||||||
const removeGroupSpy = spyOn(component.removeGroup, 'emit');
|
|
||||||
component.ngOnChanges({ 'preSelectGroups': change });
|
component.ngOnChanges({ 'preSelectGroups': change });
|
||||||
|
const removeGroupSpy = spyOn(component.removeGroup, 'emit');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const chipList = fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip');
|
|
||||||
const removeIcon = <HTMLElement> fixture.nativeElement.querySelector('[data-automation-id="adf-cloud-group-chip-remove-icon-Mock Group 1"]');
|
|
||||||
expect(chipList.length).toBe(2);
|
|
||||||
expect(component.preSelectGroups[0].readonly).toBe(false, 'Removable');
|
|
||||||
expect(component.preSelectGroups[1].readonly).toBe(false, 'Removable');
|
|
||||||
removeIcon.click();
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
|
const removeIcon = <HTMLElement> fixture.nativeElement.querySelector('[data-automation-id="adf-cloud-group-chip-remove-icon-Mock Group 1"]');
|
||||||
|
expect(chips.length).toBe(2);
|
||||||
|
expect(component.preSelectGroups[0].readonly).toBe(false, 'Removable');
|
||||||
|
expect(component.preSelectGroups[1].readonly).toBe(false, 'Removable');
|
||||||
removeIcon.click();
|
removeIcon.click();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(removeGroupSpy).toHaveBeenCalled();
|
expect(removeGroupSpy).toHaveBeenCalled();
|
||||||
@ -497,65 +502,101 @@ describe('GroupCloudComponent', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe('Multiple Mode and Pre-selected groups with validate flag', () => {
|
describe('Component readonly mode', () => {
|
||||||
|
const change = new SimpleChange(null, mockIdentityGroups, false);
|
||||||
|
|
||||||
beforeEach(async(() => {
|
it('should chip list be disabled and show one single chip - single mode', () => {
|
||||||
component.mode = 'multiple';
|
component.mode = 'single';
|
||||||
component.validate = true;
|
component.readOnly = true;
|
||||||
component.preSelectGroups = <any> mockIdentityGroups;
|
component.preSelectGroups = <any> mockIdentityGroups;
|
||||||
element = fixture.nativeElement;
|
component.ngOnChanges({ 'preSelectGroups': change });
|
||||||
alfrescoApiService = TestBed.get(AlfrescoApiService);
|
|
||||||
fixture.detectChanges();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should emit warning if are invalid groups', (done) => {
|
fixture.detectChanges();
|
||||||
findGroupsByNameSpy.and.returnValue(Promise.resolve([]));
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
const warnMessage = { message: 'INVALID_PRESELECTED_GROUPS', groups: [{ name: 'invalidGroupOne' }, { name: 'invalidGroupTwo' }] };
|
const chipList = fixture.nativeElement.querySelector('mat-chip-list');
|
||||||
component.validate = true;
|
expect(chips).toBeDefined();
|
||||||
component.preSelectGroups = <any> [{ name: 'invalidGroupOne' }, { name: 'invalidGroupTwo' }];
|
expect(chipList).toBeDefined();
|
||||||
fixture.detectChanges();
|
expect(chips.length).toBe(1);
|
||||||
component.loadSinglePreselectGroup();
|
expect(chipList.attributes['ng-reflect-disabled'].value).toEqual('true');
|
||||||
component.warning.subscribe((response) => {
|
});
|
||||||
expect(response).toEqual(warnMessage);
|
|
||||||
expect(response.message).toEqual(warnMessage.message);
|
it('should chip list be disabled and show all the chips - multiple mode', () => {
|
||||||
expect(response.groups).toEqual(warnMessage.groups);
|
component.mode = 'multiple';
|
||||||
expect(response.groups[0].name).toEqual('invalidGroupOne');
|
component.readOnly = true;
|
||||||
done();
|
component.preSelectGroups = <any> mockIdentityGroups;
|
||||||
|
component.ngOnChanges({ 'preSelectGroups': change });
|
||||||
|
fixture.detectChanges();
|
||||||
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
|
const chipList = fixture.nativeElement.querySelector('mat-chip-list');
|
||||||
|
expect(chips).toBeDefined();
|
||||||
|
expect(chipList).toBeDefined();
|
||||||
|
expect(chips.length).toBe(5);
|
||||||
|
expect(chipList.attributes['ng-reflect-disabled'].value).toEqual('true');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should filter group by name if validate true', (done) => {
|
describe('Preselected groups and validation enabled', () => {
|
||||||
findGroupsByNameSpy.and.returnValue(of(mockIdentityGroups));
|
|
||||||
component.mode = 'multiple';
|
it('should check validation only for the first group and emit warning when group is invalid - single mode', (done) => {
|
||||||
component.validate = true;
|
spyOn(identityGroupService, 'findGroupsByName').and.returnValue(Promise.resolve([]));
|
||||||
component.preSelectGroups = <any> [{ name: mockIdentityGroups[1].name }, { name: mockIdentityGroups[2].name }];
|
spyOn(component, 'hasGroupIdOrName').and.returnValue(false);
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
const expectedWarning = {
|
||||||
component.filterPreselectGroups().then((result) => {
|
message: 'INVALID_PRESELECTED_GROUPS',
|
||||||
expect(findGroupsByNameSpy).toHaveBeenCalled();
|
groups: [{
|
||||||
expect(component.groupExists(result[0])).toEqual(true);
|
id: mockIdentityGroups[0].id,
|
||||||
expect(component.groupExists(result[1])).toEqual(true);
|
name: mockIdentityGroups[0].name,
|
||||||
|
path: mockIdentityGroups[0].path,
|
||||||
|
subGroups: []
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
component.warning.subscribe(warning => {
|
||||||
|
expect(warning).toEqual(expectedWarning);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
component.mode = 'single';
|
||||||
|
component.validate = true;
|
||||||
|
component.preSelectGroups = <any> [mockIdentityGroups[0], mockIdentityGroups[1]];
|
||||||
|
component.ngOnChanges({ 'preSelectGroups': new SimpleChange(null, [mockIdentityGroups[0], mockIdentityGroups[1]], false) });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check validation for all the groups and emit warning - multiple mode', (done) => {
|
||||||
|
spyOn(identityGroupService, 'findGroupsByName').and.returnValue(Promise.resolve(undefined));
|
||||||
|
|
||||||
|
const expectedWarning = {
|
||||||
|
message: 'INVALID_PRESELECTED_GROUPS',
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
id: mockIdentityGroups[0].id,
|
||||||
|
name: mockIdentityGroups[0].name,
|
||||||
|
path: mockIdentityGroups[0].path,
|
||||||
|
subGroups: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: mockIdentityGroups[1].id,
|
||||||
|
name: mockIdentityGroups[1].name,
|
||||||
|
path: mockIdentityGroups[1].path,
|
||||||
|
subGroups: []
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
component.warning.subscribe(warning => {
|
||||||
|
expect(warning).toEqual(expectedWarning);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
component.mode = 'multiple';
|
||||||
|
component.validate = true;
|
||||||
|
component.preSelectGroups = <any> [mockIdentityGroups[0], mockIdentityGroups[1]];
|
||||||
|
component.ngOnChanges({ 'preSelectGroups': new SimpleChange(null, [mockIdentityGroups[0], mockIdentityGroups[1]], false) });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not preselect any group if name is invalid and validation enable', (done) => {
|
it('should removeDuplicatedGroups return only unique groups', () => {
|
||||||
findGroupsByNameSpy.and.returnValue(of([]));
|
const duplicatedGroups = [{ name: mockIdentityGroups[0].name }, { name: mockIdentityGroups[0].name }];
|
||||||
component.mode = 'single';
|
expect(component.removeDuplicatedGroups(duplicatedGroups)).toEqual([{ name: mockIdentityGroups[0].name }]);
|
||||||
component.validate = true;
|
|
||||||
component.preSelectGroups = <any> [{ name: 'invalid group' }];
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
component.validatePreselectGroups().then((result) => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(findGroupsByNameSpy).toHaveBeenCalled();
|
|
||||||
expect(result.length).toEqual(0);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -35,7 +35,12 @@ import { trigger, state, style, transition, animate } from '@angular/animations'
|
|||||||
import { Observable, of, BehaviorSubject, Subject } from 'rxjs';
|
import { Observable, of, BehaviorSubject, Subject } from 'rxjs';
|
||||||
import { debounceTime } from 'rxjs/internal/operators/debounceTime';
|
import { debounceTime } from 'rxjs/internal/operators/debounceTime';
|
||||||
import { distinctUntilChanged, switchMap, mergeMap, filter, tap, map, takeUntil } from 'rxjs/operators';
|
import { distinctUntilChanged, switchMap, mergeMap, filter, tap, map, takeUntil } from 'rxjs/operators';
|
||||||
import { IdentityGroupModel, IdentityGroupSearchParam, IdentityGroupService, LogService } from '@alfresco/adf-core';
|
import {
|
||||||
|
IdentityGroupModel,
|
||||||
|
IdentityGroupSearchParam,
|
||||||
|
IdentityGroupService,
|
||||||
|
LogService
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-cloud-group',
|
selector: 'adf-cloud-group',
|
||||||
@ -88,7 +93,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
|
|
||||||
/** FormControl to search the group */
|
/** FormControl to search the group */
|
||||||
@Input()
|
@Input()
|
||||||
searchGroupsControl: FormControl = new FormControl();
|
searchGroupsControl: FormControl = new FormControl({ value: '', disabled: false });
|
||||||
|
|
||||||
/** Role names of the groups to be listed. */
|
/** Role names of the groups to be listed. */
|
||||||
@Input()
|
@Input()
|
||||||
@ -113,61 +118,59 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
@ViewChild('groupInput')
|
@ViewChild('groupInput')
|
||||||
private groupInput: ElementRef<HTMLInputElement>;
|
private groupInput: ElementRef<HTMLInputElement>;
|
||||||
|
|
||||||
private selectedGroups: IdentityGroupModel[] = [];
|
|
||||||
|
|
||||||
private searchGroups: IdentityGroupModel[] = [];
|
private searchGroups: IdentityGroupModel[] = [];
|
||||||
|
private searchGroupsSubject: BehaviorSubject<IdentityGroupModel[]>;
|
||||||
|
private onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
searchGroups$ = new BehaviorSubject<IdentityGroupModel[]>([]);
|
selectedGroups: IdentityGroupModel[] = [];
|
||||||
|
invalidGroups: IdentityGroupModel[] = [];
|
||||||
selectedGroups$ = new BehaviorSubject<IdentityGroupModel[]>([]);
|
|
||||||
|
|
||||||
|
searchGroups$: Observable<IdentityGroupModel[]>;
|
||||||
_subscriptAnimationState = 'enter';
|
_subscriptAnimationState = 'enter';
|
||||||
|
|
||||||
clientId: string;
|
clientId: string;
|
||||||
|
|
||||||
searchedValue = '';
|
|
||||||
|
|
||||||
isFocused: boolean;
|
isFocused: boolean;
|
||||||
|
|
||||||
isDisabled: boolean;
|
|
||||||
|
|
||||||
private onDestroy$ = new Subject<boolean>();
|
|
||||||
currentTimeout: any;
|
currentTimeout: any;
|
||||||
invalidGroups: IdentityGroupModel[] = [];
|
validateGroupsMessage: string;
|
||||||
|
searchedValue = '';
|
||||||
|
|
||||||
|
isLoading = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private identityGroupService: IdentityGroupService,
|
private identityGroupService: IdentityGroupService,
|
||||||
private logService: LogService
|
private logService: LogService) {}
|
||||||
) { }
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
if (this.searchGroupsSubject === undefined) {
|
||||||
|
this.searchGroupsSubject = new BehaviorSubject<IdentityGroupModel[]>(this.searchGroups);
|
||||||
|
this.searchGroups$ = this.searchGroupsSubject.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadClientId();
|
||||||
this.initSearch();
|
this.initSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
|
||||||
if (this.isPreselectedGroupsChanged(changes)) {
|
if (this.hasPreselectedGroupsChanged(changes) || this.hasModeChanged(changes) || this.isValidationChanged(changes)) {
|
||||||
if (this.isValidationEnabled()) {
|
if (this.hasPreSelectGroups()) {
|
||||||
this.loadPreSelectGroups();
|
this.loadPreSelectGroups();
|
||||||
} else {
|
} else if (this.hasPreselectedGroupsCleared(changes)) {
|
||||||
this.loadNoValidationPreselectGroups();
|
this.selectedGroups = [];
|
||||||
|
this.invalidGroups = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isValidationEnabled()) {
|
||||||
|
this.invalidGroups = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isAppNameChanged(changes.appName)) {
|
if (changes.appName && this.isAppNameChanged(changes.appName)) {
|
||||||
this.disableSearch();
|
|
||||||
this.loadClientId();
|
this.loadClientId();
|
||||||
} else {
|
this.initSearch();
|
||||||
this.enableSearch();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private isPreselectedGroupsChanged(changes: SimpleChanges): boolean {
|
|
||||||
return changes.preSelectGroups
|
|
||||||
&& changes.preSelectGroups.previousValue !== changes.preSelectGroups.currentValue
|
|
||||||
&& this.hasPreSelectGroups();
|
|
||||||
}
|
|
||||||
|
|
||||||
private isAppNameChanged(change: SimpleChange): boolean {
|
private isAppNameChanged(change: SimpleChange): boolean {
|
||||||
return change && change.previousValue !== change.currentValue && this.appName && this.appName.length > 0;
|
return change && change.previousValue !== change.currentValue && this.appName && this.appName.length > 0;
|
||||||
}
|
}
|
||||||
@ -175,23 +178,23 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
private async loadClientId() {
|
private async loadClientId() {
|
||||||
this.clientId = await this.identityGroupService.getClientIdByApplicationName(this.appName).toPromise();
|
this.clientId = await this.identityGroupService.getClientIdByApplicationName(this.appName).toPromise();
|
||||||
if (this.clientId) {
|
if (this.clientId) {
|
||||||
this.enableSearch();
|
this.searchGroupsControl.enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initSearch() {
|
initSearch() {
|
||||||
this.searchGroupsControl.valueChanges.pipe(
|
this.searchGroupsControl.valueChanges.pipe(
|
||||||
|
debounceTime(500),
|
||||||
|
distinctUntilChanged(),
|
||||||
filter((value) => {
|
filter((value) => {
|
||||||
return typeof value === 'string';
|
return typeof value === 'string';
|
||||||
}),
|
}),
|
||||||
tap((value) => {
|
tap((value) => {
|
||||||
this.searchedValue = value;
|
this.searchedValue = value;
|
||||||
if (value) {
|
if (value) {
|
||||||
this.setError();
|
this.setTypingError();
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
debounceTime(500),
|
|
||||||
distinctUntilChanged(),
|
|
||||||
tap(() => {
|
tap(() => {
|
||||||
this.resetSearchGroups();
|
this.resetSearchGroups();
|
||||||
}),
|
}),
|
||||||
@ -221,7 +224,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
takeUntil(this.onDestroy$)
|
takeUntil(this.onDestroy$)
|
||||||
).subscribe((searchedGroup: any) => {
|
).subscribe((searchedGroup: any) => {
|
||||||
this.searchGroups.push(searchedGroup);
|
this.searchGroups.push(searchedGroup);
|
||||||
this.searchGroups$.next(this.searchGroups);
|
this.searchGroupsSubject.next(this.searchGroups);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,7 +239,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
private isGroupAlreadySelected(group: IdentityGroupModel): boolean {
|
private isGroupAlreadySelected(group: IdentityGroupModel): boolean {
|
||||||
if (this.selectedGroups && this.selectedGroups.length > 0 && this.isMultipleMode()) {
|
if (this.selectedGroups && this.selectedGroups.length > 0 && this.isMultipleMode()) {
|
||||||
const result = this.selectedGroups.find((selectedGroup: IdentityGroupModel) => {
|
const result = this.selectedGroups.find((selectedGroup: IdentityGroupModel) => {
|
||||||
return selectedGroup.id === group.id;
|
return selectedGroup.name === group.name;
|
||||||
});
|
});
|
||||||
|
|
||||||
return !!result;
|
return !!result;
|
||||||
@ -244,115 +247,74 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async searchGroup(groupName: any): Promise<IdentityGroupModel> {
|
async searchGroup(groupName: string): Promise<IdentityGroupModel> {
|
||||||
return (await this.identityGroupService.findGroupsByName(this.createSearchParam(groupName)).toPromise())[0];
|
return (await this.identityGroupService.findGroupsByName({ name: groupName }).toPromise())[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
async filterPreselectGroups() {
|
async validatePreselectGroups(): Promise<any> {
|
||||||
const promiseBatch = this.preSelectGroups.map(async (group: IdentityGroupModel) => {
|
this.invalidGroups = [];
|
||||||
let result: any;
|
|
||||||
|
let preselectedGroupsToValidate: IdentityGroupModel[] = [];
|
||||||
|
|
||||||
|
if (this.isSingleMode()) {
|
||||||
|
preselectedGroupsToValidate = [this.preSelectGroups[0]];
|
||||||
|
} else {
|
||||||
|
preselectedGroupsToValidate = this.removeDuplicatedGroups(this.preSelectGroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(preselectedGroupsToValidate.map(async (group: IdentityGroupModel) => {
|
||||||
try {
|
try {
|
||||||
result = await this.searchGroup(group.name);
|
const validationResult = await this.searchGroup(group.name);
|
||||||
|
if (!this.hasGroupIdOrName(validationResult)) {
|
||||||
|
this.invalidGroups.push(group);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
result = [];
|
this.invalidGroups.push(group);
|
||||||
this.logService.error(error);
|
this.logService.error(error);
|
||||||
}
|
}
|
||||||
const isGroupValid: boolean = this.groupExists(result);
|
}));
|
||||||
return isGroupValid ? result : null;
|
this.checkPreselectValidationErrors();
|
||||||
});
|
this.isLoading = false;
|
||||||
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<IdentityGroupModel[]> {
|
|
||||||
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() {
|
public checkPreselectValidationErrors() {
|
||||||
|
|
||||||
|
this.invalidGroups = this.removeDuplicatedGroups(this.invalidGroups);
|
||||||
|
|
||||||
if (this.invalidGroups.length > 0) {
|
if (this.invalidGroups.length > 0) {
|
||||||
this.warning.emit({
|
this.generateInvalidGroupsMessage();
|
||||||
message: 'INVALID_PRESELECTED_GROUPS',
|
|
||||||
groups: this.invalidGroups
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.warning.emit({
|
||||||
|
message: 'INVALID_PRESELECTED_GROUPS',
|
||||||
|
groups: this.invalidGroups
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadPreSelectGroups() {
|
generateInvalidGroupsMessage() {
|
||||||
if (!this.isMultipleMode()) {
|
this.validateGroupsMessage = '';
|
||||||
this.loadSinglePreselectGroup();
|
|
||||||
} else {
|
|
||||||
this.loadMultiplePreselectGroups();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadNoValidationPreselectGroups() {
|
this.invalidGroups.forEach((invalidGroup: IdentityGroupModel, index) => {
|
||||||
this.selectedGroups = [...this.removeDuplicatedGroups([...this.preSelectGroups])];
|
if (index === this.invalidGroups.length - 1) {
|
||||||
if (this.isMultipleMode()) {
|
this.validateGroupsMessage += `${invalidGroup.name} `;
|
||||||
this.selectedGroups$.next(this.selectedGroups);
|
} else {
|
||||||
} else {
|
this.validateGroupsMessage += `${invalidGroup.name}, `;
|
||||||
|
|
||||||
if (this.currentTimeout) {
|
|
||||||
clearTimeout(this.currentTimeout);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.currentTimeout = setTimeout(() => {
|
private async loadPreSelectGroups() {
|
||||||
this.searchGroupsControl.setValue(this.selectedGroups[0]);
|
this.selectedGroups = [];
|
||||||
this.onSelect(this.selectedGroups[0]);
|
|
||||||
}, 0);
|
if (this.isSingleMode()) {
|
||||||
|
this.selectedGroups = [this.preSelectGroups[0]];
|
||||||
|
} else {
|
||||||
|
this.selectedGroups = this.removeDuplicatedGroups(this.preSelectGroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isValidationEnabled()) {
|
||||||
|
this.isLoading = true;
|
||||||
|
await this.validatePreselectGroups();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,33 +330,67 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
if (this.isMultipleMode()) {
|
if (this.isMultipleMode()) {
|
||||||
if (!this.isGroupAlreadySelected(group)) {
|
if (!this.isGroupAlreadySelected(group)) {
|
||||||
this.selectedGroups.push(group);
|
this.selectedGroups.push(group);
|
||||||
this.selectedGroups$.next(this.selectedGroups);
|
|
||||||
this.searchGroups$.next([]);
|
|
||||||
}
|
}
|
||||||
this.groupInput.nativeElement.value = '';
|
|
||||||
this.searchGroupsControl.setValue('');
|
|
||||||
} else {
|
} else {
|
||||||
|
this.invalidGroups = [];
|
||||||
this.selectedGroups = [group];
|
this.selectedGroups = [group];
|
||||||
}
|
}
|
||||||
this.changedGroups.emit(this.selectedGroups);
|
|
||||||
|
|
||||||
this.clearError();
|
this.groupInput.nativeElement.value = '';
|
||||||
|
this.searchGroupsControl.setValue('');
|
||||||
|
|
||||||
|
this.changedGroups.emit(this.selectedGroups);
|
||||||
this.resetSearchGroups();
|
this.resetSearchGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemove(removedGroup: IdentityGroupModel) {
|
onRemove(groupToRemove: IdentityGroupModel) {
|
||||||
this.removeGroup.emit(removedGroup);
|
this.removeGroup.emit(groupToRemove);
|
||||||
const indexToRemove = this.selectedGroups.findIndex((group: IdentityGroupModel) => {
|
const indexToRemove = this.selectedGroups.findIndex((group: IdentityGroupModel) => {
|
||||||
return group.id === removedGroup.id;
|
return group.id === groupToRemove.id;
|
||||||
});
|
});
|
||||||
this.selectedGroups.splice(indexToRemove, 1);
|
this.selectedGroups.splice(indexToRemove, 1);
|
||||||
this.selectedGroups$.next(this.selectedGroups);
|
|
||||||
this.changedGroups.emit(this.selectedGroups);
|
this.changedGroups.emit(this.selectedGroups);
|
||||||
|
this.searchGroupsControl.markAsDirty();
|
||||||
|
|
||||||
|
if (this.isValidationEnabled()) {
|
||||||
|
this.removeGroupFromValidation(groupToRemove.name);
|
||||||
|
this.checkPreselectValidationErrors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeGroupFromValidation(groupName: string) {
|
||||||
|
const indexToRemove = this.invalidGroups.findIndex((invalidGroup) => {
|
||||||
|
return invalidGroup.name === groupName;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (indexToRemove !== -1) {
|
||||||
|
this.invalidGroups.splice(indexToRemove, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private resetSearchGroups() {
|
private resetSearchGroups() {
|
||||||
this.searchGroups = [];
|
this.searchGroups = [];
|
||||||
this.searchGroups$.next([]);
|
this.searchGroupsSubject.next(this.searchGroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
hasGroupIdOrName(group: IdentityGroupModel): boolean {
|
||||||
|
return group && (group.id !== undefined || group.name !== undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
isSingleMode(): boolean {
|
||||||
|
return this.mode === GroupCloudComponent.MODE_SINGLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isSingleSelectionReadonly(): boolean {
|
||||||
|
return this.isSingleMode() && this.selectedGroups.length === 1 && this.selectedGroups[0].readonly === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasPreselectError(): boolean {
|
||||||
|
return this.invalidGroups && this.invalidGroups.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
isReadonly(): boolean {
|
||||||
|
return this.readOnly || this.isSingleSelectionReadonly();
|
||||||
}
|
}
|
||||||
|
|
||||||
isMultipleMode(): boolean {
|
isMultipleMode(): boolean {
|
||||||
@ -405,58 +401,76 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
return group ? group.name : '';
|
return group ? group.name : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeDuplicatedGroups(groups: IdentityGroupModel[]): IdentityGroupModel[] {
|
removeDuplicatedGroups(groups: IdentityGroupModel[]): IdentityGroupModel[] {
|
||||||
return groups.filter((group, index, self) =>
|
return groups.filter((group, index, self) =>
|
||||||
index === self.findIndex((auxGroup) => {
|
index === self.findIndex((auxGroup) => {
|
||||||
return group.id === auxGroup.id && group.name === auxGroup.name;
|
return group.id === auxGroup.id && group.name === auxGroup.name;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private hasPreSelectGroups(): boolean {
|
private hasPreSelectGroups(): boolean {
|
||||||
return this.preSelectGroups && this.preSelectGroups.length > 0;
|
return this.preSelectGroups && this.preSelectGroups.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private hasModeChanged(changes): boolean {
|
||||||
|
return changes && changes.mode && changes.mode.currentValue !== changes.mode.previousValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isValidationChanged(changes): boolean {
|
||||||
|
return changes && changes.validate && changes.validate.currentValue !== changes.validate.previousValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasPreselectedGroupsChanged(changes): boolean {
|
||||||
|
return changes && changes.preSelectGroups && changes.preSelectGroups.currentValue !== changes.preSelectGroups.previousValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasPreselectedGroupsCleared(changes): boolean {
|
||||||
|
return changes && changes.preSelectGroups && changes.preSelectGroups.currentValue.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
private createSearchParam(value: string): IdentityGroupSearchParam {
|
private createSearchParam(value: string): IdentityGroupSearchParam {
|
||||||
const queryParams: IdentityGroupSearchParam = { name: value };
|
const queryParams: IdentityGroupSearchParam = { name: value };
|
||||||
return queryParams;
|
return queryParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSelectedGroups(): IdentityGroupModel[] {
|
||||||
|
return this.selectedGroups;
|
||||||
|
}
|
||||||
|
|
||||||
private hasRoles(): boolean {
|
private hasRoles(): boolean {
|
||||||
return this.roles && this.roles.length > 0;
|
return this.roles && this.roles.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private disableSearch() {
|
private setTypingError() {
|
||||||
this.searchGroupsControl.disable();
|
this.searchGroupsControl.setErrors({ searchTypingError: true, ...this.searchGroupsControl.errors });
|
||||||
this.isDisabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private enableSearch() {
|
|
||||||
this.searchGroupsControl.enable();
|
|
||||||
this.isDisabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private setError() {
|
|
||||||
this.searchGroupsControl.setErrors({ invalid: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
private clearError() {
|
|
||||||
this.searchGroupsControl.setErrors(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hasError(): boolean {
|
hasError(): boolean {
|
||||||
return this.searchGroupsControl && this.searchGroupsControl.errors && (this.searchGroupsControl.errors.invalid || this.searchGroupsControl.errors.required);
|
return !!this.searchGroupsControl.errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidationLoading(): boolean {
|
||||||
|
return this.isValidationEnabled() && this.isLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
setFocus(isFocused: boolean) {
|
setFocus(isFocused: boolean) {
|
||||||
this.isFocused = isFocused;
|
this.isFocused = isFocused;
|
||||||
}
|
}
|
||||||
|
|
||||||
isValidationEnabled() {
|
isValidationEnabled(): boolean {
|
||||||
return this.validate === true;
|
return this.validate === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasErrorMessage(): boolean {
|
getValidationPattern(): string {
|
||||||
return !this.isFocused && this.hasError();
|
return this.searchGroupsControl.errors.pattern.requiredPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
getValidationMaxLength(): string {
|
||||||
|
return this.searchGroupsControl.errors.maxlength.requiredLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
getValidationMinLength(): string {
|
||||||
|
return this.searchGroupsControl.errors.minlength.requiredLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
@ -181,6 +181,20 @@
|
|||||||
"NOT_FOUND": "No group found with the name {{groupName}}"
|
"NOT_FOUND": "No group found with the name {{groupName}}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"ADF_CLOUD_USERS": {
|
||||||
|
"ERROR": {
|
||||||
|
"NOT_FOUND": "No user found with the name {{userName}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ADF_CLOUD_PEOPLE_GROUPS": {
|
||||||
|
"ERROR": {
|
||||||
|
"INVALID_PATTERN": "Not mathcing pattern {{pattern}}",
|
||||||
|
"INVALID_MIN_LENGTH": "Minimum length {{requiredLength}}",
|
||||||
|
"INVALID_MAX_LENGTH": "Maximum length {{requiredLength}}",
|
||||||
|
"REQUIRED": "Field is required"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ADF_CLOUD_TASK_HEADER": {
|
"ADF_CLOUD_TASK_HEADER": {
|
||||||
"BUTTON": {
|
"BUTTON": {
|
||||||
"CLAIM": "Claim",
|
"CLAIM": "Claim",
|
||||||
|
@ -1,47 +1,35 @@
|
|||||||
<form>
|
<form>
|
||||||
<mat-form-field class="adf-people-cloud">
|
<mat-form-field class="adf-people-cloud">
|
||||||
<mat-label id="adf-people-cloud-title-id">{{ title | translate }}</mat-label>
|
<mat-label id="adf-people-cloud-title-id">{{ title | translate }}</mat-label>
|
||||||
<mat-chip-list #userChipList *ngIf="isMultipleMode(); else singleSelection">
|
<mat-chip-list #userMultipleChipList [disabled]="isReadonly() || isValidationLoading()" data-automation-id="adf-cloud-people-chip-list">
|
||||||
<mat-chip
|
<mat-chip
|
||||||
*ngFor="let user of selectedUsers$ | async"
|
*ngFor="let user of selectedUsers"
|
||||||
[removable]="!(user.readonly)"
|
[removable]="!(user.readonly)"
|
||||||
[attr.data-automation-id]="'adf-people-cloud-chip-' + user.username"
|
[attr.data-automation-id]="'adf-people-cloud-chip-' + user.username"
|
||||||
matTooltip="{{ (user.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}"
|
(removed)="onRemove(user)"
|
||||||
(removed)="onRemove(user)">
|
matTooltip="{{ (user.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}">
|
||||||
{{user | fullName}}
|
{{user | fullName}}
|
||||||
<mat-icon
|
<mat-icon
|
||||||
matChipRemove
|
matChipRemove
|
||||||
*ngIf="!(user.readonly || readOnly)"
|
*ngIf="!(user.readonly || readOnly)"
|
||||||
[attr.data-automation-id]="'adf-people-cloud-chip-remove-icon-' + user.username">
|
[attr.data-automation-id]="'adf-people-cloud-chip-remove-icon-' + user.username">
|
||||||
cancel
|
cancel
|
||||||
</mat-icon>
|
</mat-icon>
|
||||||
</mat-chip>
|
</mat-chip>
|
||||||
<input
|
<input matInput
|
||||||
#userInput
|
[formControl]="searchUserCtrl"
|
||||||
matInput
|
[matAutocomplete]="auto"
|
||||||
[formControl]="searchUserCtrl"
|
[matChipInputFor]="userMultipleChipList"
|
||||||
[matAutocomplete]="auto"
|
(focus)="setFocus(true)"
|
||||||
[matChipInputFor]="userChipList"
|
(blur)="setFocus(false)"
|
||||||
class="adf-cloud-input"
|
class="adf-cloud-input"
|
||||||
(focus)="setFocus(true)"
|
data-automation-id="adf-people-cloud-search-input" #userInput>
|
||||||
(blur)="setFocus(false)"
|
|
||||||
data-automation-id="adf-people-cloud-search-input">
|
|
||||||
</mat-chip-list>
|
</mat-chip-list>
|
||||||
|
|
||||||
<ng-template #singleSelection>
|
|
||||||
<input matInput
|
|
||||||
(focus)="setFocus(true)"
|
|
||||||
(blur)="setFocus(false)"
|
|
||||||
class="adf-cloud-input"
|
|
||||||
data-automation-id="adf-people-cloud-search-input"
|
|
||||||
type="text"
|
|
||||||
[formControl]="searchUserCtrl"
|
|
||||||
[matAutocomplete]="auto">
|
|
||||||
</ng-template>
|
|
||||||
<mat-autocomplete autoActiveFirstOption class="adf-people-cloud-list"
|
<mat-autocomplete autoActiveFirstOption class="adf-people-cloud-list"
|
||||||
#auto="matAutocomplete"
|
#auto="matAutocomplete"
|
||||||
(optionSelected)="onSelect($event.option.value)"
|
(optionSelected)="onSelect($event.option.value)"
|
||||||
[displayWith]="getDisplayName">
|
[displayWith]="getDisplayName">
|
||||||
<mat-option *ngFor="let user of searchUsers$ | async; let i = index" [value]="user">
|
<mat-option *ngFor="let user of searchUsers$ | async; let i = index" [value]="user">
|
||||||
<div class="adf-people-cloud-row" id="adf-people-cloud-user-{{i}}">
|
<div class="adf-people-cloud-row" id="adf-people-cloud-user-{{i}}">
|
||||||
<div [outerHTML]="user | usernameInitials:'adf-people-widget-pic'"></div>
|
<div [outerHTML]="user | usernameInitials:'adf-people-widget-pic'"></div>
|
||||||
@ -50,10 +38,28 @@
|
|||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-autocomplete>
|
</mat-autocomplete>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<div class="adf-start-task-cloud-error">
|
<mat-progress-bar
|
||||||
<div *ngIf="hasErrorMessage()" fxLayout="row" fxLayoutAlign="start start" [@transitionMessages]="_subscriptAnimationState">
|
*ngIf="isLoading"
|
||||||
<div class="adf-start-task-cloud-error-message">{{ 'ADF_CLOUD_START_TASK.ERROR.MESSAGE' | translate }}</div>
|
mode="indeterminate">
|
||||||
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
</mat-progress-bar>
|
||||||
</div>
|
|
||||||
</div>
|
<mat-error *ngIf="hasPreselectError() && !isValidationLoading()">
|
||||||
|
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
||||||
|
{{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate : { userName : validateUsersMessage } }}</mat-error>
|
||||||
|
<mat-error *ngIf="searchUserCtrl.hasError('pattern')">
|
||||||
|
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
||||||
|
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_PATTERN' | translate: { pattern: getValidationPattern() } }}</mat-error>
|
||||||
|
<mat-error *ngIf="searchUserCtrl.hasError('maxlength')">
|
||||||
|
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
||||||
|
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MAX_LENGTH' | translate: { requiredLength: getValidationMaxLength() } }}
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="searchUserCtrl.hasError('minlength')">
|
||||||
|
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
||||||
|
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MIN_LENGTH' | translate: { requiredLength: getValidationMinLength() } }}</mat-error>
|
||||||
|
<mat-error *ngIf="searchUserCtrl.hasError('required')">
|
||||||
|
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
||||||
|
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.REQUIRED' | translate }} </mat-error>
|
||||||
|
<mat-error *ngIf="searchUserCtrl.hasError('searchTypingError') && !this.isFocused" data-automation-id="invalid-users-typing-error">
|
||||||
|
<mat-icon class="adf-start-task-cloud-error-icon">warning</mat-icon>
|
||||||
|
{{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate : { userName : searchedValue } }}</mat-error>
|
||||||
</form>
|
</form>
|
||||||
|
@ -17,7 +17,12 @@
|
|||||||
|
|
||||||
import { PeopleCloudComponent } from './people-cloud.component';
|
import { PeopleCloudComponent } from './people-cloud.component';
|
||||||
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||||
import { IdentityUserService, AlfrescoApiService, CoreModule, setupTestBed } from '@alfresco/adf-core';
|
import {
|
||||||
|
IdentityUserService,
|
||||||
|
AlfrescoApiService,
|
||||||
|
CoreModule,
|
||||||
|
setupTestBed
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module';
|
import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module';
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import { mockUsers } from '../mock/user-cloud.mock';
|
import { mockUsers } from '../mock/user-cloud.mock';
|
||||||
@ -32,7 +37,6 @@ describe('PeopleCloudComponent', () => {
|
|||||||
let identityService: IdentityUserService;
|
let identityService: IdentityUserService;
|
||||||
let alfrescoApiService: AlfrescoApiService;
|
let alfrescoApiService: AlfrescoApiService;
|
||||||
let findUsersByNameSpy: jasmine.Spy;
|
let findUsersByNameSpy: jasmine.Spy;
|
||||||
let findUserByUsernameSpy: jasmine.Spy;
|
|
||||||
|
|
||||||
const mock = {
|
const mock = {
|
||||||
oauth2Auth: {
|
oauth2Auth: {
|
||||||
@ -62,7 +66,6 @@ describe('PeopleCloudComponent', () => {
|
|||||||
identityService = TestBed.get(IdentityUserService);
|
identityService = TestBed.get(IdentityUserService);
|
||||||
alfrescoApiService = TestBed.get(AlfrescoApiService);
|
alfrescoApiService = TestBed.get(AlfrescoApiService);
|
||||||
spyOn(alfrescoApiService, 'getInstance').and.returnValue(mock);
|
spyOn(alfrescoApiService, 'getInstance').and.returnValue(mock);
|
||||||
findUserByUsernameSpy = spyOn(identityService, 'findUserByUsername').and.returnValue(Promise.resolve([]));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create PeopleCloudComponent', () => {
|
it('should create PeopleCloudComponent', () => {
|
||||||
@ -73,7 +76,7 @@ describe('PeopleCloudComponent', () => {
|
|||||||
component.title = 'TITLE_KEY';
|
component.title = 'TITLE_KEY';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const matLabel: HTMLInputElement = <HTMLInputElement> fixture.nativeElement.querySelector('#adf-people-cloud-title-id');
|
const matLabel: HTMLInputElement = <HTMLInputElement> fixture.nativeElement.querySelector('#adf-people-cloud-title-id');
|
||||||
fixture.whenStable().then( () => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(matLabel.textContent).toEqual('TITLE_KEY');
|
expect(matLabel.textContent).toEqual('TITLE_KEY');
|
||||||
});
|
});
|
||||||
@ -83,7 +86,7 @@ describe('PeopleCloudComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const matLabel: HTMLInputElement = <HTMLInputElement> fixture.nativeElement.querySelector('#adf-people-cloud-title-id');
|
const matLabel: HTMLInputElement = <HTMLInputElement> fixture.nativeElement.querySelector('#adf-people-cloud-title-id');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable().then( () => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(matLabel.textContent).toEqual('');
|
expect(matLabel.textContent).toEqual('');
|
||||||
});
|
});
|
||||||
@ -97,14 +100,14 @@ describe('PeopleCloudComponent', () => {
|
|||||||
findUsersByNameSpy = spyOn(identityService, 'findUsersByName').and.returnValue(of(mockUsers));
|
findUsersByNameSpy = spyOn(identityService, 'findUsersByName').and.returnValue(of(mockUsers));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should list the users if the typed result match', (done) => {
|
it('should list the users as dropdown options if the search term has results', (done) => {
|
||||||
findUsersByNameSpy.and.returnValue(of(mockUsers));
|
|
||||||
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
|
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
|
||||||
inputHTMLElement.focus();
|
inputHTMLElement.focus();
|
||||||
inputHTMLElement.value = 'first';
|
inputHTMLElement.value = 'first';
|
||||||
inputHTMLElement.dispatchEvent(new Event('keyup'));
|
inputHTMLElement.dispatchEvent(new Event('keyup'));
|
||||||
inputHTMLElement.dispatchEvent(new Event('input'));
|
inputHTMLElement.dispatchEvent(new Event('input'));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(3);
|
expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(3);
|
||||||
@ -127,13 +130,19 @@ describe('PeopleCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit selectedUser if option is valid', (done) => {
|
it('should selectedUser and changedUsers emit, update selected users when a user is selected', (done) => {
|
||||||
|
const user = { username: 'username' };
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
spyOn(component, 'hasUserDetails').and.returnValue(true);
|
||||||
const selectEmitSpy = spyOn(component.selectUser, 'emit');
|
const selectEmitSpy = spyOn(component.selectUser, 'emit');
|
||||||
component.onSelect({ username: 'username' });
|
const changedUsersSpy = spyOn(component.changedUsers, 'emit');
|
||||||
|
component.onSelect(user);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
expect(selectEmitSpy).toHaveBeenCalled();
|
expect(selectEmitSpy).toHaveBeenCalledWith(user);
|
||||||
|
expect(changedUsersSpy).toHaveBeenCalledWith([user]);
|
||||||
|
expect(component.getSelectedUsers()).toEqual([user]);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -150,9 +159,9 @@ describe('PeopleCloudComponent', () => {
|
|||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
inputHTMLElement.blur();
|
inputHTMLElement.blur();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const errorMessage = element.querySelector('.adf-start-task-cloud-error-message');
|
const errorMessage = element.querySelector('[data-automation-id="invalid-users-typing-error"]');
|
||||||
expect(errorMessage).not.toBeNull();
|
expect(errorMessage).not.toBeNull();
|
||||||
expect(errorMessage.textContent).toContain('ADF_CLOUD_START_TASK.ERROR.MESSAGE');
|
expect(errorMessage.textContent).toContain('ADF_CLOUD_USERS.ERROR.NOT_FOUND');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -173,6 +182,18 @@ describe('PeopleCloudComponent', () => {
|
|||||||
element = fixture.nativeElement;
|
element = fixture.nativeElement;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should fetch the client ID if appName specified', async (() => {
|
||||||
|
const getClientIdByApplicationNameSpy = spyOn(identityService, 'getClientIdByApplicationName').and.callThrough();
|
||||||
|
component.appName = 'mock-app-name';
|
||||||
|
const change = new SimpleChange(null, 'mock-app-name', false);
|
||||||
|
component.ngOnChanges({ 'appName': change });
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(getClientIdByApplicationNameSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it('should list users who have access to the app when appName is specified', (done) => {
|
it('should list users who have access to the app when appName is specified', (done) => {
|
||||||
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
|
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
|
||||||
inputHTMLElement.focus();
|
inputHTMLElement.focus();
|
||||||
@ -293,14 +314,34 @@ describe('PeopleCloudComponent', () => {
|
|||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
inputHTMLElement.blur();
|
inputHTMLElement.blur();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const errorMessage = element.querySelector('.adf-start-task-cloud-error-message');
|
const errorMessage = element.querySelector('[data-automation-id="invalid-users-typing-error"]');
|
||||||
expect(errorMessage).not.toBeNull();
|
expect(errorMessage).not.toBeNull();
|
||||||
expect(errorMessage.textContent).toContain('ADF_CLOUD_START_TASK.ERROR.MESSAGE');
|
expect(errorMessage.textContent).toContain('ADF_CLOUD_USERS.ERROR.NOT_FOUND');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('No preselected users', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not pre-select any user when preSelectUsers is empty - single mode', () => {
|
||||||
|
component.mode = 'single';
|
||||||
|
fixture.detectChanges();
|
||||||
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
|
expect(chips.length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not pre-select any users when preSelectUsers is empty - multiple mode', () => {
|
||||||
|
component.mode = 'multiple';
|
||||||
|
fixture.detectChanges();
|
||||||
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
|
expect(chips.length).toEqual(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('When roles defined', () => {
|
describe('When roles defined', () => {
|
||||||
|
|
||||||
let checkUserHasRoleSpy: jasmine.Spy;
|
let checkUserHasRoleSpy: jasmine.Spy;
|
||||||
@ -360,311 +401,170 @@ describe('PeopleCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Single Mode and Pre-selected users with no validate flag', () => {
|
describe('Single Mode with Pre-selected users', () => {
|
||||||
|
|
||||||
|
const changes = new SimpleChange(null, mockPreselectedUsers, false);
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
component.mode = 'single';
|
component.mode = 'single';
|
||||||
component.preSelectUsers = <any> mockPreselectedUsers;
|
component.preSelectUsers = <any> mockPreselectedUsers;
|
||||||
|
component.ngOnChanges({ 'preSelectUsers': changes });
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
element = fixture.nativeElement;
|
element = fixture.nativeElement;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not show chip list when mode=single', (done) => {
|
it('should show only one mat chip with the first preSelectedUser', (done) => {
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
const chip = element.querySelector('mat-chip-list');
|
|
||||||
expect(chip).toBeNull();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not pre-select any user when preSelectUsers is empty and mode=single', (done) => {
|
|
||||||
component.preSelectUsers = [];
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
const selectedUser = component.searchUserCtrl.value;
|
|
||||||
expect(selectedUser).toBeNull();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Single Mode and Pre-selected users with validate flag', () => {
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
component.mode = 'single';
|
|
||||||
component.validate = true;
|
|
||||||
component.preSelectUsers = <any> mockPreselectedUsers;
|
|
||||||
fixture.detectChanges();
|
|
||||||
element = fixture.nativeElement;
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should not show chip list when mode=single', (done) => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
const chip = element.querySelector('mat-chip-list');
|
|
||||||
expect(chip).toBeNull();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Multiple Mode and Pre-selected users with no validate flag', () => {
|
|
||||||
|
|
||||||
const change = new SimpleChange(null, mockPreselectedUsers, false);
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
component.mode = 'multiple';
|
|
||||||
component.preSelectUsers = <any> mockPreselectedUsers;
|
|
||||||
fixture.detectChanges();
|
|
||||||
element = fixture.nativeElement;
|
|
||||||
alfrescoApiService = TestBed.get(AlfrescoApiService);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should show chip list when mode=multiple', (done) => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
const chip = element.querySelector('mat-chip-list');
|
|
||||||
expect(chip).toBeDefined();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should pre-select all preSelectUsers when mode=multiple validation disabled', (done) => {
|
|
||||||
component.mode = 'multiple';
|
|
||||||
spyOn(component, 'filterPreselectUsers').and.returnValue(Promise.resolve(mockPreselectedUsers));
|
|
||||||
component.ngOnChanges({ 'preSelectUsers': change });
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
component.selectedUsers$.subscribe((selectedUsers) => {
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
expect(selectedUsers).toBeDefined();
|
expect(chips.length).toEqual(1);
|
||||||
expect(selectedUsers.length).toEqual(2);
|
expect(chips[0].attributes['data-automation-id']).toEqual(`adf-people-cloud-chip-${mockPreselectedUsers[0].username}`);
|
||||||
expect(selectedUsers[0].id).toEqual('fake-id-2');
|
done();
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Multiple Mode with read-only mode', () => {
|
describe('Multiple Mode with Pre-selected Users', () => {
|
||||||
|
|
||||||
it('Should not show remove icon for pre-selected users if readonly property set to true', (done) => {
|
it('Should not show remove icon for pre-selected users if readonly property set to true', (done) => {
|
||||||
component.mode = 'multiple';
|
fixture.detectChanges();
|
||||||
const removeUserSpy = spyOn(component.removeUser, 'emit');
|
|
||||||
component.preSelectUsers = [
|
component.preSelectUsers = [
|
||||||
{ id: mockUsers[0].id, username: mockUsers[0].username, readonly: true },
|
{ id: mockUsers[0].id, username: mockUsers[0].username, readonly: true },
|
||||||
{ id: mockUsers[1].id, username: mockUsers[1].username, readonly: true }
|
{ id: mockUsers[1].id, username: mockUsers[1].username, readonly: true }
|
||||||
];
|
];
|
||||||
fixture.detectChanges();
|
const change = new SimpleChange(null, component.preSelectUsers, false);
|
||||||
const chipList = fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip');
|
|
||||||
const removeIcon = <HTMLElement> fixture.nativeElement.querySelector('[data-automation-id="adf-people-cloud-chip-remove-icon-first-name-1 last-name-1"]');
|
|
||||||
expect(chipList.length).toBe(2);
|
|
||||||
expect(component.preSelectUsers[0].readonly).toBeTruthy();
|
|
||||||
expect(component.preSelectUsers[1].readonly).toBeTruthy();
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(removeIcon).toBeNull();
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(removeUserSpy).not.toHaveBeenCalled();
|
|
||||||
expect(component.preSelectUsers.length).toBe(2);
|
|
||||||
expect(component.preSelectUsers[0].readonly).toBe(true, 'Not removable');
|
|
||||||
expect(component.preSelectUsers[1].readonly).toBe(true, 'not removable');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Multiple Mode and Pre-selected users with validate flag', () => {
|
|
||||||
|
|
||||||
const change = new SimpleChange(null, mockPreselectedUsers, false);
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
component.mode = 'multiple';
|
component.mode = 'multiple';
|
||||||
component.validate = true;
|
|
||||||
component.preSelectUsers = <any> mockPreselectedUsers;
|
|
||||||
element = fixture.nativeElement;
|
|
||||||
alfrescoApiService = TestBed.get(AlfrescoApiService);
|
|
||||||
fixture.detectChanges();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should show chip list when mode=multiple', (done) => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
const chip = element.querySelector('mat-chip-list');
|
|
||||||
expect(chip).toBeDefined();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should pre-select all preSelectUsers when mode=multiple', (done) => {
|
|
||||||
spyOn(component, 'searchUser').and.returnValue(Promise.resolve(mockPreselectedUsers));
|
|
||||||
component.mode = 'multiple';
|
|
||||||
fixture.detectChanges();
|
|
||||||
component.ngOnChanges({ 'preSelectUsers': change });
|
component.ngOnChanges({ 'preSelectUsers': change });
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
const chipList = fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip');
|
||||||
|
const removeIcon = <HTMLElement> fixture.nativeElement.querySelector('[data-automation-id="adf-people-cloud-chip-remove-icon-first-name-1 last-name-1"]');
|
||||||
|
expect(chipList.length).toBe(2);
|
||||||
|
expect(component.preSelectUsers[0].readonly).toBeTruthy();
|
||||||
|
expect(component.preSelectUsers[1].readonly).toBeTruthy();
|
||||||
|
expect(removeIcon).toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to remove preselected users if readonly property set to false', (done) => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
component.preSelectUsers = [
|
||||||
|
{ id: mockUsers[0].id, username: mockUsers[0].username, readonly: false },
|
||||||
|
{ id: mockUsers[1].id, username: mockUsers[1].username, readonly: false }
|
||||||
|
];
|
||||||
|
const change = new SimpleChange(null, component.preSelectUsers, false);
|
||||||
|
component.mode = 'multiple';
|
||||||
|
component.ngOnChanges({ 'preSelectUsers': change });
|
||||||
|
const removeUserSpy = spyOn(component.removeUser, 'emit');
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
|
const removeIcon = <HTMLElement> fixture.nativeElement.querySelector(`[data-automation-id="adf-people-cloud-chip-remove-icon-${mockPreselectedUsers[0].username}"]`);
|
||||||
expect(chips.length).toBe(2);
|
expect(chips.length).toBe(2);
|
||||||
|
expect(component.preSelectUsers[0].readonly).toBe(false, 'Removable');
|
||||||
|
expect(component.preSelectUsers[1].readonly).toBe(false, 'Removable');
|
||||||
|
removeIcon.click();
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(removeUserSpy).toHaveBeenCalled();
|
||||||
|
expect(fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip').length).toBe(1);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit removeUser when a selected user is removed if mode=multiple', (done) => {
|
describe('Component readonly mode', () => {
|
||||||
spyOn(component.removeUser, 'emit');
|
const change = new SimpleChange(null, mockPreselectedUsers, false);
|
||||||
component.mode = 'multiple';
|
|
||||||
fixture.detectChanges();
|
it('should chip list be disabled and show one single chip - single mode', () => {
|
||||||
fixture.whenStable().then(() => {
|
component.mode = 'single';
|
||||||
|
component.readOnly = true;
|
||||||
|
component.preSelectUsers = <any> mockPreselectedUsers;
|
||||||
|
component.ngOnChanges({ 'preSelectUsers': change });
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const removeIcon = fixture.debugElement.query(By.css('mat-chip mat-icon'));
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
removeIcon.nativeElement.click();
|
const chipList = fixture.nativeElement.querySelector('mat-chip-list');
|
||||||
|
expect(chips).toBeDefined();
|
||||||
|
expect(chipList).toBeDefined();
|
||||||
|
expect(chips.length).toBe(1);
|
||||||
|
expect(chipList.attributes['ng-reflect-disabled'].value).toEqual('true');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should chip list be disabled and show mat chips for all the preselected users - multiple mode', () => {
|
||||||
|
component.mode = 'multiple';
|
||||||
|
component.readOnly = true;
|
||||||
|
component.preSelectUsers = <any> mockPreselectedUsers;
|
||||||
|
component.ngOnChanges({ 'preSelectUsers': change });
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(component.removeUser.emit).toHaveBeenCalled();
|
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||||
done();
|
const chipList = fixture.nativeElement.querySelector('mat-chip-list');
|
||||||
});
|
expect(chips).toBeDefined();
|
||||||
});
|
expect(chipList).toBeDefined();
|
||||||
|
expect(chips.length).toBe(2);
|
||||||
it('should emit warning if are invalid users', (done) => {
|
expect(chipList.attributes['ng-reflect-disabled'].value).toEqual('true');
|
||||||
findUserByUsernameSpy.and.returnValue(Promise.resolve([]));
|
|
||||||
const warnMessage = { message: 'INVALID_PRESELECTED_USERS', users: [{ username: 'invalidUsername' }] };
|
|
||||||
component.validate = true;
|
|
||||||
component.preSelectUsers = <any> [{ username: 'invalidUsername' }];
|
|
||||||
fixture.detectChanges();
|
|
||||||
component.loadSinglePreselectUser();
|
|
||||||
component.warning.subscribe((response) => {
|
|
||||||
expect(response).toEqual(warnMessage);
|
|
||||||
expect(response.message).toEqual(warnMessage.message);
|
|
||||||
expect(response.users).toEqual(warnMessage.users);
|
|
||||||
expect(response.users[0].username).toEqual('invalidUsername');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should filter user by id if validate true', async(() => {
|
|
||||||
const findByIdSpy = spyOn(identityService, 'findUserById').and.returnValue(of(mockUsers[0]));
|
|
||||||
component.mode = 'multiple';
|
|
||||||
component.validate = true;
|
|
||||||
fixture.detectChanges();
|
|
||||||
component.preSelectUsers = <any> [{ id: mockUsers[0].id }, { id: mockUsers[1].id }];
|
|
||||||
component.ngOnChanges({ 'preSelectUsers': change });
|
|
||||||
fixture.detectChanges();
|
|
||||||
component.filterPreselectUsers().then((result: any) => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(findByIdSpy).toHaveBeenCalled();
|
|
||||||
expect(component.userExists(result[0])).toEqual(true);
|
|
||||||
expect(result[1].id).toBe(mockUsers[0].id);
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should filter user by username if validate true', (done) => {
|
|
||||||
findUserByUsernameSpy.and.returnValue(of(mockUsers));
|
|
||||||
component.mode = 'multiple';
|
|
||||||
component.validate = true;
|
|
||||||
component.preSelectUsers = <any> [{ username: mockUsers[1].username }, { username: mockUsers[2].username }];
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
component.filterPreselectUsers().then((result) => {
|
|
||||||
expect(findUserByUsernameSpy).toHaveBeenCalled();
|
|
||||||
expect(component.userExists(result[0])).toEqual(true);
|
|
||||||
expect(component.userExists(result[1])).toEqual(true);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should filter user by email if validate true', (done) => {
|
|
||||||
const findUserByEmailSpy = spyOn(identityService, 'findUserByEmail').and.returnValue(of(mockUsers));
|
|
||||||
fixture.detectChanges();
|
|
||||||
component.mode = 'multiple';
|
|
||||||
component.validate = true;
|
|
||||||
component.preSelectUsers = <any> [{ email: mockUsers[1].email }, { email: mockUsers[2].email }];
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
component.filterPreselectUsers().then((result) => {
|
|
||||||
expect(findUserByEmailSpy).toHaveBeenCalled();
|
|
||||||
expect(component.userExists(result[0])).toEqual(true);
|
|
||||||
expect(component.userExists(result[1])).toEqual(true);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should search user by id on single selection mode', (done) => {
|
|
||||||
const findUserByIdSpy = spyOn(identityService, 'findUserById').and.returnValue(of(mockUsers[0]));
|
|
||||||
component.mode = 'single';
|
|
||||||
component.validate = true;
|
|
||||||
fixture.detectChanges();
|
|
||||||
component.preSelectUsers = <any> [{ id: mockUsers[0].id }];
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
component.validatePreselectUsers().then((result) => {
|
|
||||||
expect(findUserByIdSpy).toHaveBeenCalled();
|
|
||||||
expect(result.length).toEqual(1);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not preselect any user if email is invalid and validation enable', (done) => {
|
|
||||||
const findUserByEmailSpy = spyOn(identityService, 'findUserByEmail').and.returnValue(of([]));
|
|
||||||
component.mode = 'single';
|
|
||||||
component.validate = true;
|
|
||||||
component.preSelectUsers = <any> [{ email: 'invalid email' }];
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
component.validatePreselectUsers().then((result) => {
|
|
||||||
expect(findUserByEmailSpy).toHaveBeenCalled();
|
|
||||||
expect(result.length).toEqual(0);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not preselect any user if id is invalid and validation enable', (done) => {
|
|
||||||
const findUserByIdSpy = spyOn(identityService, 'findUserById').and.returnValue(of([]));
|
|
||||||
component.mode = 'single';
|
|
||||||
component.validate = true;
|
|
||||||
component.preSelectUsers = <any> [{ id: 'invalid id' }];
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
component.validatePreselectUsers().then((result) => {
|
|
||||||
expect(findUserByIdSpy).toHaveBeenCalled();
|
|
||||||
expect(result.length).toEqual(0);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not preselect any user if username is invalid and validation enable', (done) => {
|
|
||||||
findUserByUsernameSpy.and.returnValue(of([]));
|
|
||||||
component.mode = 'single';
|
|
||||||
component.validate = true;
|
|
||||||
component.preSelectUsers = <any> [{ username: 'invalid user' }];
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
component.validatePreselectUsers().then((result) => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(findUserByUsernameSpy).toHaveBeenCalled();
|
|
||||||
expect(result.length).toEqual(0);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should remove duplicated preselcted users when a user is duplicated', () => {
|
|
||||||
spyOn(identityService, 'findUserById').and.returnValue(of(mockUsers[0]));
|
|
||||||
component.mode = 'multiple';
|
|
||||||
component.validate = true;
|
|
||||||
component.preSelectUsers = <any> [{ id: mockUsers[0].id }, { id: mockUsers[0].id }];
|
|
||||||
component.ngOnChanges({ 'preSelectUsers': change });
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
component.validatePreselectUsers().then((result) => {
|
|
||||||
expect(result.length).toEqual(1);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Preselected users and validation enabled', () => {
|
||||||
|
|
||||||
|
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, 'hasUserDetails').and.returnValue(false);
|
||||||
|
|
||||||
|
const expectedWarning = {
|
||||||
|
message: 'INVALID_PRESELECTED_USERS',
|
||||||
|
users: [{
|
||||||
|
id: mockPreselectedUsers[0].id,
|
||||||
|
username: mockPreselectedUsers[0].username
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
component.warning.subscribe(warning => {
|
||||||
|
expect(warning).toEqual(expectedWarning);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
component.mode = 'single';
|
||||||
|
component.validate = true;
|
||||||
|
component.preSelectUsers = <any> [mockPreselectedUsers[0], mockPreselectedUsers[1]];
|
||||||
|
component.ngOnChanges({ 'preSelectUsers': new SimpleChange(null, [mockPreselectedUsers[0], mockPreselectedUsers[1]], false) });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check validation for all the users and emit warning - multiple mode', (done) => {
|
||||||
|
spyOn(identityService, 'findUserById').and.returnValue(Promise.resolve(undefined));
|
||||||
|
|
||||||
|
const expectedWarning = {
|
||||||
|
message: 'INVALID_PRESELECTED_USERS',
|
||||||
|
users: [
|
||||||
|
{
|
||||||
|
id: mockPreselectedUsers[0].id,
|
||||||
|
username: mockPreselectedUsers[0].username
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: mockPreselectedUsers[1].id,
|
||||||
|
username: mockPreselectedUsers[1].username
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
component.warning.subscribe(warning => {
|
||||||
|
expect(warning).toEqual(expectedWarning);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
component.mode = 'multiple';
|
||||||
|
component.validate = true;
|
||||||
|
component.preSelectUsers = <any> [mockPreselectedUsers[0], mockPreselectedUsers[1]];
|
||||||
|
component.ngOnChanges({ 'preSelectUsers': new SimpleChange(null, [mockPreselectedUsers[0], mockPreselectedUsers[1]], false) });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should removeDuplicateUsers return only unique users', () => {
|
||||||
|
const duplicatedUsers = [{ id: mockUsers[0].id }, { id: mockUsers[0].id }];
|
||||||
|
expect(component.removeDuplicatedUsers(duplicatedUsers)).toEqual([{ id: mockUsers[0].id }]);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -16,10 +16,27 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { FormControl } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
import { Component, OnInit, Output, EventEmitter, ViewEncapsulation, Input, ViewChild, ElementRef, SimpleChanges, OnChanges, OnDestroy, ChangeDetectionStrategy } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
Output,
|
||||||
|
EventEmitter,
|
||||||
|
ViewEncapsulation,
|
||||||
|
Input,
|
||||||
|
SimpleChanges,
|
||||||
|
OnChanges,
|
||||||
|
OnDestroy,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ViewChild, ElementRef
|
||||||
|
} from '@angular/core';
|
||||||
import { Observable, of, BehaviorSubject, Subject } from 'rxjs';
|
import { Observable, of, BehaviorSubject, Subject } from 'rxjs';
|
||||||
import { switchMap, debounceTime, distinctUntilChanged, mergeMap, tap, filter, map, takeUntil } from 'rxjs/operators';
|
import { switchMap, debounceTime, distinctUntilChanged, mergeMap, tap, filter, map, takeUntil } from 'rxjs/operators';
|
||||||
import { FullNamePipe, IdentityUserModel, IdentityUserService, LogService } from '@alfresco/adf-core';
|
import {
|
||||||
|
FullNamePipe,
|
||||||
|
IdentityUserModel,
|
||||||
|
IdentityUserService,
|
||||||
|
LogService
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
import { trigger, state, style, transition, animate } from '@angular/animations';
|
import { trigger, state, style, transition, animate } from '@angular/animations';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -79,7 +96,7 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
|
|
||||||
/** FormControl to search the user */
|
/** FormControl to search the user */
|
||||||
@Input()
|
@Input()
|
||||||
searchUserCtrl: FormControl = new FormControl();
|
searchUserCtrl: FormControl = new FormControl({ value: '', disabled: false });
|
||||||
|
|
||||||
/** Placeholder translation key
|
/** Placeholder translation key
|
||||||
*/
|
*/
|
||||||
@ -106,166 +123,63 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
private userInput: ElementRef<HTMLInputElement>;
|
private userInput: ElementRef<HTMLInputElement>;
|
||||||
|
|
||||||
private _searchUsers: IdentityUserModel[] = [];
|
private _searchUsers: IdentityUserModel[] = [];
|
||||||
private selectedUsersSubject: BehaviorSubject<IdentityUserModel[]>;
|
|
||||||
private searchUsersSubject: BehaviorSubject<IdentityUserModel[]>;
|
private searchUsersSubject: BehaviorSubject<IdentityUserModel[]>;
|
||||||
private onDestroy$ = new Subject<boolean>();
|
private onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
selectedUsers: IdentityUserModel[] = [];
|
selectedUsers: IdentityUserModel[] = [];
|
||||||
selectedUsers$: Observable<IdentityUserModel[]>;
|
invalidUsers: IdentityUserModel[] = [];
|
||||||
|
|
||||||
searchUsers$: Observable<IdentityUserModel[]>;
|
searchUsers$: Observable<IdentityUserModel[]>;
|
||||||
_subscriptAnimationState: string = 'enter';
|
_subscriptAnimationState: string = 'enter';
|
||||||
clientId: string;
|
clientId: string;
|
||||||
isFocused: boolean;
|
isFocused: boolean;
|
||||||
invalidUsers: IdentityUserModel[] = [];
|
|
||||||
|
|
||||||
currentTimeout: any;
|
currentTimeout: any;
|
||||||
|
validateUsersMessage: string;
|
||||||
|
searchedValue = '';
|
||||||
|
|
||||||
constructor(private identityUserService: IdentityUserService, private logService: LogService) {
|
isLoading = false;
|
||||||
}
|
|
||||||
|
constructor(
|
||||||
|
private identityUserService: IdentityUserService,
|
||||||
|
private logService: LogService) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.hasPreSelectUsers()) {
|
|
||||||
this.selectedUsers = [...this.preSelectUsers];
|
|
||||||
}
|
|
||||||
this.initSubjects();
|
|
||||||
this.initSearch();
|
|
||||||
|
|
||||||
if (this.appName) {
|
|
||||||
this.disableSearch();
|
|
||||||
this.loadClientId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
|
||||||
this.initSubjects();
|
|
||||||
|
|
||||||
if (this.isPreselectedUserChanged(changes)) {
|
|
||||||
if (this.isValidationEnabled()) {
|
|
||||||
this.loadPreSelectUsers();
|
|
||||||
} else {
|
|
||||||
this.loadNoValidationPreselectUsers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changes.appName && this.isAppNameChanged(changes.appName)) {
|
|
||||||
this.disableSearch();
|
|
||||||
this.loadClientId();
|
|
||||||
} else {
|
|
||||||
this.enableSearch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
clearTimeout(this.currentTimeout);
|
|
||||||
this.onDestroy$.next(true);
|
|
||||||
this.onDestroy$.complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
initSubjects() {
|
|
||||||
if (this.selectedUsersSubject === undefined) {
|
|
||||||
this.selectedUsersSubject = new BehaviorSubject<IdentityUserModel[]>(this.preSelectUsers);
|
|
||||||
this.selectedUsers$ = this.selectedUsersSubject.asObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.searchUsersSubject === undefined) {
|
if (this.searchUsersSubject === undefined) {
|
||||||
this.searchUsersSubject = new BehaviorSubject<IdentityUserModel[]>(this._searchUsers);
|
this.searchUsersSubject = new BehaviorSubject<IdentityUserModel[]>(this._searchUsers);
|
||||||
this.searchUsers$ = this.searchUsersSubject.asObservable();
|
this.searchUsers$ = this.searchUsersSubject.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.loadClientId();
|
||||||
|
this.initSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
private isAppNameChanged(change) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
return change.previousValue !== change.currentValue && this.appName && this.appName.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
isPreselectedUserChanged(changes: SimpleChanges) {
|
if (this.hasPreselectedUsersChanged(changes) || this.hasModeChanged(changes) || this.isValidationChanged(changes)) {
|
||||||
return changes.preSelectUsers
|
if (this.hasPreSelectUsers()) {
|
||||||
&& changes.preSelectUsers.previousValue !== changes.preSelectUsers.currentValue
|
this.loadPreSelectUsers();
|
||||||
&& this.hasPreSelectUsers();
|
} else if (this.hasPreselectedUsersCleared(changes)) {
|
||||||
}
|
this.selectedUsers = [];
|
||||||
|
this.invalidUsers = [];
|
||||||
isValidationEnabled() {
|
|
||||||
return this.validate === true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async validatePreselectUsers(): Promise<any> {
|
|
||||||
let filteredPreselectUsers: IdentityUserModel[];
|
|
||||||
let validUsers: IdentityUserModel[] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
filteredPreselectUsers = await this.filterPreselectUsers();
|
|
||||||
} catch (error) {
|
|
||||||
validUsers = [];
|
|
||||||
this.logService.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.preSelectUsers.map((user: IdentityUserModel) => {
|
|
||||||
const validUser = this.isValidUser(filteredPreselectUsers, user);
|
|
||||||
|
|
||||||
if (validUser) {
|
|
||||||
validUsers.push(validUser);
|
|
||||||
} else {
|
|
||||||
this.invalidUsers.push(user);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
validUsers = this.removeDuplicatedUsers(validUsers);
|
|
||||||
return validUsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
private removeDuplicatedUsers(users: IdentityUserModel[]): IdentityUserModel[] {
|
if (!this.isValidationEnabled()) {
|
||||||
return users.filter((user, index, self) =>
|
this.invalidUsers = [];
|
||||||
index === self.findIndex((auxUser) => {
|
|
||||||
return user.id === auxUser.id && user.username === auxUser.username;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
async filterPreselectUsers() {
|
|
||||||
const promiseBatch = this.preSelectUsers.map(async (user: IdentityUserModel) => {
|
|
||||||
let result: any;
|
|
||||||
try {
|
|
||||||
result = await this.searchUser(user);
|
|
||||||
} catch (error) {
|
|
||||||
result = [];
|
|
||||||
this.logService.error(error);
|
|
||||||
}
|
}
|
||||||
const isUserValid: boolean = this.userExists(result);
|
|
||||||
return isUserValid ? result : null;
|
|
||||||
});
|
|
||||||
return Promise.all(promiseBatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
async searchUser(user: IdentityUserModel) {
|
|
||||||
let key: string = '';
|
|
||||||
|
|
||||||
if (user.id) {
|
|
||||||
key = 'id';
|
|
||||||
} else if (user.email) {
|
|
||||||
key = 'email';
|
|
||||||
} else if (user.username) {
|
|
||||||
key = 'username';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (key) {
|
if (changes.appName && this.isAppNameChanged(changes.appName)) {
|
||||||
case 'id': return this.identityUserService.findUserById(user[key]).toPromise();
|
this.loadClientId();
|
||||||
case 'username': return (await this.identityUserService.findUserByUsername(user[key]).toPromise())[0];
|
this.initSearch();
|
||||||
case 'email': return (await this.identityUserService.findUserByEmail(user[key]).toPromise())[0];
|
|
||||||
default: return of([]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private isValidUser(filteredUsers: IdentityUserModel[], user: IdentityUserModel) {
|
private async loadClientId() {
|
||||||
return filteredUsers.find((filteredUser: IdentityUserModel) => {
|
this.clientId = await this.identityUserService.getClientIdByApplicationName(this.appName).toPromise();
|
||||||
return filteredUser &&
|
if (this.clientId) {
|
||||||
(filteredUser.id === user.id ||
|
this.searchUserCtrl.enable();
|
||||||
filteredUser.username === user.username ||
|
}
|
||||||
filteredUser.email === user.email);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public userExists(result: IdentityUserModel): boolean {
|
|
||||||
return result
|
|
||||||
&& (result.id !== undefined
|
|
||||||
|| result.username !== undefined
|
|
||||||
|| result.email !== undefined);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private initSearch() {
|
private initSearch() {
|
||||||
@ -276,12 +190,9 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
return typeof value === 'string';
|
return typeof value === 'string';
|
||||||
}),
|
}),
|
||||||
tap((value) => {
|
tap((value) => {
|
||||||
|
this.searchedValue = value;
|
||||||
if (value) {
|
if (value) {
|
||||||
this.setError();
|
this.setTypingError();
|
||||||
} else {
|
|
||||||
if (!this.isMultipleMode()) {
|
|
||||||
this.removeUser.emit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
tap(() => {
|
tap(() => {
|
||||||
@ -296,7 +207,6 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
}),
|
}),
|
||||||
mergeMap((user: any) => {
|
mergeMap((user: any) => {
|
||||||
if (this.appName) {
|
if (this.appName) {
|
||||||
|
|
||||||
return this.checkUserHasAccess(user.id).pipe(
|
return this.checkUserHasAccess(user.id).pipe(
|
||||||
mergeMap((hasRole) => {
|
mergeMap((hasRole) => {
|
||||||
return hasRole ? of(user) : of();
|
return hasRole ? of(user) : of();
|
||||||
@ -315,6 +225,20 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
clearTimeout(this.currentTimeout);
|
||||||
|
this.onDestroy$.next(true);
|
||||||
|
this.onDestroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private isAppNameChanged(change): boolean {
|
||||||
|
return change && change.previousValue !== change.currentValue && this.appName && this.appName.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidationEnabled(): boolean {
|
||||||
|
return this.validate === true;
|
||||||
|
}
|
||||||
|
|
||||||
private checkUserHasAccess(userId: string): Observable<boolean> {
|
private checkUserHasAccess(userId: string): Observable<boolean> {
|
||||||
if (this.hasRoles()) {
|
if (this.hasRoles()) {
|
||||||
return this.identityUserService.checkUserHasAnyClientAppRole(userId, this.clientId, this.roles);
|
return this.identityUserService.checkUserHasAnyClientAppRole(userId, this.clientId, this.roles);
|
||||||
@ -345,79 +269,105 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadPreSelectUsers() {
|
private async loadPreSelectUsers() {
|
||||||
if (!this.isMultipleMode()) {
|
this.selectedUsers = [];
|
||||||
this.loadSinglePreselectUser();
|
|
||||||
|
if (this.isSingleMode()) {
|
||||||
|
this.selectedUsers = [this.preSelectUsers[0]];
|
||||||
} else {
|
} else {
|
||||||
this.loadMultiplePreselectUsers();
|
this.selectedUsers = this.removeDuplicatedUsers(this.preSelectUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isValidationEnabled()) {
|
||||||
|
this.isLoading = true;
|
||||||
|
await this.validatePreselectUsers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadNoValidationPreselectUsers() {
|
async validatePreselectUsers(): Promise<any> {
|
||||||
this.selectedUsers = [...this.removeDuplicatedUsers(this.preSelectUsers)];
|
this.invalidUsers = [];
|
||||||
|
const validUsers: IdentityUserModel[] = [];
|
||||||
|
|
||||||
if (this.isMultipleMode()) {
|
let preselectedUsersToValidate: IdentityUserModel[] = [];
|
||||||
this.selectedUsersSubject.next(this.selectedUsers);
|
|
||||||
|
if (this.isSingleMode()) {
|
||||||
|
preselectedUsersToValidate = [this.preSelectUsers[0]];
|
||||||
} else {
|
} else {
|
||||||
|
preselectedUsersToValidate = this.removeDuplicatedUsers(this.preSelectUsers);
|
||||||
if (this.currentTimeout) {
|
|
||||||
clearTimeout(this.currentTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.currentTimeout = setTimeout(() => {
|
|
||||||
this.searchUserCtrl.setValue(this.selectedUsers[0]);
|
|
||||||
this.onSelect(this.selectedUsers[0]);
|
|
||||||
}, 0);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async loadSinglePreselectUser() {
|
await Promise.all(preselectedUsersToValidate.map(async (user: IdentityUserModel) => {
|
||||||
const users = await this.validatePreselectUsers();
|
try {
|
||||||
if (users && users.length > 0) {
|
const validationResult = await this.searchUser(user);
|
||||||
this.checkPreselectValidationErrors();
|
if (!this.hasUserDetails(validationResult)) {
|
||||||
this.searchUserCtrl.setValue(users[0]);
|
this.invalidUsers.push(user);
|
||||||
} else {
|
} else {
|
||||||
this.checkPreselectValidationErrors();
|
validUsers.push(validationResult);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async loadMultiplePreselectUsers() {
|
|
||||||
const users = await this.validatePreselectUsers();
|
|
||||||
if (users && users.length > 0) {
|
|
||||||
this.checkPreselectValidationErrors();
|
|
||||||
this.selectedUsers = [...this.alignPreselectedReadonlyUsersAfterValidation(users)];
|
|
||||||
this.selectedUsersSubject.next(this.selectedUsers);
|
|
||||||
} else {
|
|
||||||
this.checkPreselectValidationErrors();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private alignPreselectedReadonlyUsersAfterValidation(users: IdentityUserModel[]) {
|
|
||||||
this.preSelectUsers.forEach((preSelectedUser, index) => {
|
|
||||||
if (users[index]) {
|
|
||||||
if ((preSelectedUser.id === users[index].id) || (preSelectedUser.username === users[index].username)) {
|
|
||||||
users[index].readonly = preSelectedUser.readonly;
|
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.invalidUsers.push(user);
|
||||||
|
this.logService.error(error);
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
|
this.checkPreselectValidationErrors();
|
||||||
|
this.alignUsersAfterValidation(validUsers);
|
||||||
|
this.isLoading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private alignUsersAfterValidation(validatedUsers: IdentityUserModel[]) {
|
||||||
|
this.selectedUsers.forEach((selectedUser, index) => {
|
||||||
|
validatedUsers.forEach(validatedUser => {
|
||||||
|
if ((selectedUser.id === validatedUser.id) || (selectedUser.username === validatedUser.username)
|
||||||
|
|| (selectedUser.email === validatedUser.email)) {
|
||||||
|
validatedUser.readonly = selectedUser.readonly;
|
||||||
|
this.selectedUsers[index] = validatedUser;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
return users;
|
}
|
||||||
|
|
||||||
|
async searchUser(user: IdentityUserModel) {
|
||||||
|
let key: string = '';
|
||||||
|
|
||||||
|
if (user.id) {
|
||||||
|
key = 'id';
|
||||||
|
} else if (user.email) {
|
||||||
|
key = 'email';
|
||||||
|
} else if (user.username) {
|
||||||
|
key = 'username';
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case 'id':
|
||||||
|
return this.identityUserService.findUserById(user[key]).toPromise();
|
||||||
|
case 'username':
|
||||||
|
return (await this.identityUserService.findUserByUsername(user[key]).toPromise())[0];
|
||||||
|
case 'email':
|
||||||
|
return (await this.identityUserService.findUserByEmail(user[key]).toPromise())[0];
|
||||||
|
default:
|
||||||
|
return of([]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeDuplicatedUsers(users: IdentityUserModel[]): IdentityUserModel[] {
|
||||||
|
return users.filter((user, index, self) =>
|
||||||
|
index === self.findIndex((auxUser) => {
|
||||||
|
return user.id === auxUser.id && user.username === auxUser.username && user.email === auxUser.email;
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkPreselectValidationErrors() {
|
public checkPreselectValidationErrors() {
|
||||||
|
|
||||||
|
this.invalidUsers = this.removeDuplicatedUsers(this.invalidUsers);
|
||||||
|
|
||||||
if (this.invalidUsers.length > 0) {
|
if (this.invalidUsers.length > 0) {
|
||||||
this.warning.emit({
|
this.generateInvalidUsersMessage();
|
||||||
message: 'INVALID_PRESELECTED_USERS',
|
|
||||||
users: this.invalidUsers
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private async loadClientId() {
|
this.warning.emit({
|
||||||
this.clientId = await this.identityUserService.getClientIdByApplicationName(this.appName).toPromise();
|
message: 'INVALID_PRESELECTED_USERS',
|
||||||
|
users: this.invalidUsers
|
||||||
if (this.clientId) {
|
});
|
||||||
this.enableSearch();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelect(user: IdentityUserModel) {
|
onSelect(user: IdentityUserModel) {
|
||||||
@ -425,26 +375,66 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
if (this.isMultipleMode()) {
|
if (this.isMultipleMode()) {
|
||||||
if (!this.isUserAlreadySelected(user)) {
|
if (!this.isUserAlreadySelected(user)) {
|
||||||
this.selectedUsers.push(user);
|
this.selectedUsers.push(user);
|
||||||
this.selectedUsersSubject.next(this.selectedUsers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.userInput.nativeElement.value = '';
|
|
||||||
this.searchUserCtrl.setValue('');
|
|
||||||
} else {
|
} else {
|
||||||
|
this.invalidUsers = [];
|
||||||
this.selectedUsers = [user];
|
this.selectedUsers = [user];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.userInput.nativeElement.value = '';
|
||||||
|
this.searchUserCtrl.setValue('');
|
||||||
|
|
||||||
this.changedUsers.emit(this.selectedUsers);
|
this.changedUsers.emit(this.selectedUsers);
|
||||||
this.clearError();
|
|
||||||
this.resetSearchUsers();
|
this.resetSearchUsers();
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemove(user: IdentityUserModel) {
|
onRemove(userToRemove: IdentityUserModel) {
|
||||||
this.removeUser.emit(user);
|
this.removeUser.emit(userToRemove);
|
||||||
const indexToRemove = this.selectedUsers.findIndex((selectedUser) => { return selectedUser.id === user.id; });
|
const indexToRemove = this.selectedUsers.findIndex((selectedUser: IdentityUserModel) => {
|
||||||
|
return selectedUser.id === userToRemove.id;
|
||||||
|
});
|
||||||
this.selectedUsers.splice(indexToRemove, 1);
|
this.selectedUsers.splice(indexToRemove, 1);
|
||||||
this.selectedUsersSubject.next(this.selectedUsers);
|
|
||||||
this.changedUsers.emit(this.selectedUsers);
|
this.changedUsers.emit(this.selectedUsers);
|
||||||
|
this.searchUserCtrl.markAsDirty();
|
||||||
|
|
||||||
|
if (this.isValidationEnabled()) {
|
||||||
|
this.removeUserFromValidation(userToRemove.username);
|
||||||
|
this.checkPreselectValidationErrors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeUserFromValidation(username: string) {
|
||||||
|
const indexToRemove = this.invalidUsers.findIndex((invalidUser) => {
|
||||||
|
return invalidUser.username === username;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (indexToRemove !== -1) {
|
||||||
|
this.invalidUsers.splice(indexToRemove, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hasUserDetails(user: IdentityUserModel): boolean {
|
||||||
|
return user && (user.id !== undefined || user.username !== undefined || user.email !== undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
generateInvalidUsersMessage() {
|
||||||
|
this.validateUsersMessage = '';
|
||||||
|
|
||||||
|
this.invalidUsers.forEach((invalidUser: IdentityUserModel, index) => {
|
||||||
|
if (index === this.invalidUsers.length - 1) {
|
||||||
|
this.validateUsersMessage += `${invalidUser.username} `;
|
||||||
|
} else {
|
||||||
|
this.validateUsersMessage += `${invalidUser.username}, `;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setTypingError() {
|
||||||
|
this.searchUserCtrl.setErrors({ searchTypingError: true, ...this.searchUserCtrl.errors });
|
||||||
|
}
|
||||||
|
|
||||||
|
hasPreselectError(): boolean {
|
||||||
|
return this.invalidUsers && this.invalidUsers.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDisplayName(user): string {
|
getDisplayName(user): string {
|
||||||
@ -455,21 +445,49 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
return this.mode === PeopleCloudComponent.MODE_MULTIPLE;
|
return this.mode === PeopleCloudComponent.MODE_MULTIPLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isSingleMode(): boolean {
|
||||||
|
return this.mode === PeopleCloudComponent.MODE_SINGLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isSingleSelectionReadonly(): boolean {
|
||||||
|
return this.isSingleMode() && this.selectedUsers.length === 1 && this.selectedUsers[0].readonly === true;
|
||||||
|
}
|
||||||
|
|
||||||
private hasPreSelectUsers(): boolean {
|
private hasPreSelectUsers(): boolean {
|
||||||
return this.preSelectUsers && this.preSelectUsers.length > 0;
|
return this.preSelectUsers && this.preSelectUsers.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private hasModeChanged(changes): boolean {
|
||||||
|
return changes && changes.mode && changes.mode.currentValue !== changes.mode.previousValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isValidationChanged(changes): boolean {
|
||||||
|
return changes && changes.validate && changes.validate.currentValue !== changes.validate.previousValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasPreselectedUsersChanged(changes): boolean {
|
||||||
|
return changes && changes.preSelectUsers && changes.preSelectUsers.currentValue !== changes.preSelectUsers.previousValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasPreselectedUsersCleared(changes): boolean {
|
||||||
|
return changes && changes.preSelectUsers && changes.preSelectUsers.currentValue.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
private resetSearchUsers() {
|
private resetSearchUsers() {
|
||||||
this._searchUsers = [];
|
this._searchUsers = [];
|
||||||
this.searchUsersSubject.next(this._searchUsers);
|
this.searchUsersSubject.next(this._searchUsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setError() {
|
getSelectedUsers(): IdentityUserModel[] {
|
||||||
this.searchUserCtrl.setErrors({ invalid: true });
|
return this.selectedUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private clearError() {
|
isReadonly(): boolean {
|
||||||
this.searchUserCtrl.setErrors(null);
|
return this.readOnly || this.isSingleSelectionReadonly();
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidationLoading(): boolean {
|
||||||
|
return this.isValidationEnabled() && this.isLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
setFocus(isFocused: boolean) {
|
setFocus(isFocused: boolean) {
|
||||||
@ -480,16 +498,15 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
return !!this.searchUserCtrl.errors;
|
return !!this.searchUserCtrl.errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasErrorMessage(): boolean {
|
getValidationPattern(): string {
|
||||||
return !this.isFocused && this.hasError();
|
return this.searchUserCtrl.errors.pattern.requiredPattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
private disableSearch() {
|
getValidationMaxLength(): string {
|
||||||
this.searchUserCtrl.disable();
|
return this.searchUserCtrl.errors.maxlength.requiredLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
private enableSearch() {
|
getValidationMinLength(): string {
|
||||||
this.searchUserCtrl.enable();
|
return this.searchUserCtrl.errors.minlength.requiredLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,11 @@ export class PeopleCloudComponentPage {
|
|||||||
await this.peopleCloudSearch.sendKeys(protractor.Key.BACK_SPACE);
|
await this.peopleCloudSearch.sendKeys(protractor.Key.BACK_SPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async clearAssigneeFromChip(username: string): Promise<void> {
|
||||||
|
const assigneeChipRemoveIcon = element(by.css(`[data-automation-id="adf-people-cloud-chip-remove-icon-${username}"]`));
|
||||||
|
await assigneeChipRemoveIcon.click();
|
||||||
|
}
|
||||||
|
|
||||||
async searchAssigneeAndSelect(name: string): Promise<void> {
|
async searchAssigneeAndSelect(name: string): Promise<void> {
|
||||||
await BrowserActions.clearSendKeys(this.peopleCloudSearch, name);
|
await BrowserActions.clearSendKeys(this.peopleCloudSearch, name);
|
||||||
await this.selectAssigneeFromList(name);
|
await this.selectAssigneeFromList(name);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user