-
-
-
-
+
+
+
+
-
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/people-search.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/people-search.component.spec.ts
index f1b825c9d6..1c23fd5d5e 100644
--- a/ng2-components/ng2-activiti-tasklist/src/components/people-search.component.spec.ts
+++ b/ng2-components/ng2-activiti-tasklist/src/components/people-search.component.spec.ts
@@ -16,6 +16,7 @@
*/
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { MdButtonModule, MdInputModule } from '@angular/material';
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
import { DataTableModule } from 'ng2-alfresco-datatable';
import { Observable } from 'rxjs/Observable';
@@ -52,7 +53,9 @@ describe('PeopleSearchComponent', () => {
TestBed.configureTestingModule({
imports: [
CoreModule.forRoot(),
- DataTableModule
+ DataTableModule,
+ MdButtonModule,
+ MdInputModule
],
declarations: [
PeopleSearchComponent,
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/people-search.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/people-search.component.ts
index 01eb4a003c..a8c9819c61 100644
--- a/ng2-components/ng2-activiti-tasklist/src/components/people-search.component.ts
+++ b/ng2-components/ng2-activiti-tasklist/src/components/people-search.component.ts
@@ -15,21 +15,19 @@
* limitations under the License.
*/
-import { AfterViewInit, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormControl } from '@angular/forms';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Observable';
import { User } from '../models/user.model';
-declare let componentHandler: any;
-
@Component({
selector: 'adf-people-search, activiti-people-search',
templateUrl: './people-search.component.html',
styleUrls: ['./people-search.component.css']
})
-export class PeopleSearchComponent implements OnInit, AfterViewInit {
+export class PeopleSearchComponent implements OnInit {
@Input()
results: Observable
;
@@ -72,20 +70,6 @@ export class PeopleSearchComponent implements OnInit, AfterViewInit {
});
}
- ngAfterViewInit() {
- this.setupMaterialComponents(componentHandler);
- }
-
- setupMaterialComponents(handler?: any): boolean {
- // workaround for MDL issues with dynamic components
- let isUpgraded: boolean = false;
- if (handler) {
- handler.upgradeAllRegistered();
- isUpgraded = true;
- }
- return isUpgraded;
- }
-
onRowClick(user: User) {
this.selectedUser = user;
}
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/people.component.html b/ng2-components/ng2-activiti-tasklist/src/components/people.component.html
index d161ab5d62..e5a6c1fef8 100644
--- a/ng2-components/ng2-activiti-tasklist/src/components/people.component.html
+++ b/ng2-components/ng2-activiti-tasklist/src/components/people.component.html
@@ -16,6 +16,8 @@
(success)="involveUser($event)"
(closeSearch)="onCloseSearch()"
[results]="peopleSearch$">
+ {{ 'TASK_DETAILS.LABELS.ADD_PEOPLE' | translate }}
+ {{ 'PEOPLE.ADD_USER' | translate }}
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/people.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/people.component.spec.ts
index f4947b79fb..e5bc3fbd45 100644
--- a/ng2-components/ng2-activiti-tasklist/src/components/people.component.spec.ts
+++ b/ng2-components/ng2-activiti-tasklist/src/components/people.component.spec.ts
@@ -15,7 +15,9 @@
* limitations under the License.
*/
+import { NO_ERRORS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { MdButtonModule, MdInputModule } from '@angular/material';
import { AlfrescoTranslationService, CoreModule, LogService } from 'ng2-alfresco-core';
import { DataTableModule } from 'ng2-alfresco-datatable';
import { Observable } from 'rxjs/Observable';
@@ -54,7 +56,9 @@ describe('PeopleComponent', () => {
TestBed.configureTestingModule({
imports: [
CoreModule.forRoot(),
- DataTableModule
+ DataTableModule,
+ MdButtonModule,
+ MdInputModule
],
declarations: [
PeopleSearchComponent,
@@ -63,7 +67,8 @@ describe('PeopleComponent', () => {
],
providers: [
PeopleService
- ]
+ ],
+ schemas: [ NO_ERRORS_SCHEMA ]
}).compileComponents().then(() => {
logService = TestBed.get(LogService);
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.css b/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.css
index 13d49df36d..6257ead8e5 100644
--- a/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.css
+++ b/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.css
@@ -27,4 +27,14 @@
adf-people >>> .assignment-top-container{
background-color: #fff;
-}
\ No newline at end of file
+}
+
+.assignment-container {
+ background: #fff;
+ border: 1px solid #e1e1e1;
+ padding: 10px 20px;
+}
+
+adf-task-header.assign-edit-view >>> adf-card-view >>> .adf-property[data-automation-id="header-assignee"] {
+ display: none;
+}
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.html b/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.html
index e373501842..67529819da 100644
--- a/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.html
+++ b/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.html
@@ -13,7 +13,18 @@
expand_less
{{taskDetails.name || 'No name'}}
+
+
+ {{ 'TASK_DETAILS.LABELS.ADD_ASSIGNEE' | translate }}
+ {{ 'PEOPLE.ADD_ASSIGNEE' | translate }}
+
+
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.spec.ts
index a4265e5542..1cefd8c156 100644
--- a/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.spec.ts
+++ b/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.spec.ts
@@ -17,18 +17,30 @@
import { NO_ERRORS_SCHEMA, SimpleChange } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { MdButtonModule, MdInputModule } from '@angular/material';
import { By } from '@angular/platform-browser';
import { Observable } from 'rxjs/Rx';
import { ActivitiFormModule, FormModel, FormOutcomeEvent, FormOutcomeModel, FormService } from 'ng2-activiti-form';
-import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
+import { AlfrescoTranslationService, CoreModule, LogService } from 'ng2-alfresco-core';
import { TaskDetailsModel } from '../models/task-details.model';
+import { User } from '../models/user.model';
import { noDataMock, taskDetailsMock, taskFormMock, tasksMock } from './../assets/task-details.mock';
import { PeopleService } from './../services/people.service';
import { TaskListService } from './../services/tasklist.service';
+import { PeopleSearchComponent } from './people-search.component';
import { TaskDetailsComponent } from './task-details.component';
+declare let jasmine: any;
+
+const fakeUser: User = new User({
+ id: 'fake-id',
+ firstName: 'fake-name',
+ lastName: 'fake-last',
+ email: 'fake@mail.com'
+});
+
describe('TaskDetailsComponent', () => {
let componentHandler: any;
@@ -39,17 +51,22 @@ describe('TaskDetailsComponent', () => {
let getTaskDetailsSpy: jasmine.Spy;
let getFormSpy: jasmine.Spy;
let getTasksSpy: jasmine.Spy;
+ let assignTaskSpy: jasmine.Spy;
let getFormTaskSpy: jasmine.Spy;
let completeTaskSpy: jasmine.Spy;
+ let logService: LogService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule.forRoot(),
- ActivitiFormModule.forRoot()
+ ActivitiFormModule.forRoot(),
+ MdButtonModule,
+ MdInputModule
],
declarations: [
- TaskDetailsComponent
+ TaskDetailsComponent,
+ PeopleSearchComponent
],
providers: [
TaskListService,
@@ -58,6 +75,7 @@ describe('TaskDetailsComponent', () => {
schemas: [ NO_ERRORS_SCHEMA ]
}).compileComponents();
+ logService = TestBed.get(LogService);
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService.translate, 'get').and.callFake((key) => { return Observable.of(key); });
@@ -76,6 +94,7 @@ describe('TaskDetailsComponent', () => {
getFormTaskSpy = spyOn(formService, 'getTask').and.returnValue(Observable.of(taskDetailsMock));
getTasksSpy = spyOn(service, 'getTasks').and.returnValue(Observable.of(tasksMock));
+ assignTaskSpy = spyOn(service, 'assignTask').and.returnValue(Observable.of(fakeUser));
completeTaskSpy = spyOn(service, 'completeTask').and.returnValue(Observable.of({}));
spyOn(service, 'getComments').and.returnValue(Observable.of(noDataMock));
spyOn(service, 'getTaskChecklist').and.returnValue(Observable.of(noDataMock));
@@ -260,4 +279,77 @@ describe('TaskDetailsComponent', () => {
});
+ describe('assign task to user', () => {
+
+ beforeEach(() => {
+ component.taskId = '123';
+ fixture.detectChanges();
+ });
+
+ beforeEach(() => {
+ jasmine.Ajax.install();
+ });
+
+ afterEach(() => {
+ jasmine.Ajax.uninstall();
+ });
+
+ it('should return an observable with user search results', (done) => {
+ component.peopleSearch$.subscribe((users) => {
+ expect(users.length).toBe(2);
+ expect(users[0].firstName).toBe('fake-test-1');
+ expect(users[0].lastName).toBe('fake-last-1');
+ expect(users[0].email).toBe('fake-test-1@test.com');
+ expect(users[0].id).toBe(1);
+ done();
+ });
+ component.searchUser('fake-search-word');
+ jasmine.Ajax.requests.mostRecent().respondWith({
+ status: 200,
+ contentType: 'json',
+ responseText: {
+ data: [{
+ id: 1,
+ firstName: 'fake-test-1',
+ lastName: 'fake-last-1',
+ email: 'fake-test-1@test.com'
+ }, {
+ id: 2,
+ firstName: 'fake-test-2',
+ lastName: 'fake-last-2',
+ email: 'fake-test-2@test.com'
+ }]
+ }
+ });
+ });
+
+ it('should return an empty list for not valid search', (done) => {
+ component.peopleSearch$.subscribe((users) => {
+ expect(users.length).toBe(0);
+ done();
+ });
+ component.searchUser('fake-search-word');
+ jasmine.Ajax.requests.mostRecent().respondWith({
+ status: 200,
+ contentType: 'json',
+ responseText: {}
+ });
+ });
+
+ it('should log error message when search fails', async(() => {
+ component.peopleSearch$.subscribe(() => {
+ expect(logService.error).toHaveBeenCalledWith('Could not load users');
+ });
+ component.searchUser('fake-search');
+ jasmine.Ajax.requests.mostRecent().respondWith({
+ status: 403
+ });
+ }));
+
+ it('should assign task to user', () => {
+ component.assignTaskToUser(fakeUser);
+ expect(assignTaskSpy).toHaveBeenCalled();
+ });
+ });
+
});
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.ts
index 7919465b34..3d2c73bcd6 100644
--- a/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.ts
+++ b/ng2-components/ng2-activiti-tasklist/src/components/task-details.component.ts
@@ -27,10 +27,12 @@ import { Component,
ViewChild
} from '@angular/core';
import { ContentLinkModel, FormFieldValidator, FormModel, FormOutcomeEvent } from 'ng2-activiti-form';
-import { AlfrescoAuthenticationService, AlfrescoTranslationService, CardViewUpdateService, ClickNotification, UpdateNotification } from 'ng2-alfresco-core';
+import { AlfrescoAuthenticationService, AlfrescoTranslationService, CardViewUpdateService, ClickNotification, LogService, UpdateNotification } from 'ng2-alfresco-core';
+import { Observable, Observer } from 'rxjs/Rx';
import { TaskQueryRequestRepresentationModel } from '../models/filter.model';
import { TaskDetailsModel } from '../models/task-details.model';
import { User } from '../models/user.model';
+import { PeopleService } from './../services/people.service';
import { TaskListService } from './../services/tasklist.service';
declare var require: any;
@@ -123,6 +125,9 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
@Output()
executeOutcome: EventEmitter = new EventEmitter();
+ @Output()
+ assignTask: EventEmitter = new EventEmitter();
+
taskDetails: TaskDetailsModel;
taskFormName: string = null;
@@ -130,13 +135,22 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
noTaskDetailsTemplateComponent: TemplateRef;
+ showAssignee: boolean = false;
+
+ private peopleSearchObserver: Observer;
+ peopleSearch$: Observable;
+
constructor(translateService: AlfrescoTranslationService,
private activitiTaskList: TaskListService,
private authService: AlfrescoAuthenticationService,
+ private peopleService: PeopleService,
+ private logService: LogService,
private cardViewUpdateService: CardViewUpdateService) {
if (translateService) {
translateService.addTranslationFolder('ng2-activiti-tasklist', 'assets/ng2-activiti-tasklist');
}
+
+ this.peopleSearch$ = new Observable(observer => this.peopleSearchObserver = observer).share();
}
ngOnInit() {
@@ -150,6 +164,7 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
ngOnChanges(changes: SimpleChanges): void {
let taskId = changes.taskId;
+ this.showAssignee = false;
if (taskId && !taskId.currentValue) {
this.reset();
@@ -193,6 +208,9 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
private clickTaskDetails(clickNotification: ClickNotification) {
console.log(clickNotification.target);
+ if (clickNotification.target.key === 'assignee') {
+ this.showAssignee = true;
+ }
}
/**
@@ -320,4 +338,34 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
isCompletedTask(): boolean {
return this.taskDetails && this.taskDetails.endDate ? true : undefined;
}
+
+ searchUser(searchedWord: string) {
+ this.peopleService.getWorkflowUsers(null, searchedWord)
+ .subscribe((users) => {
+ users = users.filter((user) => user.id !== this.taskDetails.assignee.id);
+ this.peopleSearchObserver.next(users);
+ }, error => this.logService.error('Could not load users'));
+ }
+
+ onCloseSearch() {
+ this.showAssignee = false;
+ console.log(this.taskDetails.assignee);
+ }
+
+ assignTaskToUser(selectedUser: User) {
+ this.activitiTaskList.assignTask(this.taskDetails.id, selectedUser).subscribe(
+ (res: any) => {
+ this.logService.info('Task Assigned to ' + selectedUser.email);
+ this.assignTask.emit();
+ });
+ this.showAssignee = false;
+ }
+
+ getTaskHeaderViewClass() {
+ if (this.showAssignee) {
+ return 'assign-edit-view';
+ } else {
+ return 'default-view';
+ }
+ }
}
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/task-header.component.css b/ng2-components/ng2-activiti-tasklist/src/components/task-header.component.css
new file mode 100644
index 0000000000..6063900889
--- /dev/null
+++ b/ng2-components/ng2-activiti-tasklist/src/components/task-header.component.css
@@ -0,0 +1,3 @@
+adf-card-view >>> .adf-textitem-clickable-value {
+ color: #ff9100;
+}
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/task-header.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/task-header.component.ts
index 006a3bbf9b..e49df09182 100644
--- a/ng2-components/ng2-activiti-tasklist/src/components/task-header.component.ts
+++ b/ng2-components/ng2-activiti-tasklist/src/components/task-header.component.ts
@@ -23,7 +23,7 @@ import { TaskListService } from './../services/tasklist.service';
@Component({
selector: 'adf-task-header, activiti-task-header',
templateUrl: './task-header.component.html',
- styleUrls: ['./task-header.component.scss']
+ styleUrls: ['./task-header.component.scss', './task-header.component.css']
})
export class TaskHeaderComponent implements OnChanges {
@@ -55,7 +55,7 @@ export class TaskHeaderComponent implements OnChanges {
if (this.taskDetails) {
let valueMap = new Map([[this.taskDetails.processInstanceId, this.taskDetails.processDefinitionName]]);
this.properties = [
- new CardViewTextItemModel({ label: 'Assignee', value: this.taskDetails.getFullName(), key: 'assignee', default: 'No assignee' } ),
+ new CardViewTextItemModel({ label: 'Assignee', value: this.taskDetails.getFullName(), key: 'assignee', default: 'No assignee', clickable: !this.isCompleted() } ),
new CardViewTextItemModel({ label: 'Status', value: this.getTaskStatus(), key: 'status' }),
new CardViewDateItemModel({ label: 'Due Date', value: this.taskDetails.dueDate, key: 'dueDate', default: 'No date', editable: true }),
new CardViewTextItemModel({ label: 'Category', value: this.taskDetails.category, key: 'category', default: 'No category' }),
diff --git a/ng2-components/ng2-activiti-tasklist/src/i18n/en.json b/ng2-components/ng2-activiti-tasklist/src/i18n/en.json
index b0fb9049f6..37e7aea674 100644
--- a/ng2-components/ng2-activiti-tasklist/src/i18n/en.json
+++ b/ng2-components/ng2-activiti-tasklist/src/i18n/en.json
@@ -16,7 +16,8 @@
"COMMENTS": "Comments",
"CHECKLIST": "Checklist",
"INVOLVED_PEOPLE": "Involved people",
- "ADD_PEOPLE": "Add people & groups"
+ "ADD_PEOPLE": "Add people & groups",
+ "ADD_ASSIGNEE": "Add new assignee"
},
"BUTTON": {
"COMPLETE": "Complete",
@@ -91,6 +92,8 @@
"PEOPLE": {
"DIALOG_CLOSE": "CLOSE",
"ADD_USER": "ADD",
+ "ADD_ASSIGNEE": "ASSIGN",
+ "SEARCH_USER": "Search user",
"SEARCH": {
"NO_USERS": "No user found to involve"
}