mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-26 17:24:56 +00:00
[ADF-1088] Task Header in TaskDetails component shows Assignee but is not editable (#2176)
* added translate keyword for assignee header * changed people-search component to change the header according to filter type * changed tash-header component to make assignee clickable * imlemented people-search component to assign the task to new user * added handler for assign task to new user * added testcase for assign task to user * changed mdl textbox to angular material * changed button to md and fixed issues in testcase after changed md * changed property for people-search component * added ng-content selector to pass header text and action button text and removed property from people-search component * added no_error_schema to fix testcase issue in people component * fixed no-task-details component test case bug * added people-search component in read me
This commit is contained in:
parent
ecc6aecd80
commit
5ad4fe171a
@ -72,6 +72,7 @@
|
|||||||
(formCompleted)="onFormCompleted($event)"
|
(formCompleted)="onFormCompleted($event)"
|
||||||
(formContentClicked)="onFormContentClick($event)"
|
(formContentClicked)="onFormContentClick($event)"
|
||||||
(taskCreated)="onTaskCreated($event)"
|
(taskCreated)="onTaskCreated($event)"
|
||||||
|
(assignTask)="onAssignTask()"
|
||||||
(taskDeleted)="onTaskDeleted($event)">
|
(taskDeleted)="onTaskDeleted($event)">
|
||||||
</activiti-task-details>
|
</activiti-task-details>
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -382,4 +382,9 @@ export class ActivitiDemoComponent implements AfterViewInit, OnDestroy, OnInit {
|
|||||||
isTaskCompleted(): boolean {
|
isTaskCompleted(): boolean {
|
||||||
return this.activitidetails.isCompletedTask();
|
return this.activitidetails.isCompletedTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAssignTask() {
|
||||||
|
this.taskList.reload();
|
||||||
|
this.currentTaskId = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,9 @@
|
|||||||
- [Task Audit Directive](#task-audit-directive)
|
- [Task Audit Directive](#task-audit-directive)
|
||||||
* [Properties](#properties-11)
|
* [Properties](#properties-11)
|
||||||
+ [Events](#events-10)
|
+ [Events](#events-10)
|
||||||
|
- [People Search Component](#people-search-component)
|
||||||
|
* [Properties](#properties-12)
|
||||||
|
* [Events](#events-12)
|
||||||
- [Build from sources](#build-from-sources)
|
- [Build from sources](#build-from-sources)
|
||||||
- [NPM scripts](#npm-scripts)
|
- [NPM scripts](#npm-scripts)
|
||||||
- [Demo](#demo)
|
- [Demo](#demo)
|
||||||
@ -555,6 +558,42 @@ This directive provide a way to fetch the Task Audit information in the pdf or j
|
|||||||
| clicked | Raised when the task audit info is ready |
|
| clicked | Raised when the task audit info is ready |
|
||||||
| error | Raised if there is an error during fetching task information |
|
| error | Raised if there is an error during fetching task information |
|
||||||
|
|
||||||
|
## People Search
|
||||||
|
|
||||||
|
The component used to search users/people.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<adf-people-search></adf-people-search>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| results | Observable<User[]> | The params to show people list |
|
||||||
|
|
||||||
|
### Events
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| searchPeople | Raised when the search people with new keyword |
|
||||||
|
| success | Raised when select the user and click action button |
|
||||||
|
| closeSearch | Raised when click the clse button |
|
||||||
|
|
||||||
|
### How to use
|
||||||
|
|
||||||
|
```html
|
||||||
|
<adf-people-search
|
||||||
|
(searchPeople)="searchUser($event)"
|
||||||
|
(success)="involveUser($event)"
|
||||||
|
(closeSearch)="onCloseSearch()"
|
||||||
|
[results]="peopleSearch$">
|
||||||
|
<header-title>{{ 'TASK_DETAILS.LABELS.ADD_PEOPLE' | translate }}</header-title>
|
||||||
|
<action-button-label>{{ 'PEOPLE.ADD_USER' | translate }}</action-button-label>
|
||||||
|
</adf-people-search>
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## Build from sources
|
## Build from sources
|
||||||
|
|
||||||
You can build component from sources with the following commands:
|
You can build component from sources with the following commands:
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
import { ModuleWithProviders, NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { MdAutocompleteModule, MdButtonModule, MdCardModule, MdDatepickerModule, MdGridListModule,
|
import { MdAutocompleteModule, MdButtonModule, MdCardModule, MdDatepickerModule, MdGridListModule,
|
||||||
MdIconModule, MdInputModule, MdNativeDateModule, MdProgressSpinnerModule, MdSelectModule } from '@angular/material';
|
MdIconModule, MdInputModule, MdNativeDateModule, MdProgressSpinnerModule, MdSelectModule } from '@angular/material';
|
||||||
import { ActivitiFormModule } from 'ng2-activiti-form';
|
import { ActivitiFormModule } from 'ng2-activiti-form';
|
||||||
@ -176,7 +176,8 @@ export const ACTIVITI_TASKLIST_PROVIDERS: any[] = [
|
|||||||
...ACTIVITI_TASKLIST_DIRECTIVES,
|
...ACTIVITI_TASKLIST_DIRECTIVES,
|
||||||
MdIconModule,
|
MdIconModule,
|
||||||
MdButtonModule
|
MdButtonModule
|
||||||
]
|
],
|
||||||
|
schemas: [ NO_ERRORS_SCHEMA ]
|
||||||
})
|
})
|
||||||
export class ActivitiTaskListModule {
|
export class ActivitiTaskListModule {
|
||||||
static forRoot(): ModuleWithProviders {
|
static forRoot(): ModuleWithProviders {
|
||||||
|
@ -24,7 +24,7 @@ describe('NoTaskDetailsTemplateDirective', () => {
|
|||||||
let detailsComponent: TaskDetailsComponent;
|
let detailsComponent: TaskDetailsComponent;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
detailsComponent = new TaskDetailsComponent(null, null, null, null);
|
detailsComponent = new TaskDetailsComponent(null, null, null, null, null, null);
|
||||||
component = new NoTaskDetailsTemplateDirective(detailsComponent);
|
component = new NoTaskDetailsTemplateDirective(detailsComponent);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -41,12 +41,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.search-list-container{
|
.search-list-container{
|
||||||
max-height: 152px;
|
max-height: 188px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
adf-people-list >>> alfresco-datatable >>> thead {
|
adf-people-list >>> adf-datatable >>> thead {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,11 +66,11 @@ adf-people-list >>> alfresco-datatable >>> thead {
|
|||||||
color: rgb(255, 152, 0);
|
color: rgb(255, 152, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
adf-people-list >>> alfresco-datatable >>> .people-full-name {
|
adf-people-list >>> adf-datatable >>> .people-full-name {
|
||||||
font-family: 'Muli';
|
font-family: 'Muli';
|
||||||
}
|
}
|
||||||
|
|
||||||
adf-people-list >>> alfresco-datatable >>> .people-pic {
|
adf-people-list >>> adf-datatable >>> .people-pic {
|
||||||
background: #ffc800;
|
background: #ffc800;
|
||||||
padding: 10px 6px;
|
padding: 10px 6px;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
@ -83,10 +83,18 @@ adf-people-list >>> alfresco-datatable >>> .people-pic {
|
|||||||
min-width: 30px;
|
min-width: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
adf-people-list >>> alfresco-datatable >>> td.mdl-data-table__cell--non-numeric.non-selectable.data-cell{
|
adf-people-list >>> adf-datatable >>> td.mdl-data-table__cell--non-numeric.non-selectable.data-cell{
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mdl-textfield {
|
.mdl-textfield {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adf-people-list >>> adf-datatable >>> .adf-data-table td:first-of-type {
|
||||||
|
padding: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-text-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
<div class="search-text-header">{{ 'TASK_DETAILS.LABELS.ADD_PEOPLE' | translate }}</div>
|
<div class="search-text-header">
|
||||||
<div class="search-text-container">
|
<ng-content select="header-title"></ng-content>
|
||||||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
|
||||||
<input class="mdl-textfield__input" type="text" id="userSearchText" [value]="" [formControl]="searchUser"/>
|
|
||||||
<label class="mdl-textfield__label" for="userSearchText">Search user</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<md-input-container class="search-text-container">
|
||||||
|
<input mdInput placeholder="{{'PEOPLE.SEARCH_USER'|translate}}" type="text" id="userSearchText" [value]="" [formControl]="searchUser">
|
||||||
|
</md-input-container>
|
||||||
<div class="search-list-container" id="search-people-list" *ngIf="hasUsers()">
|
<div class="search-list-container" id="search-people-list" *ngIf="hasUsers()">
|
||||||
<adf-people-list
|
<adf-people-list
|
||||||
[users]="users"
|
[users]="users"
|
||||||
@ -24,10 +23,10 @@
|
|||||||
</adf-people-list>
|
</adf-people-list>
|
||||||
</div>
|
</div>
|
||||||
<div class="search-list-action-container">
|
<div class="search-list-action-container">
|
||||||
<button type="button" id="close-people-search" (click)="closeSearchList()" class="mdl-button close">
|
<button md-button type="button" id="close-people-search" (click)="closeSearchList()">
|
||||||
{{'PEOPLE.DIALOG_CLOSE' | translate }}
|
{{'PEOPLE.DIALOG_CLOSE' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button type="button" id="add-people" (click)="addInvolvedUser()" class="mdl-button close">
|
<button md-button type="button" id="add-people" (click)="addInvolvedUser()">
|
||||||
{{'PEOPLE.ADD_USER' | translate }}
|
<ng-content select="action-button-label"></ng-content>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { MdButtonModule, MdInputModule } from '@angular/material';
|
||||||
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
||||||
import { DataTableModule } from 'ng2-alfresco-datatable';
|
import { DataTableModule } from 'ng2-alfresco-datatable';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
@ -52,7 +53,9 @@ describe('PeopleSearchComponent', () => {
|
|||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
CoreModule.forRoot(),
|
CoreModule.forRoot(),
|
||||||
DataTableModule
|
DataTableModule,
|
||||||
|
MdButtonModule,
|
||||||
|
MdInputModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
PeopleSearchComponent,
|
PeopleSearchComponent,
|
||||||
|
@ -15,21 +15,19 @@
|
|||||||
* limitations under the License.
|
* 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 { FormControl } from '@angular/forms';
|
||||||
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { User } from '../models/user.model';
|
import { User } from '../models/user.model';
|
||||||
|
|
||||||
declare let componentHandler: any;
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-people-search, activiti-people-search',
|
selector: 'adf-people-search, activiti-people-search',
|
||||||
templateUrl: './people-search.component.html',
|
templateUrl: './people-search.component.html',
|
||||||
styleUrls: ['./people-search.component.css']
|
styleUrls: ['./people-search.component.css']
|
||||||
})
|
})
|
||||||
|
|
||||||
export class PeopleSearchComponent implements OnInit, AfterViewInit {
|
export class PeopleSearchComponent implements OnInit {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
results: Observable<User[]>;
|
results: Observable<User[]>;
|
||||||
@ -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) {
|
onRowClick(user: User) {
|
||||||
this.selectedUser = user;
|
this.selectedUser = user;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
(success)="involveUser($event)"
|
(success)="involveUser($event)"
|
||||||
(closeSearch)="onCloseSearch()"
|
(closeSearch)="onCloseSearch()"
|
||||||
[results]="peopleSearch$">
|
[results]="peopleSearch$">
|
||||||
|
<header-title>{{ 'TASK_DETAILS.LABELS.ADD_PEOPLE' | translate }}</header-title>
|
||||||
|
<action-button-label>{{ 'PEOPLE.ADD_USER' | translate }}</action-button-label>
|
||||||
</adf-people-search>
|
</adf-people-search>
|
||||||
</div>
|
</div>
|
||||||
<div class="assignment-list-container" id="assignment-people-list" *ngIf="hasPeople()">
|
<div class="assignment-list-container" id="assignment-people-list" *ngIf="hasPeople()">
|
||||||
|
@ -15,7 +15,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { MdButtonModule, MdInputModule } from '@angular/material';
|
||||||
import { AlfrescoTranslationService, CoreModule, LogService } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, CoreModule, LogService } from 'ng2-alfresco-core';
|
||||||
import { DataTableModule } from 'ng2-alfresco-datatable';
|
import { DataTableModule } from 'ng2-alfresco-datatable';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
@ -54,7 +56,9 @@ describe('PeopleComponent', () => {
|
|||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
CoreModule.forRoot(),
|
CoreModule.forRoot(),
|
||||||
DataTableModule
|
DataTableModule,
|
||||||
|
MdButtonModule,
|
||||||
|
MdInputModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
PeopleSearchComponent,
|
PeopleSearchComponent,
|
||||||
@ -63,7 +67,8 @@ describe('PeopleComponent', () => {
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
PeopleService
|
PeopleService
|
||||||
]
|
],
|
||||||
|
schemas: [ NO_ERRORS_SCHEMA ]
|
||||||
}).compileComponents().then(() => {
|
}).compileComponents().then(() => {
|
||||||
|
|
||||||
logService = TestBed.get(LogService);
|
logService = TestBed.get(LogService);
|
||||||
|
@ -28,3 +28,13 @@
|
|||||||
adf-people >>> .assignment-top-container{
|
adf-people >>> .assignment-top-container{
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
@ -13,7 +13,18 @@
|
|||||||
<md-icon *ngIf="showHeaderContent">expand_less</md-icon>
|
<md-icon *ngIf="showHeaderContent">expand_less</md-icon>
|
||||||
<span>{{taskDetails.name || 'No name'}}</span>
|
<span>{{taskDetails.name || 'No name'}}</span>
|
||||||
</h2>
|
</h2>
|
||||||
|
<div class="assignment-container" *ngIf="showAssignee">
|
||||||
|
<adf-people-search
|
||||||
|
(searchPeople)="searchUser($event)"
|
||||||
|
(success)="assignTaskToUser($event)"
|
||||||
|
(closeSearch)="onCloseSearch()"
|
||||||
|
[results]="peopleSearch$">
|
||||||
|
<header-title>{{ 'TASK_DETAILS.LABELS.ADD_ASSIGNEE' | translate }}</header-title>
|
||||||
|
<action-button-label>{{ 'PEOPLE.ADD_ASSIGNEE' | translate }}</action-button-label>
|
||||||
|
</adf-people-search>
|
||||||
|
</div>
|
||||||
<adf-task-header *ngIf="showHeaderContent"
|
<adf-task-header *ngIf="showHeaderContent"
|
||||||
|
[class]="getTaskHeaderViewClass()"
|
||||||
[taskDetails]="taskDetails"
|
[taskDetails]="taskDetails"
|
||||||
[formName]="taskFormName"
|
[formName]="taskFormName"
|
||||||
(claim)="onClaimTask($event)">
|
(claim)="onClaimTask($event)">
|
||||||
|
@ -17,18 +17,30 @@
|
|||||||
|
|
||||||
import { NO_ERRORS_SCHEMA, SimpleChange } from '@angular/core';
|
import { NO_ERRORS_SCHEMA, SimpleChange } from '@angular/core';
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { MdButtonModule, MdInputModule } from '@angular/material';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { Observable } from 'rxjs/Rx';
|
import { Observable } from 'rxjs/Rx';
|
||||||
|
|
||||||
import { ActivitiFormModule, FormModel, FormOutcomeEvent, FormOutcomeModel, FormService } from 'ng2-activiti-form';
|
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 { TaskDetailsModel } from '../models/task-details.model';
|
||||||
|
import { User } from '../models/user.model';
|
||||||
import { noDataMock, taskDetailsMock, taskFormMock, tasksMock } from './../assets/task-details.mock';
|
import { noDataMock, taskDetailsMock, taskFormMock, tasksMock } from './../assets/task-details.mock';
|
||||||
import { PeopleService } from './../services/people.service';
|
import { PeopleService } from './../services/people.service';
|
||||||
import { TaskListService } from './../services/tasklist.service';
|
import { TaskListService } from './../services/tasklist.service';
|
||||||
|
import { PeopleSearchComponent } from './people-search.component';
|
||||||
import { TaskDetailsComponent } from './task-details.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', () => {
|
describe('TaskDetailsComponent', () => {
|
||||||
|
|
||||||
let componentHandler: any;
|
let componentHandler: any;
|
||||||
@ -39,17 +51,22 @@ describe('TaskDetailsComponent', () => {
|
|||||||
let getTaskDetailsSpy: jasmine.Spy;
|
let getTaskDetailsSpy: jasmine.Spy;
|
||||||
let getFormSpy: jasmine.Spy;
|
let getFormSpy: jasmine.Spy;
|
||||||
let getTasksSpy: jasmine.Spy;
|
let getTasksSpy: jasmine.Spy;
|
||||||
|
let assignTaskSpy: jasmine.Spy;
|
||||||
let getFormTaskSpy: jasmine.Spy;
|
let getFormTaskSpy: jasmine.Spy;
|
||||||
let completeTaskSpy: jasmine.Spy;
|
let completeTaskSpy: jasmine.Spy;
|
||||||
|
let logService: LogService;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
CoreModule.forRoot(),
|
CoreModule.forRoot(),
|
||||||
ActivitiFormModule.forRoot()
|
ActivitiFormModule.forRoot(),
|
||||||
|
MdButtonModule,
|
||||||
|
MdInputModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
TaskDetailsComponent
|
TaskDetailsComponent,
|
||||||
|
PeopleSearchComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
TaskListService,
|
TaskListService,
|
||||||
@ -58,6 +75,7 @@ describe('TaskDetailsComponent', () => {
|
|||||||
schemas: [ NO_ERRORS_SCHEMA ]
|
schemas: [ NO_ERRORS_SCHEMA ]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
|
logService = TestBed.get(LogService);
|
||||||
let translateService = TestBed.get(AlfrescoTranslationService);
|
let translateService = TestBed.get(AlfrescoTranslationService);
|
||||||
spyOn(translateService, 'addTranslationFolder').and.stub();
|
spyOn(translateService, 'addTranslationFolder').and.stub();
|
||||||
spyOn(translateService.translate, 'get').and.callFake((key) => { return Observable.of(key); });
|
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));
|
getFormTaskSpy = spyOn(formService, 'getTask').and.returnValue(Observable.of(taskDetailsMock));
|
||||||
|
|
||||||
getTasksSpy = spyOn(service, 'getTasks').and.returnValue(Observable.of(tasksMock));
|
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({}));
|
completeTaskSpy = spyOn(service, 'completeTask').and.returnValue(Observable.of({}));
|
||||||
spyOn(service, 'getComments').and.returnValue(Observable.of(noDataMock));
|
spyOn(service, 'getComments').and.returnValue(Observable.of(noDataMock));
|
||||||
spyOn(service, 'getTaskChecklist').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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -27,10 +27,12 @@ import { Component,
|
|||||||
ViewChild
|
ViewChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { ContentLinkModel, FormFieldValidator, FormModel, FormOutcomeEvent } from 'ng2-activiti-form';
|
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 { TaskQueryRequestRepresentationModel } from '../models/filter.model';
|
||||||
import { TaskDetailsModel } from '../models/task-details.model';
|
import { TaskDetailsModel } from '../models/task-details.model';
|
||||||
import { User } from '../models/user.model';
|
import { User } from '../models/user.model';
|
||||||
|
import { PeopleService } from './../services/people.service';
|
||||||
import { TaskListService } from './../services/tasklist.service';
|
import { TaskListService } from './../services/tasklist.service';
|
||||||
|
|
||||||
declare var require: any;
|
declare var require: any;
|
||||||
@ -123,6 +125,9 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
|
|||||||
@Output()
|
@Output()
|
||||||
executeOutcome: EventEmitter<FormOutcomeEvent> = new EventEmitter<FormOutcomeEvent>();
|
executeOutcome: EventEmitter<FormOutcomeEvent> = new EventEmitter<FormOutcomeEvent>();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
assignTask: EventEmitter<void> = new EventEmitter<void>();
|
||||||
|
|
||||||
taskDetails: TaskDetailsModel;
|
taskDetails: TaskDetailsModel;
|
||||||
taskFormName: string = null;
|
taskFormName: string = null;
|
||||||
|
|
||||||
@ -130,13 +135,22 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
noTaskDetailsTemplateComponent: TemplateRef<any>;
|
noTaskDetailsTemplateComponent: TemplateRef<any>;
|
||||||
|
|
||||||
|
showAssignee: boolean = false;
|
||||||
|
|
||||||
|
private peopleSearchObserver: Observer<User[]>;
|
||||||
|
peopleSearch$: Observable<User[]>;
|
||||||
|
|
||||||
constructor(translateService: AlfrescoTranslationService,
|
constructor(translateService: AlfrescoTranslationService,
|
||||||
private activitiTaskList: TaskListService,
|
private activitiTaskList: TaskListService,
|
||||||
private authService: AlfrescoAuthenticationService,
|
private authService: AlfrescoAuthenticationService,
|
||||||
|
private peopleService: PeopleService,
|
||||||
|
private logService: LogService,
|
||||||
private cardViewUpdateService: CardViewUpdateService) {
|
private cardViewUpdateService: CardViewUpdateService) {
|
||||||
if (translateService) {
|
if (translateService) {
|
||||||
translateService.addTranslationFolder('ng2-activiti-tasklist', 'assets/ng2-activiti-tasklist');
|
translateService.addTranslationFolder('ng2-activiti-tasklist', 'assets/ng2-activiti-tasklist');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.peopleSearch$ = new Observable<User[]>(observer => this.peopleSearchObserver = observer).share();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -150,6 +164,7 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
let taskId = changes.taskId;
|
let taskId = changes.taskId;
|
||||||
|
this.showAssignee = false;
|
||||||
|
|
||||||
if (taskId && !taskId.currentValue) {
|
if (taskId && !taskId.currentValue) {
|
||||||
this.reset();
|
this.reset();
|
||||||
@ -193,6 +208,9 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
private clickTaskDetails(clickNotification: ClickNotification) {
|
private clickTaskDetails(clickNotification: ClickNotification) {
|
||||||
console.log(clickNotification.target);
|
console.log(clickNotification.target);
|
||||||
|
if (clickNotification.target.key === 'assignee') {
|
||||||
|
this.showAssignee = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -320,4 +338,34 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
|
|||||||
isCompletedTask(): boolean {
|
isCompletedTask(): boolean {
|
||||||
return this.taskDetails && this.taskDetails.endDate ? true : undefined;
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
adf-card-view >>> .adf-textitem-clickable-value {
|
||||||
|
color: #ff9100;
|
||||||
|
}
|
@ -23,7 +23,7 @@ import { TaskListService } from './../services/tasklist.service';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-task-header, activiti-task-header',
|
selector: 'adf-task-header, activiti-task-header',
|
||||||
templateUrl: './task-header.component.html',
|
templateUrl: './task-header.component.html',
|
||||||
styleUrls: ['./task-header.component.scss']
|
styleUrls: ['./task-header.component.scss', './task-header.component.css']
|
||||||
})
|
})
|
||||||
export class TaskHeaderComponent implements OnChanges {
|
export class TaskHeaderComponent implements OnChanges {
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ export class TaskHeaderComponent implements OnChanges {
|
|||||||
if (this.taskDetails) {
|
if (this.taskDetails) {
|
||||||
let valueMap = new Map([[this.taskDetails.processInstanceId, this.taskDetails.processDefinitionName]]);
|
let valueMap = new Map([[this.taskDetails.processInstanceId, this.taskDetails.processDefinitionName]]);
|
||||||
this.properties = [
|
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 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 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' }),
|
new CardViewTextItemModel({ label: 'Category', value: this.taskDetails.category, key: 'category', default: 'No category' }),
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
"COMMENTS": "Comments",
|
"COMMENTS": "Comments",
|
||||||
"CHECKLIST": "Checklist",
|
"CHECKLIST": "Checklist",
|
||||||
"INVOLVED_PEOPLE": "Involved people",
|
"INVOLVED_PEOPLE": "Involved people",
|
||||||
"ADD_PEOPLE": "Add people & groups"
|
"ADD_PEOPLE": "Add people & groups",
|
||||||
|
"ADD_ASSIGNEE": "Add new assignee"
|
||||||
},
|
},
|
||||||
"BUTTON": {
|
"BUTTON": {
|
||||||
"COMPLETE": "Complete",
|
"COMPLETE": "Complete",
|
||||||
@ -91,6 +92,8 @@
|
|||||||
"PEOPLE": {
|
"PEOPLE": {
|
||||||
"DIALOG_CLOSE": "CLOSE",
|
"DIALOG_CLOSE": "CLOSE",
|
||||||
"ADD_USER": "ADD",
|
"ADD_USER": "ADD",
|
||||||
|
"ADD_ASSIGNEE": "ASSIGN",
|
||||||
|
"SEARCH_USER": "Search user",
|
||||||
"SEARCH": {
|
"SEARCH": {
|
||||||
"NO_USERS": "No user found to involve"
|
"NO_USERS": "No user found to involve"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user