[ADF-4269] ProcessCloud - fix start task with invalid Asignee or Candidat… (#4727)

* [ADF-4269] - prevent starting a task with invalid Asignee or CandidateUser

* [ADF-4269] - refractor people/group cloud

* [ADF-4269] - change docs
This commit is contained in:
Silviu Popa
2019-05-15 17:49:46 +03:00
committed by Maurizio Vitale
parent 4a363c731b
commit b4e3a71bef
7 changed files with 49 additions and 9 deletions

View File

@@ -29,6 +29,7 @@ Searches Groups.
| 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. |
| mode | `string` | | User selection mode (single/multiple). | | mode | `string` | | User selection mode (single/multiple). |
| preSelectGroups | [`GroupModel`](../../../lib/process-services-cloud/src/lib/group/models/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 | [`GroupModel`](../../../lib/process-services-cloud/src/lib/group/models/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. |
| searchGroupsControl | `FormControl` | new FormControl() | FormControl to search the group. |
| roles | `string[]` | \[] | Role names of the groups to be listed. | | roles | `string[]` | \[] | Role names of the groups to be listed. |
| title | `string` | | Title of the field | | title | `string` | | Title of the field |

View File

@@ -29,6 +29,7 @@ Allows one or more users to be selected (with auto-suggestion) based on the inpu
| preSelectUsers | [`IdentityUserModel`](../../../lib/core/userinfo/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/userinfo/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. |
| title | `string` | | Placeholder translation key | | title | `string` | | Placeholder translation key |
| searchUserCtrl | `FormControl` | new FormControl() | FormControl to search the users. |
| validate | `Boolean` | false | This flag enables the validation on the preSelectUsers passed as input. In case the flag is true the components call the [identity service](../../../lib/testing/src/lib/core/actions/identity/identity.service.ts) to verify the validity of the information passed as input. Otherwise, no check will be done. | | validate | `Boolean` | false | This flag enables the validation on the preSelectUsers passed as input. In case the flag is true the components call the [identity service](../../../lib/testing/src/lib/core/actions/identity/identity.service.ts) to verify the validity of the information passed as input. Otherwise, no check will be done. |
### Events ### Events

View File

@@ -71,6 +71,10 @@ export class GroupCloudComponent implements OnInit, OnChanges {
@Input() @Input()
preSelectGroups: GroupModel[] = []; preSelectGroups: GroupModel[] = [];
/** FormControl to search the group */
@Input()
searchGroupsControl: FormControl = new FormControl();
/** Role names of the groups to be listed. */ /** Role names of the groups to be listed. */
@Input() @Input()
roles: string[] = []; roles: string[] = [];
@@ -98,8 +102,6 @@ export class GroupCloudComponent implements OnInit, OnChanges {
selectedGroups$: Observable<GroupModel[]>; selectedGroups$: Observable<GroupModel[]>;
searchGroupsControl: FormControl = new FormControl('');
_subscriptAnimationState = 'enter'; _subscriptAnimationState = 'enter';
clientId: string; clientId: string;
@@ -154,8 +156,6 @@ export class GroupCloudComponent implements OnInit, OnChanges {
this.searchedValue = value; this.searchedValue = value;
if (value) { if (value) {
this.setError(); this.setError();
} else {
this.clearError();
} }
}), }),
debounceTime(500), debounceTime(500),
@@ -300,7 +300,7 @@ export class GroupCloudComponent implements OnInit, OnChanges {
} }
hasError(): boolean { hasError(): boolean {
return this.searchGroupsControl && this.searchGroupsControl.errors && this.searchGroupsControl.errors.invalid; return this.searchGroupsControl && this.searchGroupsControl.errors && (this.searchGroupsControl.errors.invalid || this.searchGroupsControl.errors.required);
} }
setFocus(isFocused: boolean) { setFocus(isFocused: boolean) {

View File

@@ -71,6 +71,10 @@ export class PeopleCloudComponent implements OnInit, OnChanges {
@Input() @Input()
preSelectUsers: IdentityUserModel[]; preSelectUsers: IdentityUserModel[];
/** FormControl to search the user */
@Input()
searchUserCtrl: FormControl = new FormControl();
/** Placeholder translation key /** Placeholder translation key
*/ */
@Input() @Input()
@@ -97,8 +101,6 @@ export class PeopleCloudComponent implements OnInit, OnChanges {
selectedUsers$: Observable<IdentityUserModel[]>; selectedUsers$: Observable<IdentityUserModel[]>;
searchUsers$: Observable<IdentityUserModel[]>; searchUsers$: Observable<IdentityUserModel[]>;
searchUserCtrl: FormControl = new FormControl();
_subscriptAnimationState: string = 'enter'; _subscriptAnimationState: string = 'enter';
clientId: string; clientId: string;
@@ -241,7 +243,6 @@ export class PeopleCloudComponent implements OnInit, OnChanges {
if (!this.isMultipleMode()) { if (!this.isMultipleMode()) {
this.removeUser.emit(); this.removeUser.emit();
} }
this.clearError();
} }
}), }),
debounceTime(500), debounceTime(500),

View File

@@ -64,6 +64,7 @@
<adf-cloud-people fxFlex #peopleInput *ngIf="currentUser" <adf-cloud-people fxFlex #peopleInput *ngIf="currentUser"
[appName]="appName" [appName]="appName"
[preSelectUsers]="[currentUser]" [preSelectUsers]="[currentUser]"
[searchUserCtrl]="assigneeFormControl"
(selectUser)="onAssigneeSelect($event)" (selectUser)="onAssigneeSelect($event)"
[title]="'ADF_TASK_LIST.START_TASK.FORM.LABEL.ASSIGNEE'" [title]="'ADF_TASK_LIST.START_TASK.FORM.LABEL.ASSIGNEE'"
(removeUser)="onAssigneeRemove()"></adf-cloud-people> (removeUser)="onAssigneeRemove()"></adf-cloud-people>
@@ -74,6 +75,7 @@
[mode]="'multiple'" [mode]="'multiple'"
[title]="'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.CANDIDATE_GROUP'" [title]="'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.CANDIDATE_GROUP'"
[appName]="appName" [appName]="appName"
[searchGroupsControl]="candidateUserFormControl"
(selectGroup)="onCandidateGroupSelect($event)" (selectGroup)="onCandidateGroupSelect($event)"
(removeGroup)="onCandidateGroupRemove($event)"> (removeGroup)="onCandidateGroupRemove($event)">
</adf-cloud-group> </adf-cloud-group>
@@ -96,7 +98,7 @@
<button <button
color="primary" color="primary"
type="submit" type="submit"
[disabled]="dateError || !taskForm.valid || submitted || assignee.hasError() || candidateGroups.hasError()" [disabled]="!canStartTask()"
mat-button mat-button
id="button-start"> id="button-start">
{{'ADF_CLOUD_TASK_LIST.START_TASK.FORM.ACTION.START'|translate}} {{'ADF_CLOUD_TASK_LIST.START_TASK.FORM.ACTION.START'|translate}}

View File

@@ -153,6 +153,18 @@ describe('StartTaskCloudComponent', () => {
expect(createNewTaskSpy).toHaveBeenCalledWith(taskRequest); expect(createNewTaskSpy).toHaveBeenCalledWith(taskRequest);
}); });
})); }));
it('should cannot start a task if assigne or candidate group is invalid', async(() => {
component.taskForm.controls['name'].setValue('fakeName');
fixture.detectChanges();
fixture.whenStable().then( () => {
const createTaskButton = <HTMLElement> element.querySelector('#button-start');
component.assignee.searchUserCtrl.setValue('');
component.candidateGroups.searchGroupsControl.setValue('');
fixture.detectChanges();
expect(createTaskButton.hasAttribute('disabled')).toEqual(true);
});
}));
}); });
it('should select logged in user as assignee by default', () => { it('should select logged in user as assignee by default', () => {

View File

@@ -99,6 +99,9 @@ export class StartTaskCloudComponent implements OnInit, OnDestroy {
formKey: string; formKey: string;
private assigneeForm: AbstractControl = new FormControl('', [Validators.required]);
private groupForm: AbstractControl = new FormControl('');
private localeSub: Subscription; private localeSub: Subscription;
private createTaskSub: Subscription; private createTaskSub: Subscription;
@@ -190,9 +193,13 @@ export class StartTaskCloudComponent implements OnInit, OnDestroy {
onAssigneeSelect(assignee: IdentityUserModel) { onAssigneeSelect(assignee: IdentityUserModel) {
this.assigneeName = assignee ? assignee.username : ''; this.assigneeName = assignee ? assignee.username : '';
this.groupForm.clearValidators();
this.groupForm.updateValueAndValidity();
} }
onAssigneeRemove() { onAssigneeRemove() {
this.groupForm.setValidators(Validators.required);
this.groupForm.updateValueAndValidity();
this.assigneeName = ''; this.assigneeName = '';
} }
@@ -210,6 +217,14 @@ export class StartTaskCloudComponent implements OnInit, OnDestroy {
} }
} }
canStartTask(): boolean {
return !(this.dateError ||
!this.taskForm.valid ||
this.submitted ||
this.assignee.hasError() ||
this.candidateGroups.hasError());
}
public whitespaceValidator(control: FormControl) { public whitespaceValidator(control: FormControl) {
const isWhitespace = (control.value || '').trim().length === 0; const isWhitespace = (control.value || '').trim().length === 0;
const isValid = control.value.length === 0 || !isWhitespace; const isValid = control.value.length === 0 || !isWhitespace;
@@ -224,6 +239,14 @@ export class StartTaskCloudComponent implements OnInit, OnDestroy {
return this.taskForm.get('priority'); return this.taskForm.get('priority');
} }
get assigneeFormControl(): AbstractControl {
return this.assigneeForm;
}
get candidateUserFormControl(): AbstractControl {
return this.groupForm;
}
onFormSelect(formKey: string) { onFormSelect(formKey: string) {
this.formKey = formKey || ''; this.formKey = formKey || '';
} }