mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
Add processlist component to demo shell
- Improvements to and rename list component - Add many more processlist components (filters, details, header, tasks) - Add dependency on tasklist component - Glue into demo-shell - Add Karma config but not actual tests yet Refs #492
This commit is contained in:
@@ -13,12 +13,12 @@
|
||||
<div class="mdl-grid">
|
||||
<div class="mdl-cell mdl-cell--2-col task-column mdl-shadow--2dp">
|
||||
<span>Task Filters</span>
|
||||
<activiti-filters (filterClick)="onFilterClick($event)"></activiti-filters>
|
||||
<activiti-filters (filterClick)="onTaskFilterClick($event)"></activiti-filters>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--3-col task-column mdl-shadow--2dp">
|
||||
<span>Task List</span>
|
||||
<activiti-tasklist *ngIf="isTaskListSelected()" [taskFilter]="taskFilter" [schemaColumn]="schemaColumn"
|
||||
(rowClick)="onRowClick($event)" #activititasklist></activiti-tasklist>
|
||||
<activiti-tasklist *ngIf="isTaskListSelected()" [taskFilter]="taskFilter" [schemaColumn]="taskSchemaColumns"
|
||||
(rowClick)="onTaskRowClick($event)" #activititasklist></activiti-tasklist>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--7-col task-column mdl-shadow--2dp">
|
||||
<span>Task Details</span>
|
||||
@@ -33,12 +33,16 @@
|
||||
<div class="mdl-grid">
|
||||
<div class="mdl-cell mdl-cell--2-col task-column">
|
||||
<span>Process Filters</span>
|
||||
<activiti-process-filters (filterClick)="onProcessFilterClick($event)"></activiti-process-filters>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--3-col task-column">
|
||||
<span>Process List</span>
|
||||
<activiti-process-instance-list [filter]="processFilter" [schemaColumn]="processSchemaColumns"
|
||||
(rowClick)="onProcessRowClick($event)" #activitiprocesslist></activiti-process-instance-list>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--7-col task-column">
|
||||
<span>Process Details</span>
|
||||
<activiti-process-instance-details [processInstanceId]="currentProcessInstanceId" (taskFormCompleted)="taskFormCompleted()" (processCancelled)="processCancelled()" #activitiprocessdetails></activiti-process-instance-details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -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) {
|
||||
|
@@ -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'}
|
||||
};
|
||||
|
@@ -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<DataRow> {
|
||||
return this.rows;
|
||||
}
|
||||
|
||||
// TODO: disable this api
|
||||
setRows(rows: Array<DataRow>) {
|
||||
this.rows = rows || [];
|
||||
this.sort();
|
||||
}
|
||||
|
||||
getColumns(): Array<DataColumn> {
|
||||
return this.columns;
|
||||
}
|
||||
|
||||
setColumns(columns: Array<DataColumn>) {
|
||||
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 = (<ActivitiDataColumn>(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;
|
||||
}
|
@@ -44,7 +44,7 @@ import {
|
||||
<label for="token"><b>Insert a servicePath</b></label><br>
|
||||
<input id="token" type="text" size="48" [(ngModel)]="servicePath"><br>
|
||||
<div class="container" *ngIf="authenticated">
|
||||
<activiti-processlist></activiti-processlist>
|
||||
<activiti-process-instance-list></activiti-process-instance-list>
|
||||
</div>`,
|
||||
providers: [ACTIVITI_PROCESSLIST_PROVIDERS],
|
||||
directives: [ACTIVITI_PROCESSLIST_DIRECTIVES]
|
||||
|
@@ -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] = [
|
||||
|
@@ -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},
|
||||
|
||||
|
@@ -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",
|
||||
|
@@ -0,0 +1,7 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.activiti-label {
|
||||
font-weight: bolder;
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
<span class="activiti-label mdl-badge"
|
||||
[attr.data-badge]="comments?.length">{{ '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">
|
||||
{{ '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 { 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>;
|
||||
comment$: Observable<Comment>;
|
||||
|
||||
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<Comment>(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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
.mdl-list__item {
|
||||
cursor: pointer;
|
||||
}
|
@@ -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,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<FilterModel> = new EventEmitter<FilterModel>();
|
||||
|
||||
@Output()
|
||||
onSuccess: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Output()
|
||||
onError: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Input()
|
||||
appId: string;
|
||||
|
||||
@Input()
|
||||
appName: string;
|
||||
|
||||
private filterObserver: Observer<FilterModel>;
|
||||
filter$: Observable<FilterModel>;
|
||||
|
||||
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<FilterModel>(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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
<div *ngIf="!processInstanceDetails">{{ 'DETAILS.MESSAGES.NONE'|translate }}</div>
|
||||
<div *ngIf="processInstanceDetails">
|
||||
<h2 class="mdl-card__title-text">{{processInstanceDetails.name}}</h2>
|
||||
<activiti-process-instance-header [processInstance]="processInstanceDetails" (processCancelled)="processCancelled()" #activitiprocessheader></activiti-process-instance-header>
|
||||
<div class="mdl-grid">
|
||||
<div class="mdl-cell mdl-cell--8-col">
|
||||
<activiti-process-instance-tasks [processId]="processInstanceDetails.id" (taskFormCompleted)="taskFormCompleted()" #activitiprocesstasks></activiti-process-instance-tasks>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<activiti-comments [processId]="processInstanceDetails.id" #activitiprocesscomments></activiti-comments>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.activiti-label {
|
||||
font-weight: bolder;
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
<div *ngIf="processInstance">
|
||||
<div class="mdl-grid">
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<span class="activiti-label">{{ 'DETAILS.LABELS.STARTED_BY' | translate }}</span>:
|
||||
{{getStartedByFullName()}}
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<span class="activiti-label">{{ 'DETAILS.LABELS.STARTED' | translate }}</span>:
|
||||
{{getStartedDate() | date:'medium'}}
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<button type="button" (click)="cancelProcess()" class="mdl-button">Cancel Process</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -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));
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
<div *ngIf="showRefreshButton" class="process-tasks-refresh" >
|
||||
<button (click)="onRefreshClicked()"
|
||||
class="mdl-button mdl-button--icon mdl-js-button mdl-js-ripple-effect">
|
||||
<i class="material-icons">refresh</i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<span class="activiti-label mdl-badge"
|
||||
[attr.data-badge]="activeTasks?.length">{{ 'DETAILS.LABELS.TASKS_ACTIVE'|translate }}</span>
|
||||
|
||||
<div class="menu-container" *ngIf="activeTasks?.length > 0">
|
||||
<ul class='mdl-list'>
|
||||
<li class="mdl-list__item mdl-list__item--two-line" *ngFor="let task of activeTasks">
|
||||
<span class="mdl-list__item-primary-content" (click)="clickTask($event, task)">
|
||||
<i class="material-icons mdl-list__item-icon">assignment</i>
|
||||
<span>{{task.name}}</span>
|
||||
<span class="mdl-list__item-sub-title">Assigned to {{getUserFullName(task.assignee)}}, created {{task.created | date:'mediumDate'}}</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div *ngIf="activeTasks?.length === 0">
|
||||
{{ 'DETAILS.TASKS.NO_ACTIVE' | translate }}
|
||||
</div>
|
||||
|
||||
<span class="activiti-label mdl-badge"
|
||||
[attr.data-badge]="completedTasks?.length">{{ 'DETAILS.LABELS.TASKS_COMPLETED'|translate }}</span>
|
||||
|
||||
<div class="menu-container" *ngIf="completedTasks?.length > 0">
|
||||
<ul class='mdl-list'>
|
||||
<li class="mdl-list__item mdl-list__item--two-line" *ngFor="let task of completedTasks">
|
||||
<span class="mdl-list__item-primary-content" (click)="clickTask($event, task)">
|
||||
<i class="material-icons mdl-list__item-icon">assignment</i>
|
||||
<span>{{task.name}}</span>
|
||||
<span class="mdl-list__item-sub-title">Assigned to {{getUserFullName(task.assignee)}}, created {{task.created | date:'mediumDate'}}</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div *ngIf="completedTasks?.length === 0">
|
||||
{{ 'DETAILS.TASKS.NO_COMPLETED' | translate }}
|
||||
</div>
|
||||
|
||||
<dialog class="mdl-dialog task-details-dialog" #dialog>
|
||||
<h4 class="mdl-dialog__title">Task details</h4>
|
||||
<div class="mdl-dialog__content">
|
||||
<activiti-task-details [taskId]="selectedTaskId" (formCompleted)="taskFormCompleted()" #taskdetails></activiti-task-details>
|
||||
</div>
|
||||
<div class="mdl-dialog__actions">
|
||||
<button type="button" (click)="cancelDialog()" class="mdl-button close">Close</button>
|
||||
</div>
|
||||
</dialog>
|
@@ -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<TaskDetailsModel>;
|
||||
private completedTaskObserver: Observer<TaskDetailsModel>;
|
||||
|
||||
task$: Observable<TaskDetailsModel>;
|
||||
completedTask$: Observable<TaskDetailsModel>;
|
||||
|
||||
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<TaskDetailsModel>(observer => this.taskObserver = observer).share();
|
||||
this.completedTask$ = new Observable<TaskDetailsModel>(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);
|
||||
}
|
||||
}
|
@@ -1,6 +1,12 @@
|
||||
<h1>My Activiti Processes</h1>
|
||||
|
||||
<p *ngIf="processInstances && processInstances.length == 0">{{ 'PROCESSLIST.NONE' | translate }}</p>
|
||||
<div *ngIf="!filter">{{ 'FILTERS.MESSAGES.NONE' | translate }}</div>
|
||||
<div *ngIf="filter">
|
||||
<div *ngIf="!isListEmpty()">
|
||||
<alfresco-datatable
|
||||
[data]="data">
|
||||
[data]="data"
|
||||
(rowClick)="onRowClick($event)">
|
||||
</alfresco-datatable>
|
||||
</div>
|
||||
<div *ngIf="isListEmpty()">
|
||||
{{ 'PROCESSLIST.NONE' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -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;
|
||||
|
@@ -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<string> = new EventEmitter<string>();
|
||||
|
||||
@Output()
|
||||
onSuccess: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Output()
|
||||
onError: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
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 = <any>error);
|
||||
error => {
|
||||
this.errorMessage = <any>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;
|
||||
}
|
||||
}
|
||||
|
@@ -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."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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<any>}
|
||||
*/
|
||||
getDeployedApplications(name: string): Observable<any> {
|
||||
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<ProcessInstance[]> {
|
||||
let request = {'page': 0, 'sort': 'created-desc', 'state': 'all'};
|
||||
|
||||
@@ -36,6 +49,99 @@ export class ActivitiProcessService {
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getProcessInstances(filter: FilterModel): Observable<ProcessInstance[]> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.processApi.getProcessInstances(filter))
|
||||
.map(this.extractData)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getProcessFilters(appId: string): Observable<any[]> {
|
||||
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<ProcessInstance> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.processApi.getProcessInstance(id))
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getProcessTasks(id: string, state: string): Observable<any[]> {
|
||||
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 {<Comment[]>}
|
||||
*/
|
||||
getProcessInstanceComments(id: string): Observable<Comment[]> {
|
||||
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<Comment> {
|
||||
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 || {};
|
||||
}
|
||||
|
Reference in New Issue
Block a user