process details improvements (#1408)

* process details improvements

- new: redirect to task instead of opening a dialog (Activiti parity)
- fixed: task headers for nameless tasks
- fixed: cursor style for task list items
- new: stub for ng-1 directive api (Activiti stencils)
- code cleanup

* error handling fixes
This commit is contained in:
Denys Vuika
2017-01-09 12:57:03 +00:00
committed by Will Abson
parent 35d2109f17
commit 885e0e85aa
15 changed files with 130 additions and 188 deletions

View File

@@ -5,9 +5,9 @@
<!-- TABS --> <!-- TABS -->
<div class="mdl-layout__tab-bar mdl-js-ripple-effect"> <div class="mdl-layout__tab-bar mdl-js-ripple-effect">
<a id="tasks-header" href="#tasks" class="mdl-layout__tab is-active">TASKS</a> <a id="tasks-header" href="#tasks" class="mdl-layout__tab" [class.is-active]="activeTab === 'tasks'" (click)="activeTab = 'tasks'">TASKS</a>
<a id="processes-header" href="#processes" class="mdl-layout__tab" (click)="activeProcess()">PROCESSES</a> <a id="processes-header" href="#processes" class="mdl-layout__tab" [class.is-active]="activeTab === 'processes'" (click)="activeTab = 'processes'">PROCESSES</a>
<a id="report-header" href="#report" class="mdl-layout__tab" (click)="activeReports()">REPORTS</a> <a id="report-header" href="#report" class="mdl-layout__tab" [class.is-active]="activeTab === 'reports'" (click)="activeTab = 'reports'">REPORTS</a>
</div> </div>
</header> </header>
@@ -15,7 +15,7 @@
<!-- TASKS COMPONENT --> <!-- TASKS COMPONENT -->
<section class="mdl-layout__tab-panel is-active" id="tasks"> <section class="mdl-layout__tab-panel" [class.is-active]="activeTab === 'tasks'" id="tasks">
<div class="page-content"> <div class="page-content">
<div class="mdl-grid"> <div class="mdl-grid">
<div class="mdl-cell mdl-cell--2-col task-column mdl-shadow--2dp"> <div class="mdl-cell mdl-cell--2-col task-column mdl-shadow--2dp">
@@ -52,8 +52,8 @@
<!-- PROCESS COMPONENT --> <!-- PROCESS COMPONENT -->
<section class="mdl-layout__tab-panel" id="processes"> <section class="mdl-layout__tab-panel" [class.is-active]="activeTab === 'processes'" id="processes">
<div class="page-content" *ngIf="processTabActivie"> <div class="page-content" *ngIf="activeTab === 'processes'">
<div class="page-content"> <div class="page-content">
<div class="mdl-grid"> <div class="mdl-grid">
<div class="mdl-cell mdl-cell--2-col task-column mdl-shadow--2dp"> <div class="mdl-cell mdl-cell--2-col task-column mdl-shadow--2dp">
@@ -81,9 +81,11 @@
<div class="mdl-cell mdl-cell--7-col task-column mdl-shadow--2dp" *ngIf="!isStartProcessMode()"> <div class="mdl-cell mdl-cell--7-col task-column mdl-shadow--2dp" *ngIf="!isStartProcessMode()">
<span><h5>Process Details</h5></span> <span><h5>Process Details</h5></span>
<hr> <hr>
<activiti-process-instance-details [processInstanceId]="currentProcessInstanceId" <activiti-process-instance-details
(activitiprocesslist)="taskFormCompleted()" [processInstanceId]="currentProcessInstanceId"
(processCancelled)="processCancelled()"></activiti-process-instance-details> (processCancelled)="processCancelled()"
(taskClick)="onProcessDetailsTaskClick($event)">
</activiti-process-instance-details>
</div> </div>
<div class="mdl-cell mdl-cell--7-col task-column" *ngIf="isStartProcessMode()"> <div class="mdl-cell mdl-cell--7-col task-column" *ngIf="isStartProcessMode()">
<span>Start Process</span> <span>Start Process</span>
@@ -98,8 +100,8 @@
<!-- ANALYTICS COMPONENT --> <!-- ANALYTICS COMPONENT -->
<section class="mdl-layout__tab-panel" id="report"> <section class="mdl-layout__tab-panel" [class.is-active]="activeTab === 'reports'" id="report">
<div class="page-content" *ngIf="reportsTabActivie"> <div class="page-content" *ngIf="activeTab === 'reports'">
<div class="mdl-grid"> <div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col task-column mdl-shadow--2dp"> <div class="mdl-cell mdl-cell--4-col task-column mdl-shadow--2dp">
<span><h5>Report List</h5></span> <span><h5>Report List</h5></span>

View File

@@ -19,9 +19,9 @@ import { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular
import { import {
ActivitiApps, ActivitiApps,
ActivitiFilters, ActivitiFilters,
ActivitiTaskDetails,
ActivitiTaskList, ActivitiTaskList,
FilterRepresentationModel FilterRepresentationModel,
TaskDetailsEvent
} from 'ng2-activiti-tasklist'; } from 'ng2-activiti-tasklist';
import { import {
ActivitiProcessFilters, ActivitiProcessFilters,
@@ -52,18 +52,12 @@ const currentProcessIdNew = '__NEW__';
}) })
export class ActivitiDemoComponent implements AfterViewInit { export class ActivitiDemoComponent implements AfterViewInit {
@ViewChild(ActivitiApps)
activitiapps: ActivitiApps;
@ViewChild(ActivitiFilters) @ViewChild(ActivitiFilters)
activitifilter: ActivitiFilters; activitifilter: ActivitiFilters;
@ViewChild(ActivitiTaskList) @ViewChild(ActivitiTaskList)
activititasklist: ActivitiTaskList; activititasklist: ActivitiTaskList;
@ViewChild(ActivitiTaskDetails)
activitidetails: ActivitiTaskDetails;
@ViewChild(ActivitiProcessFilters) @ViewChild(ActivitiProcessFilters)
activitiprocessfilter: ActivitiProcessFilters; activitiprocessfilter: ActivitiProcessFilters;
@@ -89,9 +83,7 @@ export class ActivitiDemoComponent implements AfterViewInit {
taskSchemaColumns: any [] = []; taskSchemaColumns: any [] = [];
processSchemaColumns: any [] = []; processSchemaColumns: any [] = [];
processTabActivie: boolean = false; activeTab: string = 'tasks'; // tasks|processes|reports
reportsTabActivie: boolean = false;
taskFilter: FilterRepresentationModel; taskFilter: FilterRepresentationModel;
report: any; report: any;
@@ -219,10 +211,6 @@ export class ActivitiDemoComponent implements AfterViewInit {
this.activitiprocesslist.reload(); this.activitiprocesslist.reload();
} }
taskFormCompleted(data: any) {
this.activitiprocesslist.reload();
}
onFormCompleted(form) { onFormCompleted(form) {
this.activititasklist.reload(); this.activititasklist.reload();
this.currentTaskId = null; this.currentTaskId = null;
@@ -237,14 +225,6 @@ export class ActivitiDemoComponent implements AfterViewInit {
this.loadStencilScriptsInPageFromActiviti(); this.loadStencilScriptsInPageFromActiviti();
} }
activeProcess() {
this.processTabActivie = true;
}
activeReports() {
this.reportsTabActivie = true;
}
loadStencilScriptsInPageFromActiviti() { loadStencilScriptsInPageFromActiviti() {
this.apiService.getInstance().activiti.scriptFileApi.getControllers().then(response => { this.apiService.getInstance().activiti.scriptFileApi.getControllers().then(response => {
if (response) { if (response) {
@@ -256,4 +236,10 @@ export class ActivitiDemoComponent implements AfterViewInit {
}); });
} }
onProcessDetailsTaskClick(event: TaskDetailsEvent) {
event.preventDefault();
this.currentTaskId = event.value.id;
this.activeTab = 'tasks';
}
} }

View File

@@ -47,7 +47,7 @@ export class EcmModelService {
}); });
} }
}, },
this.handleError err => this.handleError(err)
); );
}); });
@@ -72,10 +72,10 @@ export class EcmModelService {
observer.complete(); observer.complete();
}); });
}, },
this.handleError err => this.handleError(err)
); );
}, },
this.handleError err => this.handleError(err)
); );
}); });
} }
@@ -95,7 +95,7 @@ export class EcmModelService {
observer.complete(); observer.complete();
} }
}, },
this.handleError err => this.handleError(err)
); );
}); });
} }
@@ -111,9 +111,9 @@ export class EcmModelService {
observer.next(typeCreated); observer.next(typeCreated);
observer.complete(); observer.complete();
}, },
this.handleError); err => this.handleError(err));
}, },
this.handleError); err => this.handleError(err));
}); });
} }
@@ -126,25 +126,25 @@ export class EcmModelService {
public activeEcmModel(modelName: string): Observable<any> { public activeEcmModel(modelName: string): Observable<any> {
return Observable.fromPromise(this.apiService.getInstance().core.customModelApi.activateCustomModel(modelName)) return Observable.fromPromise(this.apiService.getInstance().core.customModelApi.activateCustomModel(modelName))
.map(this.toJson) .map(this.toJson)
.catch(this.handleError); .catch(err => this.handleError(err));
} }
public createEcmModel(modelName: string, nameSpace: string): Observable<any> { public createEcmModel(modelName: string, nameSpace: string): Observable<any> {
return Observable.fromPromise(this.apiService.getInstance().core.customModelApi.createCustomModel('DRAFT', '', modelName, modelName, nameSpace)) return Observable.fromPromise(this.apiService.getInstance().core.customModelApi.createCustomModel('DRAFT', '', modelName, modelName, nameSpace))
.map(this.toJson) .map(this.toJson)
.catch(this.handleError); .catch(err => this.handleError(err));
} }
public getEcmModels(): Observable<any> { public getEcmModels(): Observable<any> {
return Observable.fromPromise(this.apiService.getInstance().core.customModelApi.getAllCustomModel()) return Observable.fromPromise(this.apiService.getInstance().core.customModelApi.getAllCustomModel())
.map(this.toJson) .map(this.toJson)
.catch(this.handleError); .catch(err => this.handleError(err));
} }
public getEcmType(modelName: string): Observable<any> { public getEcmType(modelName: string): Observable<any> {
return Observable.fromPromise(this.apiService.getInstance().core.customModelApi.getAllCustomType(modelName)) return Observable.fromPromise(this.apiService.getInstance().core.customModelApi.getAllCustomType(modelName))
.map(this.toJson) .map(this.toJson)
.catch(this.handleError); .catch(err => this.handleError(err));
} }
public createEcmType(typeName: string, modelName: string, parentType: string): Observable<any> { public createEcmType(typeName: string, modelName: string, parentType: string): Observable<any> {
@@ -152,7 +152,7 @@ export class EcmModelService {
return Observable.fromPromise(this.apiService.getInstance().core.customModelApi.createCustomType(modelName, name, parentType, typeName, '')) return Observable.fromPromise(this.apiService.getInstance().core.customModelApi.createCustomType(modelName, name, parentType, typeName, ''))
.map(this.toJson) .map(this.toJson)
.catch(this.handleError); .catch(err => this.handleError(err));
} }
public addPropertyToAType(modelName: string, typeName: string, formFields: any) { public addPropertyToAType(modelName: string, typeName: string, formFields: any) {
@@ -177,11 +177,11 @@ export class EcmModelService {
return Observable.fromPromise(this.apiService.getInstance().core.customModelApi.addPropertyToType(modelName, name, properties)) return Observable.fromPromise(this.apiService.getInstance().core.customModelApi.addPropertyToType(modelName, name, properties))
.map(this.toJson) .map(this.toJson)
.catch(this.handleError); .catch(err => this.handleError(err));
} }
public cleanNameType(name: string): string { cleanNameType(name: string): string {
let cleanName = name; let cleanName = name;
if (name.indexOf(':') !== -1) { if (name.indexOf(':') !== -1) {
cleanName = name.split(':')[1]; cleanName = name.split(':')[1];

View File

@@ -5,8 +5,11 @@ window.angular = {
return { return {
controller: function (controllerName) { controller: function (controllerName) {
console.info('ng1: controller %s requested', controllerName); console.info('ng1: controller %s requested', controllerName);
return { return {}
} },
directive: function (directiveName) {
console.info('ng1: directive %s requested', directiveName);
return {}
} }
} }
} }

View File

@@ -4,8 +4,10 @@
<activiti-process-instance-header [processInstance]="processInstanceDetails"></activiti-process-instance-header> <activiti-process-instance-header [processInstance]="processInstanceDetails"></activiti-process-instance-header>
<div class="mdl-card mdl-shadow--2dp activiti-process-container"> <div class="mdl-card mdl-shadow--2dp activiti-process-container">
<div class="mdl-cell mdl-cell--12-col"> <div class="mdl-cell mdl-cell--12-col">
<activiti-process-instance-tasks [processInstanceDetails]="processInstanceDetails" <activiti-process-instance-tasks
(taskFormCompleted)="bubbleTaskFormCompleted()"></activiti-process-instance-tasks> [processInstanceDetails]="processInstanceDetails"
(taskClick)="onTaskClicked($event)">
</activiti-process-instance-tasks>
</div> </div>
</div> </div>
<div class="mdl-cell mdl-cell--4-col" data-automation-id="header-status" *ngIf="isRunning()"> <div class="mdl-cell mdl-cell--4-col" data-automation-id="header-status" *ngIf="isRunning()">

View File

@@ -21,7 +21,7 @@ import { By } from '@angular/platform-browser';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { AlfrescoTranslateService, CoreModule } from 'ng2-alfresco-core'; import { AlfrescoTranslateService, CoreModule } from 'ng2-alfresco-core';
import { ActivitiFormModule, FormModel, FormService } from 'ng2-activiti-form'; import { ActivitiFormModule, FormService } from 'ng2-activiti-form';
import { ActivitiTaskListModule } from 'ng2-activiti-tasklist'; import { ActivitiTaskListModule } from 'ng2-activiti-tasklist';
import { ActivitiProcessInstanceDetails } from './activiti-process-instance-details.component'; import { ActivitiProcessInstanceDetails } from './activiti-process-instance-details.component';
@@ -139,20 +139,4 @@ describe('ActivitiProcessInstanceDetails', () => {
}); });
}); });
describe('events', () => {
beforeEach(async(() => {
component.processInstanceId = '123';
fixture.detectChanges();
fixture.whenStable();
}));
it('should emit a task form completed event when task form completed', () => {
let emitSpy: jasmine.Spy = spyOn(component.taskFormCompleted, 'emit');
component.bubbleTaskFormCompleted(new FormModel());
expect(emitSpy).toHaveBeenCalled();
});
});
}); });

View File

@@ -17,13 +17,13 @@
import { Component, Input, ViewChild, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core'; import { Component, Input, ViewChild, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
import { AlfrescoTranslateService, LogService } from 'ng2-alfresco-core'; import { AlfrescoTranslateService, LogService } from 'ng2-alfresco-core';
import { TaskDetailsEvent } from 'ng2-activiti-tasklist';
import { ActivitiProcessService } from './../services/activiti-process.service'; import { ActivitiProcessService } from './../services/activiti-process.service';
import { ActivitiProcessInstanceHeader } from './activiti-process-instance-header.component'; import { ActivitiProcessInstanceHeader } from './activiti-process-instance-header.component';
import { ActivitiProcessInstanceTasks } from './activiti-process-instance-tasks.component'; import { ActivitiProcessInstanceTasks } from './activiti-process-instance-tasks.component';
import { ProcessInstance } from '../models/process-instance.model'; import { ProcessInstance } from '../models/process-instance.model';
declare let componentHandler: any;
@Component({ @Component({
selector: 'activiti-process-instance-details', selector: 'activiti-process-instance-details',
moduleId: module.id, moduleId: module.id,
@@ -51,7 +51,7 @@ export class ActivitiProcessInstanceDetails implements OnChanges {
processCancelled: EventEmitter<any> = new EventEmitter<any>(); processCancelled: EventEmitter<any> = new EventEmitter<any>();
@Output() @Output()
taskFormCompleted: EventEmitter<any> = new EventEmitter<any>(); taskClick: EventEmitter<TaskDetailsEvent> = new EventEmitter<TaskDetailsEvent>();
processInstanceDetails: ProcessInstance; processInstanceDetails: ProcessInstance;
@@ -98,10 +98,6 @@ export class ActivitiProcessInstanceDetails implements OnChanges {
} }
} }
bubbleTaskFormCompleted(data: any) {
this.taskFormCompleted.emit(data);
}
isRunning(): boolean { isRunning(): boolean {
return this.processInstanceDetails && !this.processInstanceDetails.ended; return this.processInstanceDetails && !this.processInstanceDetails.ended;
} }
@@ -114,4 +110,9 @@ export class ActivitiProcessInstanceDetails implements OnChanges {
this.logService.error(err); this.logService.error(err);
}); });
} }
// bubbles (taskClick) event
onTaskClicked(event: TaskDetailsEvent) {
this.taskClick.emit(event);
}
} }

View File

@@ -47,3 +47,7 @@
display: block; display: block;
padding: 12px; padding: 12px;
} }
.process-tasks__task-item {
cursor: pointer;
}

View File

@@ -1,6 +1,5 @@
<div *ngIf="showRefreshButton" class="process-tasks-refresh" > <div *ngIf="showRefreshButton" class="process-tasks-refresh" >
<button (click)="onRefreshClicked()" <button (click)="onRefreshClicked()" class="mdl-button mdl-button--icon mdl-js-button mdl-js-ripple-effect">
class="mdl-button mdl-button--icon mdl-js-button mdl-js-ripple-effect">
<i class="material-icons">refresh</i> <i class="material-icons">refresh</i>
</button> </button>
</div> </div>
@@ -12,11 +11,13 @@
<div class="menu-container" *ngIf="activeTasks?.length > 0" data-automation-id="active-tasks"> <div class="menu-container" *ngIf="activeTasks?.length > 0" data-automation-id="active-tasks">
<ul class='mdl-list'> <ul class='mdl-list'>
<li class="mdl-list__item mdl-list__item--two-line" *ngFor="let task of activeTasks"> <li class="mdl-list__item mdl-list__item--two-line process-tasks__task-item" *ngFor="let task of activeTasks">
<span class="mdl-list__item-primary-content" (click)="clickTask($event, task)"> <span class="mdl-list__item-primary-content" (click)="clickTask($event, task)">
<i class="material-icons mdl-list__item-icon">assignment</i> <i class="material-icons mdl-list__item-icon">assignment</i>
<span>{{task.name}}</span> <span>{{task.name || 'Nameless task'}}</span>
<span class="mdl-list__item-sub-title">{{ 'DETAILS.LABELS.TASK_SUBTITLE' | translate:{user: getUserFullName(task.assignee), created: getFormatDate(task.created, 'mediumDate') } }}</span> <span class="mdl-list__item-sub-title">
{{ 'DETAILS.LABELS.TASK_SUBTITLE' | translate:{user: getUserFullName(task.assignee), created: getFormatDate(task.created, 'mediumDate') } }}
</span>
</span> </span>
</li> </li>
</ul> </ul>
@@ -34,12 +35,13 @@
<!--IF START TASK COMPLETED --> <!--IF START TASK COMPLETED -->
<div class="menu-container"> <div class="menu-container">
<ul class='mdl-list'> <ul class='mdl-list'>
<li class="mdl-list__item mdl-list__item--two-line"> <li class="mdl-list__item mdl-list__item--two-line process-tasks__task-item">
<span class="mdl-list__item-primary-content" (click)="clickStartTask($event)"> <span class="mdl-list__item-primary-content" (click)="clickStartTask($event)">
<i class="material-icons mdl-list__item-icon">assignment</i> <i class="material-icons mdl-list__item-icon">assignment</i>
<span>{{ 'DETAILS.LABELS.START_FORM'|translate }}</span> <span>{{ 'DETAILS.LABELS.START_FORM'|translate }}</span>
<span class="mdl-list__item-sub-title">{{ 'DETAILS.LABELS.TASK_SUBTITLE' | translate:{user: <span class="mdl-list__item-sub-title">
getUserFullName(processInstanceDetails.startedBy), created: getFormatDate(processInstanceDetails.started, 'mediumDate') } }}</span> {{ 'DETAILS.LABELS.TASK_SUBTITLE' | translate:{user:getUserFullName(processInstanceDetails.startedBy), created: getFormatDate(processInstanceDetails.started, 'mediumDate') } }}
</span>
</span> </span>
</li> </li>
</ul> </ul>
@@ -53,12 +55,13 @@
<div class="menu-container" *ngIf="completedTasks?.length > 0" data-automation-id="completed-tasks"> <div class="menu-container" *ngIf="completedTasks?.length > 0" data-automation-id="completed-tasks">
<ul class='mdl-list'> <ul class='mdl-list'>
<li class="mdl-list__item mdl-list__item--two-line" *ngFor="let task of completedTasks"> <li class="mdl-list__item mdl-list__item--two-line process-tasks__task-item" *ngFor="let task of completedTasks">
<span class="mdl-list__item-primary-content" (click)="clickTask($event, task)"> <span class="mdl-list__item-primary-content" (click)="clickTask($event, task)">
<i class="material-icons mdl-list__item-icon">assignment</i> <i class="material-icons mdl-list__item-icon">assignment</i>
<span>{{task.name}}</span> <span>{{task.name || 'Nameless task'}}</span>
<span class="mdl-list__item-sub-title">{{ 'DETAILS.LABELS.TASK_SUBTITLE' | translate:{user: <span class="mdl-list__item-sub-title">
getUserFullName(task.assignee), created: getFormatDate(task.created, 'mediumDate') } }}</span> {{ 'DETAILS.LABELS.TASK_SUBTITLE' | translate:{user:getUserFullName(task.assignee), created: getFormatDate(task.created, 'mediumDate') } }}
</span>
</span> </span>
</li> </li>
</ul> </ul>
@@ -68,16 +71,6 @@
{{ 'DETAILS.TASKS.NO_COMPLETED' | translate }} {{ 'DETAILS.TASKS.NO_COMPLETED' | translate }}
</div> </div>
<dialog class="mdl-dialog task-details-dialog" #dialog>
<h4 class="mdl-dialog__title">{{ 'DETAILS.TASKS.TASK_DETAILS' | translate }}</h4>
<div class="mdl-dialog__content form__size">
<activiti-task-details [taskId]="selectedTaskId" (formCompleted)="onTaskFormCompleted()" #taskdetails></activiti-task-details>
</div>
<div class="mdl-dialog__actions">
<button type="button" (click)="closeDialog()" class="mdl-button close" data-automation-id="button-task-close">{{ 'DETAILS.TASKS.TASK_CLOSE' | translate }}</button>
</div>
</dialog>
<dialog *ngIf="hasStartFormDefined()" class="mdl-dialog task-details-dialog" #startDialog> <dialog *ngIf="hasStartFormDefined()" class="mdl-dialog task-details-dialog" #startDialog>
<h4 class="mdl-dialog__title">{{ 'DETAILS.LABELS.START_FORM'|translate }}</h4> <h4 class="mdl-dialog__title">{{ 'DETAILS.LABELS.START_FORM'|translate }}</h4>
<div class="mdl-dialog__content form__size"> <div class="mdl-dialog__content form__size">

View File

@@ -158,51 +158,4 @@ describe('ActivitiProcessInstanceTasks', () => {
expect(getProcessTasksSpy).toHaveBeenCalled(); expect(getProcessTasksSpy).toHaveBeenCalled();
}); });
}); });
describe('task details', () => {
let closeSpy;
beforeEach(async(() => {
closeSpy = spyOn(component.dialog.nativeElement, 'close');
component.processInstanceDetails = exampleProcessInstance;
fixture.detectChanges();
fixture.whenStable();
component.taskdetails = jasmine.createSpyObj('taskdetails', [
'loadDetails'
]);
}));
it('should display task details dialog when task clicked', () => {
let showModalSpy = spyOn(component.dialog.nativeElement, 'showModal');
component.clickTask({}, new TaskDetailsModel(taskDetailsMock));
expect(showModalSpy).toHaveBeenCalled();
});
it('should close the task details dialog when close button clicked', () => {
component.clickTask({}, new TaskDetailsModel(taskDetailsMock));
fixture.detectChanges();
let closeButton: DebugElement = debugElement.query(By.css('[data-automation-id="button-task-close"]'));
closeButton.triggerEventHandler('click', null);
expect(closeSpy).toHaveBeenCalled();
});
it('should output event when task form completed', async(() => {
let emitSpy = spyOn(component.taskFormCompleted, 'emit');
fixture.detectChanges();
component.clickTask({}, new TaskDetailsModel(taskDetailsMock));
fixture.detectChanges();
component.onTaskFormCompleted();
expect(emitSpy).toHaveBeenCalled();
}));
it('should close dialog when task form completed', async(() => {
component.clickTask({}, new TaskDetailsModel(taskDetailsMock));
fixture.detectChanges();
component.onTaskFormCompleted();
expect(closeSpy).toHaveBeenCalled();
}));
});
}); });

View File

@@ -20,7 +20,7 @@ import { DatePipe } from '@angular/common';
import { Observable, Observer } from 'rxjs/Rx'; import { Observable, Observer } from 'rxjs/Rx';
import { AlfrescoTranslateService, LogService } from 'ng2-alfresco-core'; import { AlfrescoTranslateService, LogService } from 'ng2-alfresco-core';
import { ActivitiProcessService } from './../services/activiti-process.service'; import { ActivitiProcessService } from './../services/activiti-process.service';
import { TaskDetailsModel } from 'ng2-activiti-tasklist'; import { TaskDetailsModel, TaskDetailsEvent } from 'ng2-activiti-tasklist';
import { ProcessInstance } from '../models/process-instance.model'; import { ProcessInstance } from '../models/process-instance.model';
declare let componentHandler: any; declare let componentHandler: any;
@@ -40,9 +40,6 @@ export class ActivitiProcessInstanceTasks implements OnInit, OnChanges {
@Input() @Input()
showRefreshButton: boolean = true; showRefreshButton: boolean = true;
@Output()
taskFormCompleted = new EventEmitter();
activeTasks: TaskDetailsModel[] = []; activeTasks: TaskDetailsModel[] = [];
completedTasks: TaskDetailsModel[] = []; completedTasks: TaskDetailsModel[] = [];
@@ -53,9 +50,6 @@ export class ActivitiProcessInstanceTasks implements OnInit, OnChanges {
completedTask$: Observable<TaskDetailsModel>; completedTask$: Observable<TaskDetailsModel>;
message: string; message: string;
selectedTaskId: string;
processId: string; processId: string;
@ViewChild('dialog') @ViewChild('dialog')
@@ -67,6 +61,9 @@ export class ActivitiProcessInstanceTasks implements OnInit, OnChanges {
@ViewChild('taskdetails') @ViewChild('taskdetails')
taskdetails: any; taskdetails: any;
@Output()
taskClick: EventEmitter<TaskDetailsEvent> = new EventEmitter<TaskDetailsEvent>();
constructor(private translate: AlfrescoTranslateService, constructor(private translate: AlfrescoTranslateService,
private activitiProcess: ActivitiProcessService, private activitiProcess: ActivitiProcessService,
private logService: LogService) { private logService: LogService) {
@@ -94,12 +91,12 @@ export class ActivitiProcessInstanceTasks implements OnInit, OnChanges {
} }
} }
public load(processId: string) { load(processId: string) {
this.loadActive(processId); this.loadActive(processId);
this.loadCompleted(processId); this.loadCompleted(processId);
} }
public loadActive(processId: string) { loadActive(processId: string) {
this.activeTasks = []; this.activeTasks = [];
if (processId) { if (processId) {
this.activitiProcess.getProcessTasks(processId, null).subscribe( this.activitiProcess.getProcessTasks(processId, null).subscribe(
@@ -117,7 +114,7 @@ export class ActivitiProcessInstanceTasks implements OnInit, OnChanges {
} }
} }
public loadCompleted(processId: string) { loadCompleted(processId: string) {
this.completedTasks = []; this.completedTasks = [];
if (processId) { if (processId) {
this.activitiProcess.getProcessTasks(processId, 'completed').subscribe( this.activitiProcess.getProcessTasks(processId, 'completed').subscribe(
@@ -157,17 +154,17 @@ export class ActivitiProcessInstanceTasks implements OnInit, OnChanges {
} }
} }
public clickTask($event: any, task: TaskDetailsModel) { clickTask($event: any, task: TaskDetailsModel) {
this.selectedTaskId = task.id; let args = new TaskDetailsEvent(task);
this.showDialog(); this.taskClick.emit(args);
} }
public clickStartTask() { clickStartTask() {
this.processId = this.processInstanceDetails.id; this.processId = this.processInstanceDetails.id;
this.showStartDialog(); this.showStartDialog();
} }
public showStartDialog() { showStartDialog() {
if (!this.startDialog.nativeElement.showModal) { if (!this.startDialog.nativeElement.showModal) {
dialogPolyfill.registerDialog(this.startDialog.nativeElement); dialogPolyfill.registerDialog(this.startDialog.nativeElement);
} }
@@ -177,35 +174,13 @@ export class ActivitiProcessInstanceTasks implements OnInit, OnChanges {
} }
} }
public showDialog() { closeSartDialog() {
if (!this.dialog.nativeElement.showModal) {
dialogPolyfill.registerDialog(this.dialog.nativeElement);
}
if (this.dialog) {
this.dialog.nativeElement.showModal();
}
}
public closeSartDialog() {
if (this.startDialog) { if (this.startDialog) {
this.startDialog.nativeElement.close(); this.startDialog.nativeElement.close();
} }
} }
private closeDialog() { onRefreshClicked() {
if (this.dialog) {
this.dialog.nativeElement.close();
}
this.selectedTaskId = null;
}
public onTaskFormCompleted() {
this.closeDialog();
this.load(this.processInstanceDetails.id);
this.taskFormCompleted.emit(this.processInstanceDetails.id);
}
public onRefreshClicked() {
this.load(this.processInstanceDetails.id); this.load(this.processInstanceDetails.id);
} }
} }

View File

@@ -20,3 +20,4 @@ export * from './filter.model';
export * from './icon.model'; export * from './icon.model';
export * from './user.model'; export * from './user.model';
export * from './task-details.model'; export * from './task-details.model';
export * from './task-details.event';

View File

@@ -0,0 +1,40 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TaskDetailsModel } from './task-details.model';
export class TaskDetailsEvent {
private _value: TaskDetailsModel;
private _defaultPrevented: boolean = false;
get value(): TaskDetailsModel {
return this._value;
}
get defaultPrevented() {
return this._defaultPrevented;
}
constructor(value: TaskDetailsModel) {
this._value = value;
}
preventDefault() {
this._defaultPrevented = true;
}
}

View File

@@ -40,7 +40,7 @@ export class BpmUserService {
getCurrentUserInfo(): Observable<BpmUserModel> { getCurrentUserInfo(): Observable<BpmUserModel> {
return Observable.fromPromise(this.alfrescoJsApi.getInstance().activiti.profileApi.getProfile()) return Observable.fromPromise(this.alfrescoJsApi.getInstance().activiti.profileApi.getProfile())
.map((data) => <BpmUserModel> data) .map((data) => <BpmUserModel> data)
.catch(this.handleError); .catch(err => this.handleError(err));
} }
getCurrentUserProfileImage(): string { getCurrentUserProfileImage(): string {

View File

@@ -40,10 +40,8 @@ export class EcmUserService {
*/ */
getUserInfo(userName: string): Observable<EcmUserModel> { getUserInfo(userName: string): Observable<EcmUserModel> {
return Observable.fromPromise(this.callApiGetPersonInfo(userName)) return Observable.fromPromise(this.callApiGetPersonInfo(userName))
.map( .map(data => <EcmUserModel> data['entry'])
(data) => <EcmUserModel> data['entry'] .catch(err => this.handleError(err));
)
.catch(this.handleError);
} }
getCurrentUserInfo() { getCurrentUserInfo() {