diff --git a/demo-shell-ng2/app/components/activiti/activiti-demo.component.html b/demo-shell-ng2/app/components/activiti/activiti-demo.component.html index 766434a190..41bfb72f31 100644 --- a/demo-shell-ng2/app/components/activiti/activiti-demo.component.html +++ b/demo-shell-ng2/app/components/activiti/activiti-demo.component.html @@ -13,12 +13,12 @@
Task Filters - +
Task List - +
Task Details @@ -33,12 +33,16 @@
Process Filters +
Process List +
Process Details +
diff --git a/demo-shell-ng2/app/components/activiti/activiti-demo.component.ts b/demo-shell-ng2/app/components/activiti/activiti-demo.component.ts index 9775ac02b8..95ed87e8dd 100644 --- a/demo-shell-ng2/app/components/activiti/activiti-demo.component.ts +++ b/demo-shell-ng2/app/components/activiti/activiti-demo.component.ts @@ -17,6 +17,7 @@ import { Component, AfterViewChecked, ViewChild } from '@angular/core'; import { ALFRESCO_TASKLIST_DIRECTIVES } from 'ng2-activiti-tasklist'; +import { ACTIVITI_PROCESSLIST_DIRECTIVES } from 'ng2-activiti-processlist'; import { ActivitiForm } from 'ng2-activiti-form'; declare let __moduleName: string; @@ -27,7 +28,7 @@ declare var componentHandler; selector: 'activiti-demo', templateUrl: './activiti-demo.component.html', styleUrls: ['./activiti-demo.component.css'], - directives: [ALFRESCO_TASKLIST_DIRECTIVES, ActivitiForm] + directives: [ALFRESCO_TASKLIST_DIRECTIVES, ACTIVITI_PROCESSLIST_DIRECTIVES, ActivitiForm] }) export class ActivitiDemoComponent implements AfterViewChecked { @@ -39,11 +40,20 @@ export class ActivitiDemoComponent implements AfterViewChecked { @ViewChild('activititasklist') activititasklist: any; - currentTaskId: string; + @ViewChild('activitiprocesslist') + activitiprocesslist: any; - schemaColumn: any [] = []; + @ViewChild('activitiprocessdetails') + activitiprocessdetails: any; + + currentTaskId: string; + currentProcessInstanceId: string; + + taskSchemaColumns: any [] = []; + processSchemaColumns: any [] = []; taskFilter: any; + processFilter: any; setChoice($event) { this.currentChoice = $event.target.value; @@ -58,23 +68,44 @@ export class ActivitiDemoComponent implements AfterViewChecked { } constructor() { - console.log('Activiti demo component'); - this.schemaColumn = [ + this.taskSchemaColumns = [ {type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true} // {type: 'text', key: 'created', title: 'Created', sortable: true} ]; + this.processSchemaColumns = [ + {type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true} + ]; } - onFilterClick(event: any) { + onTaskFilterClick(event: any) { this.taskFilter = event; this.activititasklist.load(this.taskFilter); } - onRowClick(taskId) { + onProcessFilterClick(event: any) { + this.processFilter = event.filter; + this.activitiprocesslist.load(this.processFilter); + } + + onTaskRowClick(taskId) { this.currentTaskId = taskId; this.activitidetails.loadDetails(this.currentTaskId); } + onProcessRowClick(processInstanceId) { + this.currentProcessInstanceId = processInstanceId; + this.activitiprocessdetails.load(this.currentProcessInstanceId); + } + + processCancelled(data: any) { + this.currentProcessInstanceId = null; + this.activitiprocesslist.reload(); + } + + taskFormCompleted(data: any) { + this.activitiprocesslist.reload(); + } + ngAfterViewChecked() { // workaround for MDL issues with dynamic components if (componentHandler) { diff --git a/demo-shell-ng2/systemjs.config.js b/demo-shell-ng2/systemjs.config.js index 70c4466d67..782acb4d85 100644 --- a/demo-shell-ng2/systemjs.config.js +++ b/demo-shell-ng2/systemjs.config.js @@ -20,6 +20,7 @@ 'ng2-activiti-form': 'node_modules/ng2-activiti-form/dist', 'ng2-alfresco-viewer': 'node_modules/ng2-alfresco-viewer/dist', 'ng2-alfresco-webscript': 'node_modules/ng2-alfresco-webscript/dist', + 'ng2-activiti-processlist': 'node_modules/ng2-activiti-processlist/dist', 'ng2-activiti-tasklist': 'node_modules/ng2-activiti-tasklist/dist' }; // packages tells the System loader how to load when no filename and/or no extension @@ -38,6 +39,7 @@ 'ng2-alfresco-upload': { main: 'index.js', defaultExtension: 'js'}, 'ng2-alfresco-viewer': { main: 'index.js', defaultExtension: 'js'}, 'ng2-activiti-form': { main: 'index.js', defaultExtension: 'js'}, + 'ng2-activiti-processlist': { main: 'index.js', defaultExtension: 'js'}, 'ng2-activiti-tasklist': { main: 'index.js', defaultExtension: 'js'}, 'ng2-alfresco-webscript': { main: 'index.js', defaultExtension: 'js'} }; diff --git a/ng2-components/ng2-activiti-processlist/data/processlist-datatable-adapter.ts b/ng2-components/ng2-activiti-processlist/data/processlist-datatable-adapter.ts new file mode 100644 index 0000000000..b3e39360f4 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/data/processlist-datatable-adapter.ts @@ -0,0 +1,123 @@ +/*! + * @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 { DatePipe } from '@angular/common'; +import { + DataTableAdapter, ObjectDataTableAdapter, ObjectDataColumn, + DataRow, DataColumn, DataSorting +} from 'ng2-alfresco-datatable'; + +export class ProcessListDataTableAdapter extends ObjectDataTableAdapter implements DataTableAdapter { + + ERR_ROW_NOT_FOUND: string = 'Row not found'; + ERR_COL_NOT_FOUND: string = 'Column not found'; + + DEFAULT_DATE_FORMAT: string = 'medium'; + + private sorting: DataSorting; + private rows: DataRow[]; + private columns: DataColumn[]; + + constructor(rows: any, schema: DataColumn[]) { + super(rows, schema); + this.rows = rows; + this.columns = schema || []; + } + + getRows(): Array { + return this.rows; + } + + // TODO: disable this api + setRows(rows: Array) { + this.rows = rows || []; + this.sort(); + } + + getColumns(): Array { + return this.columns; + } + + setColumns(columns: Array) { + this.columns = columns || []; + } + + getValue(row: DataRow, col: DataColumn): any { + if (!row) { + throw new Error(this.ERR_ROW_NOT_FOUND); + } + if (!col) { + throw new Error(this.ERR_COL_NOT_FOUND); + } + let value = row.getValue(col.key); + + if (col.type === 'date') { + let datePipe = new DatePipe(); + let format = ((col)).format || this.DEFAULT_DATE_FORMAT; + try { + return datePipe.transform(value, format); + } catch (err) { + console.error(`Error parsing date ${value} to format ${format}`); + } + } + + return value; + } + + getSorting(): DataSorting { + return this.sorting; + } + + setSorting(sorting: DataSorting): void { + this.sorting = sorting; + + if (sorting && sorting.key && this.rows && this.rows.length > 0) { + this.rows.sort((a: DataRow, b: DataRow) => { + let left = a.getValue(sorting.key); + if (left) { + left = (left instanceof Date) ? left.valueOf().toString() : left.toString(); + } else { + left = ''; + } + + let right = b.getValue(sorting.key); + if (right) { + right = (right instanceof Date) ? right.valueOf().toString() : right.toString(); + } else { + right = ''; + } + + return sorting.direction === 'asc' + ? left.localeCompare(right) + : right.localeCompare(left); + }); + } + } + + sort(key?: string, direction?: string): void { + let sorting = this.sorting || new DataSorting(); + if (key) { + sorting.key = key; + sorting.direction = direction || 'asc'; + } + this.setSorting(sorting); + } +} + +export class ActivitiDataColumn extends ObjectDataColumn { + format: string; +} diff --git a/ng2-components/ng2-activiti-processlist/demo/src/main.ts b/ng2-components/ng2-activiti-processlist/demo/src/main.ts index 36900923c0..9d3c4df947 100644 --- a/ng2-components/ng2-activiti-processlist/demo/src/main.ts +++ b/ng2-components/ng2-activiti-processlist/demo/src/main.ts @@ -44,7 +44,7 @@ import {

- +
`, providers: [ACTIVITI_PROCESSLIST_PROVIDERS], directives: [ACTIVITI_PROCESSLIST_DIRECTIVES] diff --git a/ng2-components/ng2-activiti-processlist/index.ts b/ng2-components/ng2-activiti-processlist/index.ts index b1f8081c26..34bd934992 100644 --- a/ng2-components/ng2-activiti-processlist/index.ts +++ b/ng2-components/ng2-activiti-processlist/index.ts @@ -15,17 +15,30 @@ * limitations under the License. */ -import { ActivitiProcesslistComponent } from './src/components/activiti-processlist.component'; +import { ActivitiProcessInstanceListComponent } from './src/components/activiti-processlist.component'; +import { ActivitiProcessFilters } from './src/components/activiti-filters.component'; +import { ActivitiProcessInstanceHeader } from './src/components/activiti-process-instance-header.component'; +import { ActivitiProcessInstanceTasks } from './src/components/activiti-process-instance-tasks.component'; +import { ActivitiComments } from './src/components/activiti-comments.component'; +import { ActivitiProcessInstanceDetails } from './src/components/activiti-process-instance-details.component'; +import { ActivitiStartProcessButton } from './src/components/activiti-start-process.component'; import { ActivitiProcessService } from './src/services/activiti-process.service'; // components export * from './src/components/activiti-processlist.component'; +export * from './src/components/activiti-process-instance-details.component'; // services export * from './src/services/activiti-process.service'; export const ACTIVITI_PROCESSLIST_DIRECTIVES: [any] = [ - ActivitiProcesslistComponent + ActivitiProcessInstanceListComponent, + ActivitiProcessFilters, + ActivitiProcessInstanceDetails, + ActivitiProcessInstanceHeader, + ActivitiProcessInstanceTasks, + ActivitiComments, + ActivitiStartProcessButton ]; export const ACTIVITI_PROCESSLIST_PROVIDERS: [any] = [ diff --git a/ng2-components/ng2-activiti-processlist/karma.conf.js b/ng2-components/ng2-activiti-processlist/karma.conf.js index f9a39b76a0..1a3d76b9db 100644 --- a/ng2-components/ng2-activiti-processlist/karma.conf.js +++ b/ng2-components/ng2-activiti-processlist/karma.conf.js @@ -20,6 +20,9 @@ module.exports = function (config) { {pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.js', included: false, served: true, watched: false}, {pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.html', included: false, served: true, watched: false}, {pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.css', included: false, served: true, watched: false}, + {pattern: 'node_modules/ng2-activiti-tasklist/dist/**/*.js', included: false, served: true, watched: false}, + {pattern: 'node_modules/ng2-activiti-tasklist/dist/**/*.html', included: false, served: true, watched: false}, + {pattern: 'node_modules/ng2-activiti-tasklist/dist/**/*.css', included: false, served: true, watched: false}, {pattern: 'node_modules/ng2-translate/**/*.js', included: false, served: true, watched: false}, {pattern: 'node_modules/alfresco-js-api/dist/alfresco-js-api.js', included: true, watched: false}, diff --git a/ng2-components/ng2-activiti-processlist/package.json b/ng2-components/ng2-activiti-processlist/package.json index 27fe458691..01307a17a0 100644 --- a/ng2-components/ng2-activiti-processlist/package.json +++ b/ng2-components/ng2-activiti-processlist/package.json @@ -64,7 +64,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-tasklist": "0.2.0" }, "devDependencies": { "angular-cli": "1.0.0-beta.9", diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-comments.component.css b/ng2-components/ng2-activiti-processlist/src/components/activiti-comments.component.css new file mode 100644 index 0000000000..ff0f8dd865 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-comments.component.css @@ -0,0 +1,7 @@ +:host { + width: 100%; +} + +.activiti-label { + font-weight: bolder; +} diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-comments.component.html b/ng2-components/ng2-activiti-processlist/src/components/activiti-comments.component.html new file mode 100644 index 0000000000..169719612e --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-comments.component.html @@ -0,0 +1,35 @@ +{{ 'DETAILS.LABELS.COMMENTS' |translate }} +
add
+
+ Add a comment +
+ + +
+ {{ 'DETAILS.COMMENTS.NONE' | translate }} +
+ + + +

New comment

+
+
+ + +
+
+
+ + +
+
diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-comments.component.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-comments.component.ts new file mode 100644 index 0000000000..95f1219c92 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-comments.component.ts @@ -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 { ActivitiProcessService } from './../services/activiti-process.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: [ActivitiProcessService], + pipes: [ AlfrescoPipeTranslate ] + +}) +export class ActivitiComments implements OnInit { + + @Input() + processId: string; + + @ViewChild('dialog') + dialog: any; + + comments: Comment [] = []; + + private commentObserver: Observer; + comment$: Observable; + + message: string; + + /** + * Constructor + * @param auth + * @param translate + */ + constructor(private auth: AlfrescoAuthenticationService, + private translate: AlfrescoTranslationService, + private activitiProcess: ActivitiProcessService) { + + if (translate) { + translate.addTranslationFolder('node_modules/ng2-activiti-processlist/src'); + } + + this.comment$ = new Observable(observer => this.commentObserver = observer).share(); + + } + + ngOnInit() { + this.comment$.subscribe((comment: Comment) => { + this.comments.push(comment); + }); + + if (this.processId) { + this.load(this.processId); + } + } + + public load(taskId: string) { + this.comments = []; + if (this.processId) { + this.activitiProcess.getProcessInstanceComments(this.processId).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.activitiProcess.addProcessInstanceComment(this.processId, 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(); + } + } +} diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.css b/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.css new file mode 100644 index 0000000000..6b7e0a7a66 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.css @@ -0,0 +1,3 @@ +.mdl-list__item { + cursor: pointer; +} diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.html b/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.html new file mode 100644 index 0000000000..580798c6a3 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.html @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.ts new file mode 100644 index 0000000000..9032d2f173 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-filters.component.ts @@ -0,0 +1,131 @@ +/*! + * @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, Input } from '@angular/core'; +import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core'; +import { ActivitiProcessService } from './../services/activiti-process.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-process-filters', + moduleId: __moduleName, + templateUrl: './activiti-filters.component.html', + styleUrls: ['activiti-filters.component.css'], + providers: [ActivitiProcessService], + pipes: [AlfrescoPipeTranslate] + +}) +export class ActivitiProcessFilters implements OnInit { + + @Output() + filterClick: EventEmitter = new EventEmitter(); + + @Output() + onSuccess: EventEmitter = new EventEmitter(); + + @Output() + onError: EventEmitter = new EventEmitter(); + + @Input() + appId: string; + + @Input() + appName: string; + + private filterObserver: Observer; + filter$: Observable; + + currentFilter: FilterModel; + + filters: FilterModel [] = []; + + /** + * Constructor + * @param auth + * @param translate + * @param activiti + */ + constructor(private auth: AlfrescoAuthenticationService, + private translate: AlfrescoTranslationService, + public activiti: ActivitiProcessService) { + this.filter$ = new Observable(observer => this.filterObserver = observer).share(); + + if (translate) { + translate.addTranslationFolder('node_modules/ng2-activiti-processlist/src'); + } + } + + 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() { + if (this.appName) { + this.filterByAppName(); + } else { + this.filterByAppId(this.appId); + } + } + + private filterByAppId(appId) { + this.activiti.getProcessFilters(appId).subscribe( + (res: FilterModel[]) => { + res.forEach((filter) => { + this.filterObserver.next(filter); + }); + this.onSuccess.emit(res); + }, + (err) => { + console.log(err); + this.onError.emit(err); + } + ); + } + + private filterByAppName() { + this.activiti.getDeployedApplications(this.appName).subscribe( + application => { + this.filterByAppId(application.id); + }, + (err) => { + console.log(err); + this.onError.emit(err); + }); + } + + /** + * Pass the selected filter as next + * @param filter + */ + public selectFilter(filter: FilterModel) { + this.currentFilter = filter; + this.filterClick.emit(filter); + } +} diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.css b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.css new file mode 100644 index 0000000000..07eaf92d80 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.css @@ -0,0 +1,3 @@ +:host { + width: 100%; +} \ No newline at end of file diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.html b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.html new file mode 100644 index 0000000000..741dcabc47 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.html @@ -0,0 +1,13 @@ +
{{ 'DETAILS.MESSAGES.NONE'|translate }}
+
+

{{processInstanceDetails.name}}

+ +
+
+ +
+
+ +
+
+
diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.ts new file mode 100644 index 0000000000..bd50c40303 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.ts @@ -0,0 +1,109 @@ +/*! + * @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, ViewChild, Output, EventEmitter } from '@angular/core'; +import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core'; +import { ActivitiProcessService } from './../services/activiti-process.service'; +import { ActivitiProcessInstanceHeader } from './activiti-process-instance-header.component'; +import { ActivitiProcessInstanceTasks } from './activiti-process-instance-tasks.component'; +import { ActivitiComments } from './activiti-comments.component'; +import { ProcessInstance } from '../models/process-instance'; + + +declare let componentHandler: any; +declare let __moduleName: string; + +@Component({ + selector: 'activiti-process-instance-details', + moduleId: __moduleName, + templateUrl: './activiti-process-instance-details.component.html', + styleUrls: ['./activiti-process-instance-details.component.css'], + providers: [ActivitiProcessService], + directives: [ActivitiProcessInstanceHeader, ActivitiComments, ActivitiProcessInstanceTasks], + pipes: [AlfrescoPipeTranslate] + +}) +export class ActivitiProcessInstanceDetails { + + @Input() + processInstanceId: string; + + @ViewChild('activitiprocessheader') + processInstanceHeader: ActivitiProcessInstanceHeader; + + @ViewChild('activitiprocesstasks') + tasksList: ActivitiProcessInstanceTasks; + + @ViewChild('activitiprocesscomments') + commentsList: ActivitiComments; + + @Input() + showTitle: boolean = true; + + @Input() + showRefreshButton: boolean = true; + + @Output() + processCancelledEmitter = new EventEmitter(); + + @Output() + taskFormCompletedEmitter = new EventEmitter(); + + processInstanceDetails: ProcessInstance; + + /** + * Constructor + * @param auth + * @param translate + * @param activitiProcess + */ + constructor(private auth: AlfrescoAuthenticationService, + private translate: AlfrescoTranslationService, + private activitiProcess: ActivitiProcessService) { + + if (translate) { + translate.addTranslationFolder('node_modules/ng2-activiti-processlist/src'); + } + } + + load(processId: string) { + if (processId) { + this.activitiProcess.getProcess(processId).subscribe( + (res: ProcessInstance) => { + this.processInstanceDetails = res; + if (this.processInstanceDetails) { + if (this.commentsList) { + this.commentsList.load(this.processInstanceDetails.id); + } + if (this.tasksList) { + this.tasksList.load(this.processInstanceDetails.id); + } + } + console.log('Loaded process instance', this.processInstanceDetails); + } + ); + } + } + + processCancelled(data: any) { + this.processCancelledEmitter.emit(data); + } + + taskFormCompleted(data: any) { + this.taskFormCompletedEmitter.emit(data); + } +} diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-header.component.css b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-header.component.css new file mode 100644 index 0000000000..20fbab0626 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-header.component.css @@ -0,0 +1,7 @@ +:host { + width: 100%; +} + +.activiti-label { + font-weight: bolder; +} \ No newline at end of file diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-header.component.html b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-header.component.html new file mode 100644 index 0000000000..8e7a434a7f --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-header.component.html @@ -0,0 +1,15 @@ +
+
+
+ {{ 'DETAILS.LABELS.STARTED_BY' | translate }}: + {{getStartedByFullName()}} +
+
+ {{ 'DETAILS.LABELS.STARTED' | translate }}: + {{getStartedDate() | date:'medium'}} +
+
+ +
+
+
diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-header.component.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-header.component.ts new file mode 100644 index 0000000000..ed4f354cd4 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-header.component.ts @@ -0,0 +1,74 @@ +/*! + * @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, Output, EventEmitter } from '@angular/core'; +import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core'; +import { ProcessInstance } from '../models/process-instance'; +import { ActivitiProcessService } from './../services/activiti-process.service'; + +declare let componentHandler: any; +declare let __moduleName: string; + +@Component({ + selector: 'activiti-process-instance-header', + moduleId: __moduleName, + templateUrl: './activiti-process-instance-header.component.html', + styleUrls: ['./activiti-process-instance-header.component.css'], + pipes: [ AlfrescoPipeTranslate ] + +}) +export class ActivitiProcessInstanceHeader { + + @Input() + processInstance: ProcessInstance; + + @Output() + processCancelled = new EventEmitter(); + + /** + * Constructor + * @param auth + * @param translate + * @param activitiProcess + */ + constructor(private auth: AlfrescoAuthenticationService, + private translate: AlfrescoTranslationService, + private activitiProcess: ActivitiProcessService) { + + if (translate) { + translate.addTranslationFolder('node_modules/ng2-activiti-tasklist/src'); + } + } + + getStartedByFullName() { + if (this.processInstance && this.processInstance.startedBy) { + return (this.processInstance.startedBy.firstName && this.processInstance.startedBy.firstName !== 'null' + ? this.processInstance.startedBy.firstName + ' ' : '') + + this.processInstance.startedBy.lastName; + } + return ''; + } + + getStartedDate() { + return this.processInstance ? new Date(this.processInstance.started) : null; + } + + cancelProcess() { + console.log('Cancel process', this.processInstance); + this.processCancelled.emit(this.activitiProcess.cancelProcess(this.processInstance.id)); + } +} diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-tasks.component.css b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-tasks.component.css new file mode 100644 index 0000000000..ca7a24db2c --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-tasks.component.css @@ -0,0 +1,19 @@ +:host { + width: 100%; +} + +.activiti-label { + font-weight: bolder; +} + +.material-icons:hover { + color: rgb(255, 152, 0); +} + +.task-details-dialog { + width: 600px; +} + +.process-tasks-refresh { + float: right; +} diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-tasks.component.html b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-tasks.component.html new file mode 100644 index 0000000000..b4ab3f9ee5 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-tasks.component.html @@ -0,0 +1,52 @@ +
+ +
+ +{{ 'DETAILS.LABELS.TASKS_ACTIVE'|translate }} + + +
+ {{ 'DETAILS.TASKS.NO_ACTIVE' | translate }} +
+ +{{ 'DETAILS.LABELS.TASKS_COMPLETED'|translate }} + + +
+ {{ 'DETAILS.TASKS.NO_COMPLETED' | translate }} +
+ + +

Task details

+
+ +
+
+ +
+
diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-tasks.component.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-tasks.component.ts new file mode 100644 index 0000000000..612e9674cf --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-tasks.component.ts @@ -0,0 +1,183 @@ +/*! + * @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, Output, EventEmitter } from '@angular/core'; +import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core'; +import { ActivitiProcessService } from './../services/activiti-process.service'; +import { TaskDetailsModel } from '../models/task-details.model'; +import { ALFRESCO_TASKLIST_DIRECTIVES } from 'ng2-activiti-tasklist'; +import { Observer } from 'rxjs/Observer'; +import { Observable } from 'rxjs/Observable'; + +declare let componentHandler: any; +declare let __moduleName: string; + +@Component({ + selector: 'activiti-process-instance-tasks', + moduleId: __moduleName, + templateUrl: './activiti-process-instance-tasks.component.html', + styleUrls: ['./activiti-process-instance-tasks.component.css'], + providers: [ActivitiProcessService], + directives: [ ALFRESCO_TASKLIST_DIRECTIVES ], + pipes: [ AlfrescoPipeTranslate ] + +}) +export class ActivitiProcessInstanceTasks implements OnInit { + + @Input() + processId: string; + + @Input() + showRefreshButton: boolean = true; + + @Output() + taskFormCompletedEmitter = new EventEmitter(); + + activeTasks: TaskDetailsModel[] = []; + completedTasks: TaskDetailsModel[] = []; + + private taskObserver: Observer; + private completedTaskObserver: Observer; + + task$: Observable; + completedTask$: Observable; + + message: string; + + selectedTaskId: string; + + @ViewChild('dialog') + dialog: any; + + @ViewChild('taskdetails') + taskdetails: any; + + /** + * Constructor + * @param auth + * @param translate + * @param activitiProcess + */ + constructor(private auth: AlfrescoAuthenticationService, + private translate: AlfrescoTranslationService, + private activitiProcess: ActivitiProcessService) { + + if (translate) { + translate.addTranslationFolder('node_modules/ng2-activiti-processlist/src'); + } + + this.task$ = new Observable(observer => this.taskObserver = observer).share(); + this.completedTask$ = new Observable(observer => this.completedTaskObserver = observer).share(); + + } + + ngOnInit() { + this.task$.subscribe((task: TaskDetailsModel) => { + this.activeTasks.push(task); + }); + this.completedTask$.subscribe((task: TaskDetailsModel) => { + this.completedTasks.push(task); + }); + + if (this.processId) { + this.load(this.processId); + } + } + + public load(processId: string) { + this.loadActive(processId); + this.loadCompleted(processId); + } + + public loadActive(processId: string) { + this.activeTasks = []; + if (processId) { + this.activitiProcess.getProcessTasks(processId, null).subscribe( + (res: TaskDetailsModel[]) => { + res.forEach((task) => { + this.taskObserver.next(task); + }); + }, + (err) => { + console.log(err); + } + ); + } else { + this.activeTasks = []; + } + } + + public loadCompleted(processId: string) { + this.completedTasks = []; + if (processId) { + this.activitiProcess.getProcessTasks(processId, 'completed').subscribe( + (res: TaskDetailsModel[]) => { + res.forEach((task) => { + this.completedTaskObserver.next(task); + }); + }, + (err) => { + console.log(err); + } + ); + } else { + this.completedTasks = []; + } + } + + getUserFullName(user: any) { + if (user) { + return (user.firstName && user.firstName !== 'null' + ? user.firstName + ' ' : '') + + user.lastName; + } + return ''; + } + + public clickTask($event: any, task: TaskDetailsModel) { + console.log('selected task', task); + this.selectedTaskId = task.id; + this.taskdetails.loadDetails(task.id); + this.showDialog(); + } + + public showDialog() { + if (this.dialog) { + this.dialog.nativeElement.showModal(); + } + } + + public cancelDialog() { + this.closeDialog(); + } + + private closeDialog() { + if (this.dialog) { + this.dialog.nativeElement.close(); + } + } + + public taskFormCompleted() { + this.closeDialog(); + this.load(this.processId); + this.taskFormCompletedEmitter.emit(this.processId); + } + + public onRefreshClicked() { + this.load(this.processId); + } +} diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.html b/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.html index beedb69313..81e5da9857 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.html +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.html @@ -1,6 +1,12 @@ -

My Activiti Processes

- -

{{ 'PROCESSLIST.NONE' | translate }}

- - +
{{ 'FILTERS.MESSAGES.NONE' | translate }}
+
+
+ + +
+
+ {{ 'PROCESSLIST.NONE' | translate }} +
+
diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.spec.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.spec.ts index a6feba83bd..420a617bb0 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.spec.ts +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.spec.ts @@ -18,7 +18,7 @@ import {describe, expect, it, inject, beforeEachProviders, beforeEach} from '@angular/core/testing'; import {TestComponentBuilder} from '@angular/compiler/testing'; import {AlfrescoSettingsService, AlfrescoTranslationService, AlfrescoAuthenticationService} from 'ng2-alfresco-core'; -import {ActivitiProcesslistComponent} from '../../src/components/activiti-processlist.component'; +import {ActivitiProcessInstanceListComponent} from '../../src/components/activiti-processlist.component'; import {TranslationMock} from './../assets/translation.service.mock'; import {ActivitiProcessService} from '../services/activiti-process.service'; @@ -38,7 +38,7 @@ describe('ActivitiProcesslistComponent', () => { beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { return tcb - .createAsync(ActivitiProcesslistComponent) + .createAsync(ActivitiProcessInstanceListComponent) .then(fixture => { processlistComponentFixture = fixture; element = processlistComponentFixture.nativeElement; diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.ts index a63a7dac0b..6f22951373 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.ts +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.ts @@ -15,17 +15,17 @@ * limitations under the License. */ -import {Component, OnInit } from '@angular/core'; +import {Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import { AlfrescoPipeTranslate, AlfrescoTranslationService, CONTEXT_MENU_DIRECTIVES, CONTEXT_MENU_PROVIDERS } from 'ng2-alfresco-core'; -import { ALFRESCO_DATATABLE_DIRECTIVES, ObjectDataTableAdapter } from 'ng2-alfresco-datatable'; +import { ALFRESCO_DATATABLE_DIRECTIVES, ObjectDataTableAdapter, DataRowEvent } from 'ng2-alfresco-datatable'; import { ActivitiProcessService } from '../services/activiti-process.service'; -import { ProcessInstance } from '../models/process-instance'; +import { FilterModel } from '../models/filter.model'; declare let __moduleName: string; @Component({ moduleId: __moduleName, - selector: 'activiti-processlist', + selector: 'activiti-process-instance-list', styles: [ ` :host h1 { @@ -36,13 +36,33 @@ declare let __moduleName: string; templateUrl: './activiti-processlist.component.html', directives: [ ALFRESCO_DATATABLE_DIRECTIVES, CONTEXT_MENU_DIRECTIVES ], pipes: [ AlfrescoPipeTranslate ], - providers: [ CONTEXT_MENU_PROVIDERS ] + providers: [ CONTEXT_MENU_PROVIDERS, ActivitiProcessService ] }) -export class ActivitiProcesslistComponent implements OnInit { +export class ActivitiProcessInstanceListComponent implements OnInit { errorMessage: string; - processInstances: ProcessInstance[]; data: ObjectDataTableAdapter; + currentProcessInstanceId: string; + + @Input() + filter: FilterModel; + + @Input() + schemaColumn: any[] = [ + {type: 'text', key: 'id', title: 'Id', sortable: true}, + {type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true}, + {type: 'text', key: 'started', title: 'Started', sortable: true}, + {type: 'text', key: 'startedBy.email', title: 'Started By', sortable: true} + ]; + + @Output() + rowClick: EventEmitter = new EventEmitter(); + + @Output() + onSuccess: EventEmitter = new EventEmitter(); + + @Output() + onError: EventEmitter = new EventEmitter(); constructor (private processService: ActivitiProcessService, private translate: AlfrescoTranslationService) { if (translate !== null) { @@ -51,27 +71,77 @@ export class ActivitiProcesslistComponent implements OnInit { } ngOnInit() { - this.getProcesses(); + this.data = new ObjectDataTableAdapter( + [], + this.schemaColumn + ); + if (this.filter) { + this.load(this.filter); + } } - getProcesses() { - this.processService.getProcesses() + load(filter: FilterModel) { + this.processService.getProcessInstances(filter) .subscribe( (processInstances) => { - this.data = new ObjectDataTableAdapter( - processInstances, - [ - {type: 'text', key: 'id', title: 'Id', sortable: true}, - {type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true}, - {type: 'text', key: 'started', title: 'Started', sortable: true}, - {type: 'text', key: 'startedBy.email', title: 'Started By', sortable: true} - ] - ); + this.renderProcessInstances(processInstances); + this.onSuccess.emit(processInstances); }, - error => this.errorMessage = error); + error => { + this.errorMessage = error; + this.onError.emit(error); + }); } - onItemClick(processInstance: ProcessInstance, event: any) { - console.log(processInstance, event); + reload() { + this.load(this.filter); + } + + /** + * Render the process list + * + * @param processInstances + */ + private renderProcessInstances(processInstances: any[]) { + processInstances = this.optimizeProcessNames(processInstances); + this.data = new ObjectDataTableAdapter( + processInstances, + this.schemaColumn + ); + } + + /** + * Check if the list is empty + * @returns {ObjectDataTableAdapter|boolean} + */ + isListEmpty(): boolean { + return this.data === undefined || + (this.data && this.data.getRows() && this.data.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.currentProcessInstanceId = item.value.getValue('id'); + this.rowClick.emit(this.currentProcessInstanceId); + } + + /** + * Optimize process name field + * @param tasks + * @returns {any[]} + */ + private optimizeProcessNames(tasks: any[]) { + tasks = tasks.map(t => { + t.name = t.name || 'No name'; + if (t.name.length > 50) { + t.name = t.name.substring(0, 50) + '...'; + } + return t; + }); + return tasks; } } diff --git a/ng2-components/ng2-activiti-processlist/src/i18n/en.json b/ng2-components/ng2-activiti-processlist/src/i18n/en.json index 8706fab794..a3bbf24137 100644 --- a/ng2-components/ng2-activiti-processlist/src/i18n/en.json +++ b/ng2-components/ng2-activiti-processlist/src/i18n/en.json @@ -1,10 +1,34 @@ { "PROCESSLIST": { - "NONE": "No active processes were found", - "SUMMARY": "Found {{total}} active process instances", - "ERROR": "An error occurred while loading the processes: {{errorMessage}}", + "NONE": "No process instances were found", + "SUMMARY": "Found {{total}} process instances", + "ERROR": "An error occurred while loading the processes instances: {{errorMessage}}", "COLUMN": { "NAME": "Name" } + }, + "FILTERS": { + "MESSAGES": { + "NONE": "No process instance filter selected." + } + }, + "DETAILS": { + "LABELS": { + "STARTED_BY": "Started by", + "STARTED": "Started", + "COMMENTS": "Comments", + "TASKS_ACTIVE": "Active Tasks", + "TASKS_COMPLETED": "Completed Tasks" + }, + "MESSAGES": { + "NONE": "No process details found." + }, + "TASKS": { + "NO_ACTIVE": "No tasks are currently active", + "NO_COMPLETED": "No tasks have been completed yet" + }, + "COMMENTS": { + "NONE": "No comments." + } } } diff --git a/ng2-components/ng2-activiti-processlist/src/models/comment.model.ts b/ng2-components/ng2-activiti-processlist/src/models/comment.model.ts new file mode 100644 index 0000000000..d275e7ca1e --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/models/comment.model.ts @@ -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. + */ + +/** + * + * Comment submitted against a process + * + * @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; + } +} diff --git a/ng2-components/ng2-activiti-processlist/src/models/filter.model.ts b/ng2-components/ng2-activiti-processlist/src/models/filter.model.ts new file mode 100644 index 0000000000..2cd0c0eb42 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/models/filter.model.ts @@ -0,0 +1,60 @@ +/*! + * @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 filter. + * + * + * @returns {FilterModel} . + */ +export class FilterModel { + id: number; + name: string; + recent: boolean = false; + icon: string; + filter: FilterParamsModel; + appId: number; + + constructor(name: string, recent: boolean, icon: string, query: string, state: string, assignment: string, appDefinitionId?: string) { + this.name = name; + this.recent = recent; + this.icon = icon; + this.filter = new FilterParamsModel(query, state, assignment, appDefinitionId); + } +} + +/** + * + * This object represent the parameters of a filter. + * + * + * @returns {FilterModel} . + */ +export class FilterParamsModel { + name: string; + sort: string; + state: string; + appDefinitionId: string; + + constructor(query: string, sort: string, state: string, appDefinitionId?: string) { + this.name = query; + this.sort = sort; + this.state = state; + this.appDefinitionId = appDefinitionId; + } +} diff --git a/ng2-components/ng2-activiti-processlist/src/models/task-details.model.ts b/ng2-components/ng2-activiti-processlist/src/models/task-details.model.ts new file mode 100644 index 0000000000..5ab0361aaa --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/models/task-details.model.ts @@ -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; + } +} diff --git a/ng2-components/ng2-activiti-processlist/src/models/user.model.ts b/ng2-components/ng2-activiti-processlist/src/models/user.model.ts new file mode 100644 index 0000000000..6d21ad4e0b --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/models/user.model.ts @@ -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; + } +} diff --git a/ng2-components/ng2-activiti-processlist/src/services/activiti-process.service.ts b/ng2-components/ng2-activiti-processlist/src/services/activiti-process.service.ts index ee876a298d..751fb04252 100644 --- a/ng2-components/ng2-activiti-processlist/src/services/activiti-process.service.ts +++ b/ng2-components/ng2-activiti-processlist/src/services/activiti-process.service.ts @@ -17,6 +17,9 @@ import {AlfrescoAuthenticationService} from 'ng2-alfresco-core'; import {ProcessInstance} from '../models/process-instance'; +import {FilterModel} from '../models/filter.model'; +import {User} from '../models/user.model'; +import {Comment} from '../models/comment.model'; import {Injectable} from '@angular/core'; import {Observable} from 'rxjs/Observable'; import 'rxjs/add/operator/map'; @@ -28,6 +31,16 @@ export class ActivitiProcessService { constructor(public authService: AlfrescoAuthenticationService) { } + /** + * Retrive all the Deployed app + * @returns {Observable} + */ + getDeployedApplications(name: string): Observable { + return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.appsApi.getAppDefinitions()) + .map((response: any) => response.data.find(p => p.name === name)) + .do(data => console.log('Application: ' + JSON.stringify(data))); + } + getProcesses(): Observable { let request = {'page': 0, 'sort': 'created-desc', 'state': 'all'}; @@ -36,6 +49,99 @@ export class ActivitiProcessService { .catch(this.handleError); } + getProcessInstances(filter: FilterModel): Observable { + return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.processApi.getProcessInstances(filter)) + .map(this.extractData) + .catch(this.handleError); + } + + getProcessFilters(appId: string): Observable { + let filterOpts = appId ? { + appId: appId + } : {}; + return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.userFiltersApi.getUserProcessInstanceFilters(filterOpts)) + .map(this.extractData) + .catch(this.handleError); + } + + getProcess(id: string): Observable { + return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.processApi.getProcessInstance(id)) + .catch(this.handleError); + } + + getProcessTasks(id: string, state: string): Observable { + let taskOpts = state ? { + processInstanceId: id, + state: state + } : { + processInstanceId: id + }; + return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.taskApi.listTasks(taskOpts)) + .map(this.extractData) + .map(tasks => tasks.map((task: any) => { + task.created = new Date(task.created); + return task; + })) + .catch(this.handleError); + } + + /** + * Retrive all the process instance's comments + * @param id - process instance ID + * @returns {} + */ + getProcessInstanceComments(id: string): Observable { + return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.commentsApi.getProcessInstanceComments(id)) + .map(res => res) + .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); + } + + /** + * Add a comment to a process instance + * @param id - process instance Id + * @param message - content of the comment + * @returns {Comment} + */ + addProcessInstanceComment(id: string, message: string): Observable { + return Observable.fromPromise( + this.authService.getAlfrescoApi().activiti.commentsApi.addProcessInstanceComment({message: message}, id) + ) + .map(res => res) + .map((response: Comment) => { + return new Comment(response.id, response.message, response.created, response.createdBy); + }).catch(this.handleError); + + } + + getProcessDefinitions(appId: string) { + let opts = appId ? { + latest: true, + appId: appId + } : { + latest: true + }; + return Observable.fromPromise( + this.authService.getAlfrescoApi().activiti.processApi.getProcessDefinitions(opts) + ) + .map(this.extractData) + .catch(this.handleError); + } + + cancelProcess(processInstanceId: string) { + return Observable.fromPromise( + this.authService.getAlfrescoApi().activiti.processApi.deleteProcessInstance(processInstanceId) + ) + .catch(this.handleError); + } + private extractData(res: any) { return res.data || {}; }