Merge pull request #494 from Alfresco/dev-mvitale-464

Create a single page for Activiti components
This commit is contained in:
Mario Romano
2016-07-29 15:55:35 +01:00
committed by GitHub
39 changed files with 1964 additions and 400 deletions
@@ -2,3 +2,13 @@
cursor: pointer;
font-weight: bold;
}
.activiti {
background-color: #f5f5f5;
}
.task-column {
background-color: #f5f5f5;
padding: 10px 10px 10px 10px;
border: solid 2px rgb(31,188,210);
}
@@ -1,22 +1,60 @@
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--2-col">
<div *ngIf="!hasTasks()">No tasks found</div>
<div *ngIf="hasTasks()">
<ul class="mdl-list">
<li *ngFor="let task of tasks"
class="mdl-list__item activiti-task-list__item"
(click)="onTaskClicked(task, $event)">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-icon">launch</i>
{{task.name || 'Nameless task'}}
</span>
</ul>
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<header class="mdl-layout__header">
<!-- Tabs -->
<div class="mdl-layout__tab-bar mdl-js-ripple-effect">
<a href="#scroll-tab-1" class="mdl-layout__tab is-active">TASK LIST</a>
<a href="#scroll-tab-2" class="mdl-layout__tab">PROCESS LIST</a>
<a href="#scroll-tab-3" class="mdl-layout__tab">REPORT</a>
</div>
</div>
<div class="mdl-cell mdl-cell--10-col">
<activiti-form [taskId]="selectedTask?.id"></activiti-form>
</div>
</header>
<main class="mdl-layout__content activiti">
<section class="mdl-layout__tab-panel is-active" id="scroll-tab-1">
<div class="page-content">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--2-col task-column">
<span>Task Filters</span>
<activiti-filters (filterClick)="onFilterClick($event)"></activiti-filters>
</div>
<div class="mdl-cell mdl-cell--3-col task-column">
<span>Task List</span>
<activiti-tasklist *ngIf="isTaskListSelected()" [taskFilter]="taskFilter" [schemaColumn]="schemaColumn"
(rowClick)="onRowClick($event)" #activititasklist></activiti-tasklist>
</div>
<div class="mdl-cell mdl-cell--7-col task-column">
<span>Task Details</span>
<activiti-task-details [taskId]="currentTaskId" #activitidetails></activiti-task-details>
</div>
</div>
</div>
</section>
<section class="mdl-layout__tab-panel" id="scroll-tab-2">
<div class="page-content">
<div class="page-content">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--2-col task-column">
<span>Process Filters</span>
</div>
<div class="mdl-cell mdl-cell--3-col task-column">
<span>Process List</span>
</div>
<div class="mdl-cell mdl-cell--7-col task-column">
<span>Process Details</span>
</div>
</div>
</div>
</div>
</section>
<section class="mdl-layout__tab-panel" id="scroll-tab-3">
<div class="page-content"><!-- Your content goes here --></div>
</section>
<section class="mdl-layout__tab-panel" id="scroll-tab-4">
<div class="page-content"><!-- Your content goes here --></div>
</section>
<section class="mdl-layout__tab-panel" id="scroll-tab-5">
<div class="page-content"><!-- Your content goes here --></div>
</section>
<section class="mdl-layout__tab-panel" id="scroll-tab-6">
<div class="page-content"><!-- Your content goes here --></div>
</section>
</main>
</div>
@@ -15,9 +15,9 @@
* limitations under the License.
*/
import { Component, OnInit, AfterViewChecked } from '@angular/core';
import { ActivitiForm, FormService } from 'ng2-activiti-form';
import { Component, OnInit, AfterViewChecked, ViewChild } from '@angular/core';
import { ALFRESCO_TASKLIST_DIRECTIVES } from 'ng2-activiti-tasklist';
import { ActivitiForm } from 'ng2-activiti-form';
declare let __moduleName: string;
declare var componentHandler;
@@ -27,22 +27,52 @@ declare var componentHandler;
selector: 'activiti-demo',
templateUrl: './activiti-demo.component.html',
styleUrls: ['./activiti-demo.component.css'],
directives: [ActivitiForm],
providers: [FormService]
directives: [ALFRESCO_TASKLIST_DIRECTIVES, ActivitiForm]
})
export class ActivitiDemoComponent implements OnInit, AfterViewChecked {
tasks: any[] = [];
selectedTask: any;
currentChoice: string = 'task-list';
hasTasks(): boolean {
return this.tasks && this.tasks.length > 0;
@ViewChild('activitidetails')
activitidetails: any;
@ViewChild('activititasklist')
activititasklist: any;
currentTaskId: string;
schemaColumn: any [] = [];
taskFilter: any;
setChoice($event) {
this.currentChoice = $event.target.value;
}
constructor(private formService: FormService) {}
isProcessListSelected() {
return this.currentChoice === 'process-list';
}
ngOnInit() {
this.formService.getTasks().subscribe(val => this.tasks = val || []);
isTaskListSelected() {
return this.currentChoice === 'task-list';
}
constructor() {
console.log('Activiti demo component');
this.schemaColumn = [
{type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true}
// {type: 'text', key: 'created', title: 'Created', sortable: true}
];
}
onFilterClick(event: any) {
this.taskFilter = event;
this.activititasklist.load(this.taskFilter);
}
onRowClick(taskId) {
this.currentTaskId = taskId;
this.activitidetails.loadDetails(this.currentTaskId);
}
ngAfterViewChecked() {
@@ -52,8 +82,4 @@ export class ActivitiDemoComponent implements OnInit, AfterViewChecked {
}
}
onTaskClicked(task, e) {
this.selectedTask = task;
}
}
@@ -1,85 +0,0 @@
/*!
* @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 { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions, Response } from '@angular/http';
// import { Observable } from 'rxjs/Rx';
@Injectable()
export class ActivitiService {
constructor(private http: Http) {}
login(username: string, password: string) {
let url = 'http://localhost:9999/activiti-app/app/authentication';
let headers = new Headers({
'Content-Type': 'application/x-www-form-urlencoded',
'Cache-Control': 'no-cache'
});
let options = new RequestOptions({ headers: headers });
let data = 'j_username='
+ encodeURIComponent(username)
+ '&j_password='
+ encodeURIComponent(password)
+ '&_spring_security_remember_me=true&submit=Login';
return this.http
.post(url, data, options)
.toPromise()
// .then(res => console.log(res))
.catch(this.handleError);
}
getTasks() {
// emulate filter value
let data = JSON.stringify({
'page': 0,
'filterId': 3,
'filter': {
'sort': 'created-desc',
'name': '',
'state': 'open',
'assignment': 'involved'
},
'appDefinitionId': null
});
let url = 'http://localhost:9999/activiti-app/app/rest/filter/tasks';
let headers = new Headers({
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
});
let options = new RequestOptions({ headers: headers });
return this.http
.post(url, data, options)
.toPromise()
.then(this.parseJSON)
.catch(this.handleError);
}
private parseJSON(res: Response) {
let body = res.json();
return body.data || { };
}
private handleError(error: any) {
console.error('An error occurred', error);
return Promise.reject(error.message || error);
}
}
@@ -1,51 +0,0 @@
/*!
* @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 { Component, OnInit } from '@angular/core';
import { ActivitiTaskList } from 'ng2-activiti-tasklist';
import { ObjectDataTableAdapter, ObjectDataColumn } from 'ng2-alfresco-datatable';
@Component({
selector: 'tasks-demo',
template: `
<div class="container">
<activiti-tasklist [data]="data"></activiti-tasklist>
</div>
`,
directives: [ActivitiTaskList],
styles: [':host > .container { padding: 10px; }']
})
export class TasksDemoComponent implements OnInit {
data: ObjectDataTableAdapter;
constructor() {
this.data = new ObjectDataTableAdapter([], []);
}
ngOnInit() {
let schema = [
{type: 'text', key: 'id', title: 'Id'},
{type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true},
{type: 'text', key: 'formKey', title: 'Form Key', sortable: true},
{type: 'text', key: 'created', title: 'Created', sortable: true}
];
let columns = schema.map(col => new ObjectDataColumn(col));
this.data.setColumns(columns);
}
}
@@ -1 +1,150 @@
# Activiti Task List Component for Angular 2
## Prerequisites
Before you start using this development framework, make sure you have installed all required software and done all the
necessary configuration, see this [page](https://github.com/Alfresco/alfresco-ng2-components/blob/master/PREREQUISITES.md).
## Install
```sh
npm install --save ng2-activiti-tasklist
```
### Dependencies
You must separately install the following libraries for your application:
- [ng2-translate](https://github.com/ocombe/ng2-translate)
- [ng2-alfresco-core](https://www.npmjs.com/package/ng2-alfresco-core)
- [ng2-alfresco-datatable](https://www.npmjs.com/package/ng2-alfresco-datatable)
```sh
npm install --save ng2-translate ng2-alfresco-core ng2-alfresco-datatable
```
#### Material Design Lite
The style of this component is based on [material design](https://getmdl.io/), so if you want to visualize it correctly you have to add the material
design dependency to your project:
```sh
npm install --save material-design-icons material-design-lite
```
Also make sure you include these dependencies in your `index.html` file:
```html
<!-- Google Material Design Lite -->
<link rel="stylesheet" href="node_modules/material-design-lite/material.min.css">
<script src="node_modules/material-design-lite/material.min.js"></script>
<link rel="stylesheet" href="node_modules/material-design-icons/iconfont/material-icons.css">
```
## Basic usage example Activiti Task List
The component shows the list of all the tasks filter by the
FilterModel passed in input.
```html
<activiti-tasklist [taskFilter]="taskFilterModel"></activiti-tasklist>
```
#### Events
**onSuccess**: The event is emitted when the task list is loaded
**rowClick**: The event is emitted when the task in the list is
clicked<br />
#### Options
**taskFilter**: { FilterModel } required) FilterModel object that
is passed to the task list API to filter the task list.
Example:
```json
{
"id": 4,
"name": "Involved Tasks",
"recent": false,
"icon": "glyphicon-align-left",
"filter": {
"sort": "created-desc",
"name": "",
"state": "open",
"assignment": "involved"
}
}
```
**schemaColumn**: { any[] } optional) JSON object that represent
the number and the type of the columns that you want show
Example:
```json
[
{type: 'text', key: 'id', title: 'Id'},
{type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true},
{type: 'text', key: 'formKey', title: 'Form Key', sortable: true},
{type: 'text', key: 'created', title: 'Created', sortable: true}
]
```
## Basic usage example Activiti Task Details
The component shows the details of the task id passed in input
```html
<activiti-task-details [taskId]="taskId"></activiti-task-details>
```
#### Events
No events
#### Options
**taskId**: { string } required) The id of the task details that we
are asking for.
## Basic usage example Activiti Filter
The component shows all the available filters.
```html
<activiti-filters></activiti-filters>
```
#### Events
**filterClick**: The event is emitted when the filter in the list is
clicked
#### Options
No options
## Build from sources
Alternatively you can build component from sources with the following commands:
```sh
npm install
npm run build
```
### Build the files and keep watching for changes
```sh
$ npm run build:w
```
### Running unit tests
```sh
npm test
```
### Running unit tests in browser
```sh
npm test-browser
```
This task rebuilds all the code, runs tslint, license checks and other quality check tools
before performing unit testing.
### Code coverage
```sh
npm run coverage
```
@@ -0,0 +1,40 @@
{
"TASK_LIST": {
"MESSAGES": {
"NONE": "No tasks list found."
}
},
"TASK_DETAILS": {
"LABELS": {
"ASSIGNEE": "Assignee",
"DUE": "Due",
"FORM": "Form",
"PEOPLE": "People",
"COMMENTS": "Comments",
"CHECKLIST": "Checklist"
},
"MESSAGES": {
"NONE": "No task details found."
},
"FORM": {
"NONE": "No form."
},
"DUE": {
"NONE": "No due date."
},
"PEOPLE": {
"NONE": "No people involved."
},
"COMMENTS": {
"NONE": "No comments."
},
"CHECKLIST": {
"NONE": "No checklist."
}
},
"TASK_FILTERS": {
"MESSAGES": {
"NONE": "No task filter selected."
}
}
}
@@ -0,0 +1,28 @@
{
"TASK_LIST": {
"MESSAGES": {
"NONE": "Nessuna lista tasks trovata."
}
},
"TASK_DETAILS": {
"LABELS": {
"ASSIGNEE": "Assegnatario",
"DUE": "Scadenza",
"FORM": "Form"
},
"MESSAGES": {
"NONE": "Nessun dettaglio task trovato."
},
"FORM": {
"NONE": "Nessuna form."
},
"DUE": {
"NONE": "Nessuna data di scadenza."
}
},
"TASK_FILTERS": {
"MESSAGES": {
"NONE": "Nessun filtro task selezionato."
}
}
}
@@ -16,7 +16,9 @@
*/
import { ActivitiTaskList } from './src/components/activiti-tasklist.component';
import { ActivitiTaskDetails } from './src/components/activiti-task-details.component';
import { ActivitiFilters } from './src/components/activiti-filters.component';
export * from './src/components/activiti-tasklist.component';
export const ALFRESCO_TASKLIST_DIRECTIVES: [any] = [ActivitiTaskList];
export const ALFRESCO_TASKLIST_DIRECTIVES: [any] = [ActivitiFilters, ActivitiTaskList, ActivitiTaskDetails];
@@ -70,7 +70,8 @@
"zone.js": "0.6.12",
"ng2-translate": "2.2.2",
"ng2-alfresco-core": "0.2.0",
"ng2-alfresco-datatable": "0.2.0",
"ng2-alfresco-datatable": "0.2.0",
"ng2-activiti-form": "0.2.0",
"alfresco-js-api": "^0.1.0"
},
"peerDependencies": {
@@ -0,0 +1,11 @@
:host {
width: 100%;
}
.activiti-label {
font-weight: bolder;
}
.material-icons:hover {
color: rgb(255, 152, 0);
}
@@ -0,0 +1,33 @@
<span class="activiti-label mdl-badge"
[attr.data-badge]="checklist?.length">{{ 'TASK_DETAILS.LABELS.CHECKLIST' | translate }}</span>
<div id="addChecklist" (click)="showDialog()" class="icon material-icons">add</div>
<div class="mdl-tooltip" for="addChecklist">
Add a checklist
</div>
<div class="menu-container" *ngIf="checklist?.length > 0">
<ul class='mdl-list'>
<li class="mdl-list__item" *ngFor="let check of checklist">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-icon">done</i>
{{check.name}}
</span>
</li>
</ul>
</div>
<div *ngIf="checklist?.length === 0">
{{ 'TASK_DETAILS.CHECKLIST.NONE' | translate }}
</div>
<dialog class="mdl-dialog" #dialog>
<h4 class="mdl-dialog__title">New Task</h4>
<div class="mdl-dialog__content">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" [(ngModel)]="taskName" id="task" />
<label class="mdl-textfield__label" for="task">Name</label>
</div>
</div>
<div class="mdl-dialog__actions">
<button type="button" (click)="add()" class="mdl-button">Add Checklist</button>
<button type="button" (click)="cancel()" class="mdl-button close">Cancel</button>
</div>
</dialog>
@@ -0,0 +1,120 @@
/*!
* @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 { Component, Input, OnInit, ViewChild } from '@angular/core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
import { ActivitiTaskListService } from './../services/activiti-tasklist.service';
import { TaskDetailsModel } from '../models/task-details.model';
import { Observer } from 'rxjs/Observer';
import { Observable } from 'rxjs/Observable';
declare let componentHandler: any;
declare let __moduleName: string;
@Component({
selector: 'activiti-checklist',
moduleId: __moduleName,
templateUrl: './activiti-checklist.component.html',
styleUrls: ['./activiti-checklist.component.css'],
providers: [ActivitiTaskListService],
pipes: [AlfrescoPipeTranslate]
})
export class ActivitiChecklist implements OnInit {
@Input()
taskId: string;
@ViewChild('dialog')
dialog: any;
taskName: string;
checklist: TaskDetailsModel [] = [];
private taskObserver: Observer<TaskDetailsModel>;
task$: Observable<TaskDetailsModel>;
/**
* Constructor
* @param auth
* @param translate
*/
constructor(private auth: AlfrescoAuthenticationService,
private translate: AlfrescoTranslationService,
private activitiTaskList: ActivitiTaskListService) {
if (translate) {
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
}
this.task$ = new Observable<TaskDetailsModel>(observer => this.taskObserver = observer).share();
}
ngOnInit() {
this.task$.subscribe((task: TaskDetailsModel) => {
this.checklist.push(task);
});
if (this.taskId) {
this.load(this.taskId);
}
}
public load(taskId: string) {
this.checklist = [];
if (this.taskId) {
this.activitiTaskList.getTaskChecklist(this.taskId).subscribe(
(res: TaskDetailsModel[]) => {
res.forEach((task) => {
this.taskObserver.next(task);
});
},
(err) => {
console.log(err);
}
);
} else {
this.checklist = [];
}
}
public showDialog() {
if (this.dialog) {
this.dialog.nativeElement.showModal();
}
}
public add() {
let newTask = new TaskDetailsModel({name: this.taskName, parentTaskId: this.taskId, assignee: {id: '1'}});
this.activitiTaskList.addTask(newTask).subscribe(
(res: TaskDetailsModel) => {
this.checklist.push(res);
},
(err) => {
console.log(err);
}
);
this.cancel();
}
public cancel() {
if (this.dialog) {
this.dialog.nativeElement.close();
}
}
}
@@ -0,0 +1,11 @@
:host {
width: 100%;
}
.activiti-label {
font-weight: bolder;
}
.material-icons:hover {
color: rgb(255, 152, 0);
}
@@ -0,0 +1,35 @@
<span class="activiti-label mdl-badge"
[attr.data-badge]="comments?.length">{{ 'TASK_DETAILS.LABELS.COMMENTS' |translate }}</span>
<div id="addComment" (click)="showDialog()" class="icon material-icons">add</div>
<div class="mdl-tooltip" for="addComment">
Add a comment
</div>
<div class="menu-container" *ngIf="comments?.length > 0">
<ul class='mdl-list'>
<li class="mdl-list__item" *ngFor="let comment of comments">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-icon">comment</i>
{{comment.message}}
</span>
</li>
</ul>
</div>
<div *ngIf="comments?.length === 0">
{{ 'TASK_DETAILS.COMMENTS.NONE' | translate }}
</div>
<dialog class="mdl-dialog" #dialog>
<h4 class="mdl-dialog__title">New comment</h4>
<div class="mdl-dialog__content">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<textarea class="mdl-textfield__input" type="text" [(ngModel)]="message" rows="1" id="commentText"></textarea>
<label class="mdl-textfield__label" for="commentText">Message</label>
</div>
</div>
<div class="mdl-dialog__actions">
<button type="button" (click)="add()" class="mdl-button">Add Comment</button>
<button type="button" (click)="cancel()" class="mdl-button close">Cancel</button>
</div>
</dialog>
@@ -0,0 +1,121 @@
/*!
* @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 { Component, Input, OnInit, ViewChild } from '@angular/core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
import { ActivitiTaskListService } from './../services/activiti-tasklist.service';
import { Comment } from '../models/comment.model';
import { Observer } from 'rxjs/Observer';
import { Observable } from 'rxjs/Observable';
declare let componentHandler: any;
declare let __moduleName: string;
@Component({
selector: 'activiti-comments',
moduleId: __moduleName,
templateUrl: './activiti-comments.component.html',
styleUrls: ['./activiti-comments.component.css'],
providers: [ActivitiTaskListService],
pipes: [ AlfrescoPipeTranslate ]
})
export class ActivitiComments implements OnInit {
@Input()
taskId: string;
@ViewChild('dialog')
dialog: any;
comments: Comment [] = [];
private commentObserver: Observer<Comment>;
comment$: Observable<Comment>;
message: string;
/**
* Constructor
* @param auth
* @param translate
*/
constructor(private auth: AlfrescoAuthenticationService,
private translate: AlfrescoTranslationService,
private activitiTaskList: ActivitiTaskListService) {
if (translate) {
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
}
this.comment$ = new Observable<Comment>(observer => this.commentObserver = observer).share();
}
ngOnInit() {
this.comment$.subscribe((comment: Comment) => {
this.comments.push(comment);
});
if (this.taskId) {
this.load(this.taskId);
}
}
public load(taskId: string) {
this.comments = [];
if (this.taskId) {
this.activitiTaskList.getTaskComments(this.taskId).subscribe(
(res: Comment[]) => {
res.forEach((comment) => {
this.commentObserver.next(comment);
});
},
(err) => {
console.log(err);
}
);
} else {
this.comments = [];
}
}
public showDialog() {
if (this.dialog) {
this.dialog.nativeElement.showModal();
}
}
public add() {
this.activitiTaskList.addTaskComment(this.taskId, this.message).subscribe(
(res: Comment) => {
this.comments.push(res);
this.message = '';
},
(err) => {
console.log(err);
}
);
this.cancel();
}
public cancel() {
if (this.dialog) {
this.dialog.nativeElement.close();
}
}
}
@@ -0,0 +1,10 @@
<div class="menu-container">
<ul class='mdl-list'>
<li class="mdl-list__item"(click)="selectFilter(filter)" *ngFor="let filter of filters">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-icon">assignment</i>
{{filter.name}}
</span>
</li>
</ul>
</div>
@@ -0,0 +1,96 @@
/*!
* @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 {
it,
describe,
expect,
beforeEach
} from '@angular/core/testing';
import { ActivitiFilters } from './activiti-filters.component';
import { ActivitiTaskListService } from '../services/activiti-tasklist.service';
import { Observable } from 'rxjs/Rx';
import { FilterModel } from '../models/filter.model';
describe('ActivitiFilters', () => {
let filterList: ActivitiFilters;
let fakeGlobalFilter = [];
fakeGlobalFilter.push(new FilterModel('FakeInvolvedTasks', false, 'glyphicon-align-left', '', 'open', 'fake-involved'));
fakeGlobalFilter.push(new FilterModel('FakeMyTasks', false, 'glyphicon-align-left', '', 'open', 'fake-assignee'));
let fakeGlobalFilterPromise = new Promise(function (resolve, reject) {
resolve(fakeGlobalFilter);
});
let fakeErrorFilterList = {
error: 'wrong request'
};
let fakeErrorFilterPromise = new Promise(function (resolve, reject) {
reject(fakeErrorFilterList);
});
beforeEach(() => {
let activitiService = new ActivitiTaskListService(null, null);
filterList = new ActivitiFilters(null, null, activitiService);
});
it('should return the filter task list', (done) => {
spyOn(filterList.activiti, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
filterList.onSuccess.subscribe( (res) => {
expect(res).toBeDefined();
expect(res).toEqual('Filter task list loaded');
expect(filterList.filters).toBeDefined();
expect(filterList.filters.length).toEqual(2);
expect(filterList.filters[0].name).toEqual('FakeInvolvedTasks');
expect(filterList.filters[1].name).toEqual('FakeMyTasks');
done();
});
filterList.ngOnInit();
});
it('should emit an error with a bad response', (done) => {
spyOn(filterList.activiti, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeErrorFilterPromise));
filterList.onError.subscribe( (err) => {
expect(err).toBeDefined();
expect(err).toEqual('Error to load a task filter list');
done();
});
filterList.ngOnInit();
});
it('should emit an event when a filter is selected', (done) => {
let currentFilter = new FilterModel('FakeInvolvedTasks', false, 'glyphicon-align-left', '', 'open', 'fake-involved');
filterList.filterClick.subscribe((filter: FilterModel) => {
expect(filter).toBeDefined();
expect(filter).toEqual(currentFilter);
expect(filterList.currentFilter).toEqual(currentFilter);
done();
});
filterList.selectFilter(currentFilter);
});
});
@@ -0,0 +1,103 @@
/*!
* @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 { Component, Output, EventEmitter, OnInit} from '@angular/core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
import { ActivitiTaskListService } from './../services/activiti-tasklist.service';
import { FilterModel } from '../models/filter.model';
import { Observer } from 'rxjs/Observer';
import { Observable } from 'rxjs/Observable';
declare let componentHandler: any;
declare let __moduleName: string;
@Component({
selector: 'activiti-filters',
moduleId: __moduleName,
templateUrl: './activiti-filters.component.html',
providers: [ActivitiTaskListService],
pipes: [ AlfrescoPipeTranslate ]
})
export class ActivitiFilters implements OnInit {
@Output()
filterClick: EventEmitter<FilterModel> = new EventEmitter<FilterModel>();
@Output()
onSuccess: EventEmitter<string> = new EventEmitter<string>();
@Output()
onError: EventEmitter<string> = new EventEmitter<string>();
private filterObserver: Observer<FilterModel>;
filter$: Observable<FilterModel>;
currentFilter: FilterModel;
filters: FilterModel [] = [];
/**
* Constructor
* @param auth
* @param translate
*/
constructor(private auth: AlfrescoAuthenticationService,
private translate: AlfrescoTranslationService,
public activiti: ActivitiTaskListService) {
this.filter$ = new Observable<FilterModel>(observer => this.filterObserver = observer).share();
if (translate) {
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
}
}
ngOnInit() {
this.filter$.subscribe((filter: FilterModel) => {
this.filters.push(filter);
});
this.load();
}
/**
* The method call the adapter data table component for render the task list
* @param tasks
*/
private load() {
this.activiti.getTaskListFilters().subscribe(
(res: FilterModel[]) => {
res.forEach((filter) => {
this.filterObserver.next(filter);
});
this.onSuccess.emit('Filter task list loaded');
},
(err) => {
console.log(err);
this.onError.emit('Error to load a task filter list');
}
);
}
/**
* Pass the selected filter as next
* @param filter
*/
public selectFilter(filter: FilterModel) {
this.currentFilter = filter;
this.filterClick.emit(filter);
}
}
@@ -0,0 +1,11 @@
:host {
width: 100%;
}
.activiti-label {
font-weight: bolder;
}
.material-icons:hover {
color: rgb(255, 152, 0);
}
@@ -0,0 +1,33 @@
<span class="activiti-label mdl-badge"
[attr.data-badge]="people?.length">{{ 'TASK_DETAILS.LABELS.PEOPLE' | translate }}</span>
<div id="addPeople" (click)="showDialog()" class="icon material-icons">add</div>
<div class="mdl-tooltip" for="addPeople">
Add a people
</div>
<div class="menu-container" *ngIf="people?.length > 0">
<ul class='mdl-list'>
<li class="mdl-list__item" *ngFor="let user of people">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-icon">face</i>
{{user.firstName}}
</span>
</li>
</ul>
</div>
<div *ngIf="people?.length === 0">
{{ 'TASK_DETAILS.PEOPLE.NONE' | translate }}
</div>
<dialog class="mdl-dialog" #dialog>
<h4 class="mdl-dialog__title">New User</h4>
<div class="mdl-dialog__content">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" id="people" />
<label class="mdl-textfield__label" for="people">Name</label>
</div>
</div>
<div class="mdl-dialog__actions">
<button type="button" (click)="add()" class="mdl-button">Add User</button>
<button type="button" (click)="cancel()" class="mdl-button close">Cancel</button>
</div>
</dialog>
@@ -0,0 +1,84 @@
/*!
* @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 { Component, Input, OnInit, ViewChild } from '@angular/core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
import { User } from '../models/user.model';
import { Observer } from 'rxjs/Observer';
import { Observable } from 'rxjs/Observable';
declare let componentHandler: any;
declare let __moduleName: string;
@Component({
selector: 'activiti-people',
moduleId: __moduleName,
templateUrl: './activiti-people.component.html',
styleUrls: ['./activiti-people.component.css'],
pipes: [ AlfrescoPipeTranslate ]
})
export class ActivitiPeople implements OnInit {
@Input()
people: User [] = [];
@ViewChild('dialog')
dialog: any;
private peopleObserver: Observer<User>;
people$: Observable<User>;
/**
* Constructor
* @param auth
* @param translate
*/
constructor(private auth: AlfrescoAuthenticationService,
private translate: AlfrescoTranslationService) {
if (translate) {
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
}
this.people$ = new Observable<User>(observer => this.peopleObserver = observer).share();
}
ngOnInit() {
this.people$.subscribe((user: User) => {
this.people.push(user);
});
}
public showDialog() {
if (this.dialog) {
this.dialog.nativeElement.showModal();
}
}
public add() {
alert('add people');
this.cancel();
}
public cancel() {
if (this.dialog) {
this.dialog.nativeElement.close();
}
}
}
@@ -0,0 +1,3 @@
:host {
width: 100%;
}
@@ -0,0 +1,17 @@
<div *ngIf="!taskDetails">{{ 'TASK_DETAILS.MESSAGES.NONE' | translate }}</div>
<div *ngIf="taskDetails">
<h2 class="mdl-card__title-text">{{taskDetails.name}}</h2>
<activiti-task-header [taskDetails]="taskDetails" #activitiheader></activiti-task-header>
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col">
<activiti-people [people]="taskPeople"></activiti-people>
</div>
<div class="mdl-cell mdl-cell--4-col">
<activiti-comments [taskId]="taskId" #activiticomments></activiti-comments>
</div>
<div class="mdl-cell mdl-cell--4-col">
<activiti-checklist [taskId]="taskId" #activitichecklist></activiti-checklist>
</div>
</div>
<activiti-form *ngIf="taskDetails.formKey" [taskId]="taskId" #activitiForm ></activiti-form>
</div>
@@ -0,0 +1,114 @@
/*!
* @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 { Component, Input, OnInit, ViewChild } from '@angular/core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
import { ActivitiTaskListService } from './../services/activiti-tasklist.service';
import { ActivitiTaskHeader } from './activiti-task-header.component';
import { ActivitiComments } from './activiti-comments.component';
import { ActivitiChecklist } from './activiti-checklist.component';
import { ActivitiPeople } from './activiti-people.component';
import { TaskDetailsModel } from '../models/task-details.model';
import { User } from '../models/user.model';
import { ActivitiForm, FormModel, FormService } from 'ng2-activiti-form';
declare let componentHandler: any;
declare let __moduleName: string;
@Component({
selector: 'activiti-task-details',
moduleId: __moduleName,
templateUrl: './activiti-task-details.component.html',
styleUrls: ['./activiti-task-details.component.css'],
providers: [ActivitiTaskListService, FormService],
directives: [ActivitiTaskHeader, ActivitiPeople, ActivitiComments, ActivitiChecklist, ActivitiForm],
pipes: [AlfrescoPipeTranslate]
})
export class ActivitiTaskDetails implements OnInit {
@Input()
taskId: string;
@ViewChild('activiticomments')
activiticomments: any;
@ViewChild('activitichecklist')
activitichecklist: any;
taskDetails: TaskDetailsModel;
taskForm: FormModel;
taskPeople: User[] = [];
/**
* Constructor
* @param auth
* @param translate
*/
constructor(private auth: AlfrescoAuthenticationService,
private translate: AlfrescoTranslationService,
private activitiForm: FormService,
private activitiTaskList: ActivitiTaskListService) {
if (translate) {
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
}
}
ngOnInit() {
if (this.taskId) {
this.loadDetails(this.taskId);
}
}
loadDetails(taskId: string) {
this.taskForm = null;
this.taskPeople = [];
if (taskId) {
this.activitiTaskList.getTaskDetails(taskId).subscribe(
(res: TaskDetailsModel) => {
this.taskDetails = res;
if (this.taskDetails && this.taskDetails.involvedPeople) {
this.taskDetails.involvedPeople.forEach((user) => {
this.taskPeople.push(new User(user.id, user.email, user.firstName, user.lastName));
});
if (this.activiticomments) {
this.activiticomments.load(this.taskDetails.id);
}
if (this.activitichecklist) {
this.activitichecklist.load(this.taskDetails.id);
}
}
console.log(this.taskDetails);
}
);
}
}
onComplete() {
this.activitiTaskList.completeTask(this.taskId).subscribe(
(res) => {
console.log(res);
}
);
}
}
@@ -0,0 +1,7 @@
:host {
width: 100%;
}
.activiti-label {
font-weight: bolder;
}
@@ -0,0 +1,18 @@
<div *ngIf="taskDetails">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col">
<span class="activiti-label">{{ 'TASK_DETAILS.LABELS.ASSIGNEE' | translate }}</span>:
{{taskDetails.assignee.lastName }}
</div>
<div class="mdl-cell mdl-cell--4-col">
<span class="activiti-label">
{{ 'TASK_DETAILS.LABELS.DUE' | translate }}</span>:
{{taskDetails?.dueDate ? taskDetails.dueDate : ('TASK_DETAILS.DUE.NONE' |translate) }}
</div>
<div class="mdl-cell mdl-cell--4-col">
<span class="activiti-label">{{ 'TASK_DETAILS.LABELS.FORM' | translate }}</span>:
{{taskForm?.name ? taskForm.name : ('TASK_DETAILS.FORM.NONE' | translate) }}
</div>
</div>
</div>
@@ -0,0 +1,82 @@
/*!
* @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 { Component, Input, OnInit, OnChanges } from '@angular/core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
import { TaskDetailsModel } from '../models/task-details.model';
import { FormModel, FormService } from 'ng2-activiti-form';
declare let componentHandler: any;
declare let __moduleName: string;
@Component({
selector: 'activiti-task-header',
moduleId: __moduleName,
templateUrl: './activiti-task-header.component.html',
styleUrls: ['./activiti-task-header.component.css'],
providers: [ FormService ],
pipes: [ AlfrescoPipeTranslate ]
})
export class ActivitiTaskHeader implements OnInit, OnChanges {
@Input()
taskDetails: TaskDetailsModel;
taskForm: FormModel;
/**
* Constructor
* @param auth
* @param translate
*/
constructor(private auth: AlfrescoAuthenticationService,
private activitiForm: FormService,
private translate: AlfrescoTranslationService) {
if (translate) {
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
}
}
ngOnInit() {
if (this.taskDetails && this.taskDetails.formKey) {
this.load(this.taskDetails.id);
}
}
ngOnChanges(change) {
if (this.taskDetails && this.taskDetails.formKey) {
this.load(this.taskDetails.id);
} else {
this.taskForm = null;
}
}
public load(taskId: string) {
if (taskId) {
this.activitiForm.getTaskForm(taskId).subscribe(
(response) => {
this.taskForm = response;
},
(err) => {
console.error(err);
}
);
}
}
}
@@ -1,12 +1,12 @@
<div [ngStyle]="locationCss" class="menu-container">
<ul class="context-menu">
<li (click)="selectFilter(filter)" *ngFor="let filter of filtersList | async">
{{filter.name}}
</li>
</ul>
<div *ngIf="!taskFilter">{{ 'TASK_FILTERS.MESSAGES.NONE' | translate }}</div>
<div *ngIf="taskFilter">
<div *ngIf="!isTaskListEmpty()">
<alfresco-datatable
[data]="tasks"
(rowClick)="onRowClick($event)">
</alfresco-datatable>
</div>
<div *ngIf="isTaskListEmpty()">
{{ 'TASK_LIST.MESSAGES.NONE' | translate }}
</div>
</div>
<alfresco-datatable
[data]="tasks"
(rowClick)="onRowClick($event)">
</alfresco-datatable>
@@ -26,26 +26,13 @@ import { ActivitiTaskList } from './activiti-tasklist.component';
import { ActivitiTaskListService } from '../services/activiti-tasklist.service';
import { FilterModel } from '../models/filter.model';
import { Observable } from 'rxjs/Rx';
import { ObjectDataRow, DataRowEvent } from 'ng2-alfresco-datatable';
describe('ActivitiTaskList', () => {
let taskList: ActivitiTaskList;
let fakeGlobalFilter = {
size: 2, total: 2, start: 0,
data: [
{
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
filter: {sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved'}
},
{
id: 2, name: 'FakeMyTasks', recent: false, icon: 'glyphicon-align-left',
filter: {sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee'}
}
]
};
let fakeGlobalTask = {
size: 1, total: 12, start: 0,
data: [
@@ -64,18 +51,14 @@ describe('ActivitiTaskList', () => {
]
};
let fakeErrorTaskList = {
error: 'wrong request'
};
let fakeGlobalFilterPromise = new Promise(function (resolve, reject) {
resolve(fakeGlobalFilter);
});
let fakeGlobalTaskPromise = new Promise(function (resolve, reject) {
resolve(fakeGlobalTask);
});
let fakeErrorTaskList = {
error: 'wrong request'
};
let fakeErrorTaskPromise = new Promise(function (resolve, reject) {
reject(fakeErrorTaskList);
});
@@ -85,76 +68,71 @@ describe('ActivitiTaskList', () => {
taskList = new ActivitiTaskList(null, null, activitiSerevice);
});
it('should return the default filters', (done) => {
spyOn(taskList.activiti, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
it('should use the default schemaColumn as default', () => {
taskList.ngOnInit();
taskList.filtersList.subscribe((res: any) => {
expect(res).toBeDefined();
expect(res.length).toEqual(2);
expect(res[0].name).toEqual('FakeInvolvedTasks');
expect(res[1].name).toEqual('FakeMyTasks');
done();
});
expect(taskList.schemaColumn).toBeDefined();
expect(taskList.schemaColumn.length).toEqual(4);
});
it('should subscribe to Filter when a filter is selected', (done) => {
let filterModel: FilterModel = new FilterModel('name', false, 'icon', 'open', 'fake-assignee');
taskList.filter$.subscribe((filter: FilterModel) => {
expect(filter).toBe(filterModel);
done();
});
taskList.selectFilter(filterModel);
it('should use the schemaColumn passed in input', () => {
taskList.schemaColumn = [
{type: 'text', key: 'fake-id', title: 'Name'}
];
taskList.ngOnInit();
expect(taskList.schemaColumn).toBeDefined();
expect(taskList.schemaColumn.length).toEqual(1);
});
it('should return the tasks when a filter is selected', (done) => {
it('should return an empty task list when the taskFilter is not passed', () => {
taskList.ngOnInit();
expect(taskList.tasks).toBeUndefined();
expect(taskList.isTaskListEmpty()).toBeTruthy();
});
it('should return the filtered task list when the taskFilter is passed', (done) => {
spyOn(taskList.activiti, 'getTasks').and.returnValue(Observable.fromPromise(fakeGlobalTaskPromise));
spyOn(taskList.activiti, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
taskList.taskFilter = new FilterModel('name', false, 'icon', '', 'open', 'fake-assignee');
taskList.onSuccess.subscribe( (res) => {
expect(res).toBeDefined();
expect(res).toEqual('Task List loaded');
expect(taskList.tasks).toBeDefined();
expect(taskList.isTaskListEmpty()).not.toBeTruthy();
expect(taskList.tasks.getRows().length).toEqual(2);
expect(taskList.tasks.getRows()[0].getValue('name')).toEqual('fake-long-name-fake-long-name-fake-long-name-fak50...');
expect(taskList.tasks.getRows()[1].getValue('name')).toEqual('Nameless task');
done();
});
taskList.ngOnInit();
let filterModel: FilterModel = new FilterModel('name', false, 'icon', 'open', 'fake-assignee');
taskList.selectFilter(filterModel);
taskList.activiti.getTasks(filterModel).subscribe(
(res) => {
expect(res).toBeDefined();
done();
});
});
it('should throw an exception when the response is wrong', (done) => {
spyOn(taskList.activiti, 'getTasks').and.returnValue(Observable.fromPromise(fakeErrorTaskPromise));
spyOn(taskList.activiti, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
taskList.taskFilter = new FilterModel('name', false, 'icon', '', 'open', 'fake-assignee');
taskList.onError.subscribe( (err) => {
expect(err).toBeDefined();
expect(err).toEqual('Error to load a tasks list');
done();
});
taskList.ngOnInit();
let filterModel: FilterModel = new FilterModel('name', false, 'icon', 'open', 'fake-assignee');
taskList.selectFilter(filterModel);
taskList.activiti.getTasks(filterModel).subscribe(
(res) => {
expect(res).toBeUndefined();
},
(err: any) => {
expect(err).toBeDefined();
expect(err.error).toEqual('wrong request');
done();
});
});
it('should optimize the task name when are empty or exceed 50 characters', (done) => {
spyOn(taskList.activiti, 'getTasks').and.returnValue(Observable.fromPromise(fakeGlobalTaskPromise));
spyOn(taskList.activiti, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
taskList.ngOnInit();
it('should emit row click event', (done) => {
let row = new ObjectDataRow({
id: 999
});
let rowEvent = <DataRowEvent> {value: row};
let filterModel: FilterModel = new FilterModel('name', false, 'icon', 'open', 'fake-assignee');
taskList.selectFilter(filterModel);
taskList.rowClick.subscribe(taskId => {
expect(taskId).toEqual(999);
done();
});
taskList.activiti.getTasks(filterModel).subscribe(
(res) => {
expect(res.data[0].name).toEqual('fake-long-name-fake-long-name-fake-long-name-fak50...');
expect(res.data[1].name).toEqual('Nameless task');
done();
});
taskList.onRowClick(rowEvent);
});
});
@@ -15,13 +15,11 @@
* limitations under the License.
*/
import { Component, Input, OnInit} from '@angular/core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { Component, Input, Output, EventEmitter, OnInit} from '@angular/core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
import { ALFRESCO_DATATABLE_DIRECTIVES, ObjectDataTableAdapter, DataTableAdapter, DataRowEvent } from 'ng2-alfresco-datatable';
import { ActivitiTaskListService } from './../services/activiti-tasklist.service';
import { FilterModel } from '../models/filter.model';
import { Observer } from 'rxjs/Observer';
import { Observable } from 'rxjs/Observable';
declare let componentHandler: any;
declare let __moduleName: string;
@@ -31,22 +29,38 @@ declare let __moduleName: string;
moduleId: __moduleName,
templateUrl: './activiti-tasklist.component.html',
directives: [ALFRESCO_DATATABLE_DIRECTIVES],
providers: [ActivitiTaskListService]
providers: [ActivitiTaskListService],
pipes: [ AlfrescoPipeTranslate ]
})
export class ActivitiTaskList implements OnInit {
@Input()
taskFilter: FilterModel;
@Input()
schemaColumn: any[] = [
{type: 'text', key: 'id', title: 'Id'},
{type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true},
{type: 'text', key: 'formKey', title: 'Form Key', sortable: true},
{type: 'text', key: 'created', title: 'Created', sortable: true}
];
@Output()
rowClick: EventEmitter<string> = new EventEmitter<string>();
@Output()
onSuccess: EventEmitter<string> = new EventEmitter<string>();
@Output()
onError: EventEmitter<string> = new EventEmitter<string>();
data: DataTableAdapter;
private filterObserver: Observer<FilterModel>;
filter$: Observable<FilterModel>;
tasks: ObjectDataTableAdapter;
currentTaskId: string;
filtersList: Observable<FilterModel>;
/**
* Constructor
* @param auth
@@ -55,7 +69,6 @@ export class ActivitiTaskList implements OnInit {
constructor(private auth: AlfrescoAuthenticationService,
private translate: AlfrescoTranslationService,
public activiti: ActivitiTaskListService) {
this.filter$ = new Observable<FilterModel>(observer => this.filterObserver = observer).share();
if (translate) {
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
@@ -63,38 +76,52 @@ export class ActivitiTaskList implements OnInit {
}
ngOnInit() {
this.filtersList = this.activiti.getTaskListFilters().map(res => (res.data));
this.data = new ObjectDataTableAdapter(
[],
this.schemaColumn
);
this.filter$.subscribe((filter: FilterModel) => {
this.activiti.getTasks(filter).subscribe(
(res) => {
this.loadTasks(res.data);
}, (err) => {
console.error(err);
});
});
if (this.taskFilter) {
this.load(this.taskFilter);
}
}
public load(filter: FilterModel) {
this.activiti.getTasks(filter).subscribe(
(res) => {
this.renderTasks(res.data);
this.onSuccess.emit('Task List loaded');
}, (err) => {
console.error(err);
this.onError.emit('Error to load a tasks list');
});
}
/**
* The method call the adapter data table component for render the task list
* @param tasks
*/
private loadTasks(tasks: any[]) {
private renderTasks(tasks: any[]) {
tasks = this.optimizeTaskName(tasks);
this.tasks = new ObjectDataTableAdapter(tasks, this.data.getColumns());
}
/**
* Pass the selected filter as next
* @param filter
* Check if the tasks list is empty
* @returns {ObjectDataTableAdapter|boolean}
*/
public selectFilter(filter: FilterModel) {
this.filterObserver.next(filter);
isTaskListEmpty(): boolean {
return this.tasks === undefined || (this.tasks && this.tasks.getRows() && this.tasks.getRows().length === 0);
}
/**
* Emit the event rowClick passing the current task id when the row is clicked
* @param event
*/
onRowClick(event: DataRowEvent) {
let item = event;
this.currentTaskId = item.value.getValue('id');
this.rowClick.emit(this.currentTaskId);
}
/**
@@ -0,0 +1,39 @@
/*!
* @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.
*/
/**
*
* This object represent the comment of a task.
*
*
* @returns {Comment} .
*/
import { User } from './user.model';
export class Comment {
id: number;
message: string;
created: string;
createdBy: User;
constructor(id: number, message: string, created: string, createdBy: User) {
this.id = id;
this.message = message;
this.created = created;
this.createdBy = createdBy;
}
}
@@ -29,11 +29,11 @@ export class FilterModel {
icon: string;
filter: FilterParamsModel;
constructor(name: string, recent: boolean, icon: string, state: string, assignment: string) {
constructor(name: string, recent: boolean, icon: string, query: string, state: string, assignment: string) {
this.name = name;
this.recent = recent;
this.icon = icon;
this.filter = new FilterParamsModel(name, state, assignment);
this.filter = new FilterParamsModel(query, state, assignment);
}
}
@@ -49,8 +49,8 @@ export class FilterParamsModel {
state: string;
assignment: string;
constructor(name: string, state: string, assignment: string) {
this.name = name;
constructor(query: string, state: string, assignment: string) {
this.name = query;
this.state = state;
this.assignment = assignment;
}
@@ -0,0 +1,93 @@
/*!
* @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.
*/
/**
*
* This object represent the details of a task.
*
*
* @returns {TaskDetailsModel} .
*/
import { User } from './user.model';
export class TaskDetailsModel {
id: string;
name: string;
assignee: User;
priority: number;
adhocTaskCanBeReassigned: number;
category: string;
created: string;
description: string;
dueDate: string;
duration: string;
endDate: string;
executionId: string;
formKey: string;
initiatorCanCompleteTask: boolean = false;
managerOfCandidateGroup: boolean = false;
memberOfCandidateGroup: boolean = false;
memberOfCandidateUsers: boolean = false;
involvedPeople: User [];
parentTaskId: string;
parentTaskName: string;
processDefinitionCategory: string;
processDefinitionDeploymentId: string;
processDefinitionDescription: string;
processDefinitionId: string;
processDefinitionKey: string;
processDefinitionName: string;
processDefinitionVersion: number = 0;
processInstanceId: string;
processInstanceName: string;
processInstanceStartUserId: string;
taskDefinitionKey: string;
constructor(obj: any) {
this.id = obj.id;
this.name = obj.name;
this.priority = obj.priority;
this.assignee = new User(obj.assignee.id, obj.assignee.email, obj.assignee.firstName, obj.assignee.lastName);
this.adhocTaskCanBeReassigned = obj.adhocTaskCanBeReassigned;
this.created = obj.created;
this.description = obj.description;
this.dueDate = obj.dueDate;
this.duration = obj.duration;
this.endDate = obj.endDate;
this.executionId = obj.executionId;
this.formKey = obj.formKey;
this.initiatorCanCompleteTask = obj.initiatorCanCompleteTask;
this.managerOfCandidateGroup = obj.managerOfCandidateGroup;
this.memberOfCandidateGroup = obj.memberOfCandidateGroup;
this.memberOfCandidateUsers = obj.memberOfCandidateUsers;
this.involvedPeople = obj.involvedPeople;
this.parentTaskId = obj.parentTaskId;
this.parentTaskName = obj.parentTaskName;
this.processDefinitionCategory = obj.processDefinitionCategory;
this.processDefinitionDeploymentId = obj.processDefinitionDeploymentId;
this.processDefinitionDescription = obj.processDefinitionDescription;
this.processDefinitionId = obj.processDefinitionId;
this.processDefinitionKey = obj.processDefinitionKey;
this.processDefinitionName = obj.processDefinitionName;
this.processDefinitionVersion = obj.processDefinitionVersion;
this.processInstanceId = obj.processInstanceId;
this.processInstanceName = obj.processInstanceName;
this.processInstanceStartUserId = obj.processInstanceStartUserId;
this.taskDefinitionKey = obj.taskDefinitionKey;
}
}
@@ -0,0 +1,38 @@
/*!
* @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.
*/
/**
*
* This object represent the user.
*
*
* @returns {User} .
*/
export class User {
id: number;
email: string;
firstName: string;
lastName: string;
constructor(id: number, email: string, firstName: string, lastName: string) {
this.id = id;
this.email = email;
this.firstName = firstName;
this.lastName = lastName;
}
}
@@ -19,21 +19,79 @@ import { it, describe, inject, beforeEach, beforeEachProviders } from '@angular/
import { ActivitiTaskListService } from './activiti-tasklist.service';
import { AlfrescoSettingsService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { HTTP_PROVIDERS } from '@angular/http';
import { TaskDetailsModel } from '../models/task-details.model';
import { Comment } from '../models/comment.model';
declare let AlfrescoApi: any;
declare let jasmine: any;
describe('AlfrescoUploadService', () => {
let service, options: any;
describe('ActivitiTaskListService', () => {
let service: any;
options = {
host: 'fakehost',
url: '/some/cool/url',
baseUrlPath: 'fakebasepath',
formFields: {
siteid: 'fakeSite',
containerid: 'fakeFolder'
}
let fakeFilters = {
size: 2, total: 2, start: 0,
data: [
{
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
filter: {sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved'}
},
{
id: 2, name: 'FakeMyTasks', recent: false, icon: 'glyphicon-align-left',
filter: {sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee'}
}
]
};
let fakeFilter = {
page: 2, filterId: 2, appDefinitionId: null,
filter: {sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee' }
};
let fakeUser = { id: 1, email: 'fake-email@dom.com', firstName: 'firstName', lastName: 'lastName' };
let fakeTaskList = {
size: 1, total: 1, start: 0,
data: [
{
id: 1, name: 'FakeNameTask', description: null, category: null,
assignee: fakeUser,
created: '2016-07-15T11:19:17.440+0000'
}
]
};
let fakeErrorTaskList = {
error: 'wrong request'
};
let fakeTaskDetails = {id: '999', name: 'fake-task-name', formKey: '99', assignee: fakeUser };
let fakeTasksComment = {
size: 2, total: 2, start: 0,
data: [
{
id: 1, message: 'fake-message-1', created: '', createdBy: fakeUser
},
{
id: 2, message: 'fake-message-2', created: '', createdBy: fakeUser
}
]
};
let fakeTasksChecklist = {
size: 1, total: 1, start: 0,
data: [
{
id: 1, name: 'FakeCheckTask1', description: null, category: null,
assignee: fakeUser,
created: '2016-07-15T11:19:17.440+0000'
},
{
id: 2, name: 'FakeCheckTask2', description: null, category: null,
assignee: fakeUser,
created: '2016-07-15T11:19:17.440+0000'
}
]
};
beforeEachProviders(() => {
@@ -55,69 +113,37 @@ describe('AlfrescoUploadService', () => {
});
it('should return the task list filters', (done) => {
let fakeFilter = {
size: 2, total: 2, start: 0,
data: [
{
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
filter: {sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved'}
},
{
id: 2, name: 'FakeMyTasks', recent: false, icon: 'glyphicon-align-left',
filter: {sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee'}
}
]
};
let filters = service.getTaskListFilters();
filters.subscribe(res => {
expect(res).toBeDefined();
expect(res.size).toEqual(2);
expect(res.total).toEqual(2);
expect(res.data.length).toEqual(2);
expect(res.data[0].name).toEqual('FakeInvolvedTasks');
expect(res.data[1].name).toEqual('FakeMyTasks');
done();
});
service.getTaskListFilters().subscribe(
(res) => {
expect(res).toBeDefined();
expect(res.length).toEqual(2);
expect(res[0].name).toEqual('FakeInvolvedTasks');
expect(res[1].name).toEqual('FakeMyTasks');
done();
}
);
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeFilter)
responseText: JSON.stringify(fakeFilters)
});
});
it('should return the task list filtered', (done) => {
let fakeTaskList = {
size: 1, total: 1, start: 0,
data: [
{
id: 1, name: 'FakeNameTask', description: null, category: null,
assignee: {
id: 1,
firstName: null,
lastName: 'Fake Admin',
email: 'fake-admin'
},
created: '2016-07-15T11:19:17.440+0000'
}
]
};
let fakeFilter = {
page: 2, filterId: 2, appDefinitionId: null,
filter: {sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee'}
};
let taskList = service.getTasks(fakeFilter);
taskList.subscribe(res => {
expect(res).toBeDefined();
expect(res.size).toEqual(1);
expect(res.total).toEqual(1);
expect(res.data.length).toEqual(1);
expect(res.data[0].name).toEqual('FakeNameTask');
done();
});
service.getTasks(fakeFilter).subscribe(
res => {
expect(res).toBeDefined();
expect(res.size).toEqual(1);
expect(res.total).toEqual(1);
expect(res.data.length).toEqual(1);
expect(res.data[0].name).toEqual('FakeNameTask');
expect(res.data[0].assignee.email).toEqual('fake-email@dom.com');
expect(res.data[0].assignee.firstName).toEqual('firstName');
expect(res.data[0].assignee.lastName).toEqual('lastName');
done();
}
);
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
@@ -126,36 +152,158 @@ describe('AlfrescoUploadService', () => {
});
});
it('should throw an exception when the response is wrong', (done) => {
let fakeTaskList = {
error: 'wrong request'
};
let fakeFilter = {
page: 2, filterId: 2, appDefinitionId: null,
wrongfilter: {sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee'}
};
let fakePromise = new Promise(function (resolve, reject) {
reject(fakeTaskList);
});
spyOn(service, 'callApiTasksFiltered').and.returnValue(fakePromise);
let taskList = service.getTasks(fakeFilter);
service.getTasks(fakeFilter).subscribe((res) => {
let tasks = res.data;
service.loadTasks(tasks);
});
taskList.subscribe(
it('should throw an exception when the response is wrong', () => {
service.getTasks(fakeFilter).subscribe(
(res) => {
},
(err: any) => {
expect(err).toBeDefined();
expect(err.error).toEqual('wrong request');
done();
});
expect(err.json().error).toEqual('wrong request');
}
);
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 404,
contentType: 'application/json',
responseText: JSON.stringify(fakeErrorTaskList)
});
});
it('should return the task details ', (done) => {
service.getTaskDetails(999).subscribe(
(res: TaskDetailsModel) => {
expect(res).toBeDefined();
expect(res.id).toEqual('999');
expect(res.name).toEqual('fake-task-name');
expect(res.formKey).toEqual('99');
expect(res.assignee).toBeDefined();
expect(res.assignee.email).toEqual('fake-email@dom.com');
expect(res.assignee.firstName).toEqual('firstName');
expect(res.assignee.lastName).toEqual('lastName');
done();
}
);
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeTaskDetails)
});
});
it('should return the tasks comments ', (done) => {
service.getTaskComments(999).subscribe(
(res: Comment[]) => {
expect(res).toBeDefined();
expect(res.length).toEqual(2);
expect(res[0].message).toEqual('fake-message-1');
expect(res[1].message).toEqual('fake-message-2');
done();
}
);
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeTasksComment)
});
});
it('should return the tasks checklists ', (done) => {
service.getTaskChecklist(999).subscribe(
(res: TaskDetailsModel[]) => {
expect(res).toBeDefined();
expect(res.length).toEqual(2);
expect(res[0].name).toEqual('FakeCheckTask1');
expect(res[0].assignee.email).toEqual('fake-email@dom.com');
expect(res[0].assignee.firstName).toEqual('firstName');
expect(res[0].assignee.lastName).toEqual('lastName');
expect(res[1].name).toEqual('FakeCheckTask2');
expect(res[1].assignee.email).toEqual('fake-email@dom.com');
expect(res[1].assignee.firstName).toEqual('firstName');
expect(res[0].assignee.lastName).toEqual('lastName');
done();
}
);
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeTasksChecklist)
});
});
it('should add a task ', (done) => {
let taskFake = new TaskDetailsModel({
id: '', name: 'FakeNameTask', description: null, category: null,
assignee: fakeUser,
created: ''
});
service.addTask(taskFake).subscribe(
(res: TaskDetailsModel) => {
expect(res).toBeDefined();
expect(res.id).not.toEqual('');
expect(res.name).toEqual('FakeNameTask');
expect(res.created).not.toEqual('');
done();
}
);
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify({
id: '777', name: 'FakeNameTask', description: null, category: null,
assignee: fakeUser,
created: '2016-07-15T11:19:17.440+0000'
})
});
});
it('should add a comment task ', (done) => {
service.addTaskComment(999, 'fake-comment-message').subscribe(
(res: Comment) => {
expect(res).toBeDefined();
expect(res.id).not.toEqual('');
expect(res.message).toEqual('fake-comment-message');
expect(res.created).not.toEqual('');
expect(res.createdBy.email).toEqual('fake-email@dom.com');
expect(res.createdBy.firstName).toEqual('firstName');
expect(res.createdBy.lastName).toEqual('lastName');
done();
}
);
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify({
id: '111', message: 'fake-comment-message',
createdBy: fakeUser,
created: '2016-07-15T11:19:17.440+0000'
})
});
});
it('should complete the task ', (done) => {
service.completeTask(999).subscribe(
(res: any) => {
expect(res).toBeDefined();
done();
}
);
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify({})
});
});
});
@@ -20,6 +20,11 @@ import { AlfrescoSettingsService } from 'ng2-alfresco-core';
import { Http, Headers, RequestOptions, Response } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import { FilterModel } from '../models/filter.model';
import { FilterParamsModel } from '../models/filter.model';
import { Comment } from '../models/comment.model';
import { User } from '../models/user.model';
import { TaskDetailsModel } from '../models/task-details.model';
@Injectable()
export class ActivitiTaskListService {
@@ -33,6 +38,27 @@ export class ActivitiTaskListService {
*/
getTaskListFilters(): Observable<any> {
return Observable.fromPromise(this.callApiTaskFilters())
.map(res => res.json())
.map((response: any) => {
let filters: FilterModel[] = [];
response.data.forEach((filter) => {
let filterModel = new FilterModel(filter.name, filter.recent, filter.icon,
filter.filter.name, filter.filter.state, filter.filter.assignment);
filters.push(filterModel);
});
return filters;
})
.catch(this.handleError);
}
/**
* Retrive all the tasks filtered by filterModel
* @param filter - FilterModel
* @returns {any}
*/
getTasks(filter: FilterModel): Observable<any> {
return Observable.fromPromise(this.callApiTasksFiltered(filter.filter))
.map((res: Response) => {
return res.json();
})
@@ -40,24 +66,100 @@ export class ActivitiTaskListService {
}
/**
* Retrive all the tasks created in activiti
* @returns {any}
* Retrive all the task details
* @param id - taskId
* @returns {<TaskDetailsModel>}
*/
getTasks(filter: FilterModel): Observable<any> {
let data: any = {};
data.filterId = filter.id;
data.filter = filter.filter;
data = JSON.stringify(data);
return Observable.fromPromise(this.callApiTasksFiltered(data))
.map((res: Response) => {
return res.json();
getTaskDetails(id: string): Observable<TaskDetailsModel> {
return Observable.fromPromise(this.callApiTaskDetails(id))
.map(res => res.json())
.map((details: any) => {
return new TaskDetailsModel(details);
})
.catch(this.handleError);
}
private callApiTasksFiltered(data: Object) {
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + '/rest/filter/tasks';
/**
* Retrive all the task's comments
* @param id - taskId
* @returns {<Comment[]>}
*/
getTaskComments(id: string): Observable<Comment[]> {
return Observable.fromPromise(this.callApiTaskComments(id))
.map(res => res.json())
.map((response: any) => {
let comments: Comment[] = [];
response.data.forEach((comment) => {
let user = new User(
comment.createdBy.id, comment.createdBy.email, comment.createdBy.firstName, comment.createdBy.lastName);
comments.push(new Comment(comment.id, comment.message, comment.created, user));
});
return comments;
})
.catch(this.handleError);
}
/**
* Retrive all the task's checklist
* @param id - taskId
* @returns {TaskDetailsModel}
*/
getTaskChecklist(id: string): Observable<TaskDetailsModel[]> {
return Observable.fromPromise(this.callApiTaskChecklist(id))
.map(res => res.json())
.map((response: any) => {
let checklists: TaskDetailsModel[] = [];
response.data.forEach((checklist) => {
checklists.push(new TaskDetailsModel(checklist));
});
return checklists;
})
.catch(this.handleError);
}
/**
* Add a task
* @param task - TaskDetailsModel
* @returns {TaskDetailsModel}
*/
addTask(task: TaskDetailsModel): Observable<TaskDetailsModel> {
return Observable.fromPromise(this.callApiAddTask(task))
.map(res => res.json())
.map((response: TaskDetailsModel) => {
return new TaskDetailsModel(response);
})
.catch(this.handleError);
}
/**
* Add a comment to a task
* @param id - taskId
* @param message - content of the comment
* @returns {Comment}
*/
addTaskComment(id: string, message: string): Observable<Comment> {
return Observable.fromPromise(this.callApiAddTaskComment(id, message))
.map(res => res.json())
.map((response: Comment) => {
return new Comment(response.id, response.message, response.created, response.createdBy);
})
.catch(this.handleError);
}
/**
* Make the task completed
* @param id - taskId
* @returns {TaskDetailsModel}
*/
completeTask(id: string): Observable<TaskDetailsModel> {
return Observable.fromPromise(this.callApiCompleteTask(id))
.map(res => res.json())
.catch(this.handleError);
}
private callApiTasksFiltered(filter: FilterParamsModel) {
let data = JSON.stringify(filter);
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + `/api/enterprise/tasks/query`;
let headers = new Headers({
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
@@ -69,7 +171,7 @@ export class ActivitiTaskListService {
}
private callApiTaskFilters() {
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + '/rest/filters/tasks';
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + `/api/enterprise/filters/tasks`;
let headers = new Headers({
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
@@ -80,6 +182,80 @@ export class ActivitiTaskListService {
.get(url, options).toPromise();
}
private callApiTaskDetails(id: string) {
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + `/api/enterprise/tasks/${id}`;
let headers = new Headers({
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
});
let options = new RequestOptions({headers: headers});
return this.http
.get(url, options).toPromise();
}
private callApiTaskComments(id: string) {
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + `/api/enterprise/tasks/${id}/comments`;
let headers = new Headers({
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
});
let options = new RequestOptions({headers: headers});
return this.http
.get(url, options).toPromise();
}
private callApiAddTaskComment(id: string, message: string) {
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + `/api/enterprise/tasks/${id}/comments`;
let headers = new Headers({
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
});
let body = JSON.stringify({message: message});
let options = new RequestOptions({headers: headers});
return this.http
.post(url, body, options).toPromise();
}
private callApiAddTask(task: TaskDetailsModel) {
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + `/api/enterprise/tasks/${task.parentTaskId}/checklist`;
let headers = new Headers({
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
});
let body = JSON.stringify(task);
let options = new RequestOptions({headers: headers});
return this.http
.post(url, body, options).toPromise();
}
private callApiTaskChecklist(id: string) {
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + `/api/enterprise/tasks/${id}/checklist`;
let headers = new Headers({
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
});
let options = new RequestOptions({headers: headers});
return this.http
.get(url, options).toPromise();
}
private callApiCompleteTask(id: string) {
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + `/api/enterprise/tasks/${id}/action/complete`;
let headers = new Headers({
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
});
let options = new RequestOptions({headers: headers});
return this.http
.put(url, options).toPromise();
}
/**
* The method write the error in the console browser
@@ -75,7 +75,7 @@ export class AlfrescoAuthenticationBPM extends AlfrescoAuthenticationBase implem
}
private apiActivitiLogin(username: string, password: string) {
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + '/authentication';
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + '/app/authentication';
let headers = new Headers({
'Content-Type': 'application/x-www-form-urlencoded'
});
@@ -91,7 +91,7 @@ export class AlfrescoAuthenticationBPM extends AlfrescoAuthenticationBase implem
}
private apiActivitiLogout() {
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + '/logout';
let url = this.alfrescoSettingsService.getBPMApiBaseUrl() + '/app/logout';
return this.http.get(url).toPromise();
}
@@ -27,7 +27,6 @@ export class AlfrescoSettingsService {
static DEFAULT_BPM_CONTEXT_PATH: string = '/activiti-app';
static DEFAULT_ECM_BASE_API_PATH: string = '/api/-default-/public/alfresco/versions/1';
static DEFAULT_BPM_BASE_API_PATH: string = '/app';
private _ecmHost: string = AlfrescoSettingsService.DEFAULT_ECM_ADDRESS;
private _bpmHost: string = AlfrescoSettingsService.DEFAULT_BPM_ADDRESS;
@@ -36,7 +35,6 @@ export class AlfrescoSettingsService {
private _bpmContextPath = AlfrescoSettingsService.DEFAULT_BPM_CONTEXT_PATH;
private _apiECMBasePath: string = AlfrescoSettingsService.DEFAULT_ECM_BASE_API_PATH;
private _apiBPMBasePath: string = AlfrescoSettingsService.DEFAULT_BPM_BASE_API_PATH;
private providers: string[] = ['ECM', 'BPM'];
@@ -57,7 +55,7 @@ export class AlfrescoSettingsService {
}
public getBPMApiBaseUrl(): string {
return this._bpmHost + this._bpmContextPath + this._apiBPMBasePath;
return this._bpmHost + this._bpmContextPath;
}
public getECMApiBaseUrl(): string {