mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-31 17:38:48 +00:00
@@ -1,123 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { 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('en-US');
|
||||
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;
|
||||
}
|
@@ -45,7 +45,7 @@ module.exports = function (config) {
|
||||
// ng2-components
|
||||
{ pattern: 'node_modules/ng2-alfresco-core/dist/**/*.*', included: false, served: true, watched: false },
|
||||
{ pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.*', 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/**/*.*', included: false, served: true, watched: false },
|
||||
{ pattern: 'node_modules/ng2-activiti-form/dist/**/*.*', included: false, served: true, watched: false },
|
||||
|
||||
// paths to support debugging with source maps in dev tools
|
||||
|
@@ -31,9 +31,22 @@ export class ProcessList {
|
||||
|
||||
export class SingleProcessList extends ProcessList {
|
||||
constructor(name?: string) {
|
||||
let instance = new ProcessInstance();
|
||||
instance.id = '123';
|
||||
instance.name = name;
|
||||
let instance = new ProcessInstance({
|
||||
id: '123',
|
||||
name: name
|
||||
});
|
||||
super([instance]);
|
||||
}
|
||||
}
|
||||
|
||||
export var exampleProcess = new ProcessInstance({
|
||||
id: '123',
|
||||
name: 'Process 123',
|
||||
started: '2016-11-10T03:37:30.010+0000',
|
||||
startedBy: {
|
||||
id: 1001,
|
||||
firstName: 'Bob',
|
||||
lastName: 'Jones',
|
||||
email: 'bob@app.activiti.com'
|
||||
}
|
||||
});
|
||||
|
@@ -0,0 +1,192 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export var taskDetailsMock = {
|
||||
'id': '91',
|
||||
'name': 'Request translation',
|
||||
'description': null,
|
||||
'category': null,
|
||||
'assignee': {'id': 1001, 'firstName': 'Wilbur', 'lastName': 'Adams', 'email': 'wilbur@app.activiti.com'},
|
||||
'created': '2016-11-03T15:25:42.749+0000',
|
||||
'dueDate': null,
|
||||
'endDate': null,
|
||||
'duration': null,
|
||||
'priority': 50,
|
||||
'parentTaskId': null,
|
||||
'parentTaskName': null,
|
||||
'processInstanceId': '86',
|
||||
'processInstanceName': null,
|
||||
'processDefinitionId': 'TranslationProcess:2:8',
|
||||
'processDefinitionName': 'Translation Process',
|
||||
'processDefinitionDescription': null,
|
||||
'processDefinitionKey': 'TranslationProcess',
|
||||
'processDefinitionCategory': 'http://www.activiti.org/processdef',
|
||||
'processDefinitionVersion': 2,
|
||||
'processDefinitionDeploymentId': '5',
|
||||
'formKey': '4',
|
||||
'processInstanceStartUserId': '1001',
|
||||
'initiatorCanCompleteTask': false,
|
||||
'adhocTaskCanBeReassigned': false,
|
||||
'taskDefinitionKey': 'sid-DDECD9E4-0299-433F-9193-C3D905C3EEBE',
|
||||
'executionId': '86',
|
||||
'involvedPeople': [],
|
||||
'memberOfCandidateUsers': false,
|
||||
'managerOfCandidateGroup': false,
|
||||
'memberOfCandidateGroup': false
|
||||
};
|
||||
|
||||
export var taskFormMock = {
|
||||
'id': 4,
|
||||
'name': 'Translation request',
|
||||
'processDefinitionId': 'TranslationProcess:2:8',
|
||||
'processDefinitionName': 'Translation Process',
|
||||
'processDefinitionKey': 'TranslationProcess',
|
||||
'taskId': '91',
|
||||
'taskName': 'Request translation',
|
||||
'taskDefinitionKey': 'sid-DDECD9E4-0299-433F-9193-C3D905C3EEBE',
|
||||
'tabs': [],
|
||||
'fields': [{
|
||||
'fieldType': 'ContainerRepresentation',
|
||||
'id': '1478093984155',
|
||||
'name': 'Label',
|
||||
'type': 'container',
|
||||
'value': null,
|
||||
'required': false,
|
||||
'readOnly': false,
|
||||
'overrideId': false,
|
||||
'colspan': 1,
|
||||
'placeholder': null,
|
||||
'minLength': 0,
|
||||
'maxLength': 0,
|
||||
'minValue': null,
|
||||
'maxValue': null,
|
||||
'regexPattern': null,
|
||||
'optionType': null,
|
||||
'hasEmptyValue': null,
|
||||
'options': null,
|
||||
'restUrl': null,
|
||||
'restResponsePath': null,
|
||||
'restIdProperty': null,
|
||||
'restLabelProperty': null,
|
||||
'tab': null,
|
||||
'className': null,
|
||||
'dateDisplayFormat': null,
|
||||
'layout': null,
|
||||
'sizeX': 2,
|
||||
'sizeY': 1,
|
||||
'row': -1,
|
||||
'col': -1,
|
||||
'visibilityCondition': null,
|
||||
'numberOfColumns': 2,
|
||||
'fields': {
|
||||
'1': [{
|
||||
'fieldType': 'AttachFileFieldRepresentation',
|
||||
'id': 'originalcontent',
|
||||
'name': 'Original content',
|
||||
'type': 'upload',
|
||||
'value': [],
|
||||
'required': true,
|
||||
'readOnly': false,
|
||||
'overrideId': false,
|
||||
'colspan': 1,
|
||||
'placeholder': null,
|
||||
'minLength': 0,
|
||||
'maxLength': 0,
|
||||
'minValue': null,
|
||||
'maxValue': null,
|
||||
'regexPattern': null,
|
||||
'optionType': null,
|
||||
'hasEmptyValue': null,
|
||||
'options': null,
|
||||
'restUrl': null,
|
||||
'restResponsePath': null,
|
||||
'restIdProperty': null,
|
||||
'restLabelProperty': null,
|
||||
'tab': null,
|
||||
'className': null,
|
||||
'params': {
|
||||
},
|
||||
'dateDisplayFormat': null,
|
||||
'layout': {'row': -1, 'column': -1, 'colspan': 1},
|
||||
'sizeX': 1,
|
||||
'sizeY': 1,
|
||||
'row': -1,
|
||||
'col': -1,
|
||||
'visibilityCondition': null,
|
||||
'metaDataColumnDefinitions': []
|
||||
}],
|
||||
'2': [{
|
||||
'fieldType': 'RestFieldRepresentation',
|
||||
'id': 'language',
|
||||
'name': 'Language',
|
||||
'type': 'dropdown',
|
||||
'value': 'Choose one...',
|
||||
'required': true,
|
||||
'readOnly': false,
|
||||
'overrideId': false,
|
||||
'colspan': 1,
|
||||
'placeholder': null,
|
||||
'minLength': 0,
|
||||
'maxLength': 0,
|
||||
'minValue': null,
|
||||
'maxValue': null,
|
||||
'regexPattern': null,
|
||||
'optionType': null,
|
||||
'hasEmptyValue': true,
|
||||
'options': [{'id': 'empty', 'name': 'Choose one...'}, {'id': 'fr', 'name': 'French'}, {
|
||||
'id': 'de',
|
||||
'name': 'German'
|
||||
}, {'id': 'es', 'name': 'Spanish'}],
|
||||
'restUrl': null,
|
||||
'restResponsePath': null,
|
||||
'restIdProperty': null,
|
||||
'restLabelProperty': null,
|
||||
'tab': null,
|
||||
'className': null,
|
||||
'params': {'existingColspan': 1, 'maxColspan': 1},
|
||||
'dateDisplayFormat': null,
|
||||
'layout': {'row': -1, 'column': -1, 'colspan': 1},
|
||||
'sizeX': 1,
|
||||
'sizeY': 1,
|
||||
'row': -1,
|
||||
'col': -1,
|
||||
'visibilityCondition': null,
|
||||
'endpoint': null,
|
||||
'requestHeaders': null
|
||||
}]
|
||||
}
|
||||
}],
|
||||
'outcomes': [],
|
||||
'javascriptEvents': [],
|
||||
'className': '',
|
||||
'style': '',
|
||||
'customFieldTemplates': {},
|
||||
'metadata': {},
|
||||
'variables': [],
|
||||
'gridsterForm': false,
|
||||
'globalDateFormat': 'D-M-YYYY'
|
||||
};
|
||||
|
||||
export var tasksMock = {
|
||||
data: [
|
||||
taskDetailsMock
|
||||
]
|
||||
};
|
||||
|
||||
export var noDataMock = {
|
||||
data: []
|
||||
};
|
@@ -15,7 +15,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div *ngIf="comments?.length === 0">
|
||||
<div *ngIf="comments?.length === 0" data-automation-id="comments-none">
|
||||
{{ 'DETAILS.COMMENTS.NONE' | translate }}
|
||||
</div>
|
||||
|
||||
|
@@ -0,0 +1,191 @@
|
||||
/*!
|
||||
* @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 { SimpleChange } from '@angular/core';
|
||||
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
||||
import { ActivitiFormModule } from 'ng2-activiti-form';
|
||||
|
||||
import { ActivitiComments } from './activiti-comments.component';
|
||||
import { ActivitiProcessService } from './../services/activiti-process.service';
|
||||
import { TranslationMock } from './../assets/translation.service.mock';
|
||||
|
||||
describe('ActivitiProcessInstanceComments', () => {
|
||||
|
||||
let componentHandler: any;
|
||||
let service: ActivitiProcessService;
|
||||
let component: ActivitiComments;
|
||||
let fixture: ComponentFixture<ActivitiComments>;
|
||||
let getCommentsSpy: jasmine.Spy;
|
||||
let addCommentSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule,
|
||||
ActivitiFormModule
|
||||
],
|
||||
declarations: [
|
||||
ActivitiComments
|
||||
],
|
||||
providers: [
|
||||
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
|
||||
ActivitiProcessService
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
fixture = TestBed.createComponent(ActivitiComments);
|
||||
component = fixture.componentInstance;
|
||||
service = fixture.debugElement.injector.get(ActivitiProcessService);
|
||||
|
||||
getCommentsSpy = spyOn(service, 'getProcessInstanceComments').and.returnValue(Observable.of([{
|
||||
message: 'Test1'
|
||||
}, {
|
||||
message: 'Test2'
|
||||
}, {
|
||||
message: 'Test3'
|
||||
}]));
|
||||
addCommentSpy = spyOn(service, 'addProcessInstanceComment').and.returnValue(Observable.of({id: 123, message: 'Test'}));
|
||||
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered',
|
||||
'upgradeElement'
|
||||
]);
|
||||
window['componentHandler'] = componentHandler;
|
||||
});
|
||||
|
||||
it('should load comments when processInstanceId specified', () => {
|
||||
component.processInstanceId = '123';
|
||||
fixture.detectChanges();
|
||||
expect(getCommentsSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit an error when an error occurs loading comments', () => {
|
||||
let emitSpy = spyOn(component.error, 'emit');
|
||||
getCommentsSpy.and.returnValue(Observable.throw({}));
|
||||
component.processInstanceId = '123';
|
||||
fixture.detectChanges();
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not comments when no processInstanceId is specified', () => {
|
||||
fixture.detectChanges();
|
||||
expect(getCommentsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should display comments when the process has comments', async(() => {
|
||||
component.processInstanceId = '123';
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.queryAll(By.css('ul.mdl-list li')).length).toBe(3);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not display comments when the process has no comments', async(() => {
|
||||
component.processInstanceId = '123';
|
||||
getCommentsSpy.and.returnValue(Observable.of([]));
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.queryAll(By.css('ul.mdl-list li')).length).toBe(0);
|
||||
});
|
||||
}));
|
||||
|
||||
describe('change detection', () => {
|
||||
|
||||
let change = new SimpleChange('123', '456');
|
||||
let nullChange = new SimpleChange('123', null);
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.processInstanceId = '123';
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
getCommentsSpy.calls.reset();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fetch new comments when processInstanceId changed', () => {
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
expect(getCommentsSpy).toHaveBeenCalledWith('456');
|
||||
});
|
||||
|
||||
it('should NOT fetch new comments when empty changeset made', () => {
|
||||
component.ngOnChanges({});
|
||||
expect(getCommentsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT fetch new comments when processInstanceId changed to null', () => {
|
||||
component.ngOnChanges({ 'processInstanceId': nullChange });
|
||||
expect(getCommentsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set a placeholder message when processInstanceId changed to null', () => {
|
||||
component.ngOnChanges({ 'processInstanceId': nullChange });
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.query(By.css('[data-automation-id="comments-none"]'))).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Add comment', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.processInstanceId = '123';
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable();
|
||||
}));
|
||||
|
||||
it('should display a dialog to the user when the Add button clicked', () => {
|
||||
let dialogEl = fixture.debugElement.query(By.css('.mdl-dialog')).nativeElement;
|
||||
let showSpy: jasmine.Spy = spyOn(dialogEl, 'showModal');
|
||||
component.showDialog();
|
||||
expect(showSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call service to add a comment', () => {
|
||||
component.showDialog();
|
||||
component.message = 'Test comment';
|
||||
component.add();
|
||||
expect(addCommentSpy).toHaveBeenCalledWith('123', 'Test comment');
|
||||
});
|
||||
|
||||
it('should emit an error when an error occurs adding the comment', () => {
|
||||
let emitSpy = spyOn(component.error, 'emit');
|
||||
addCommentSpy.and.returnValue(Observable.throw({}));
|
||||
component.showDialog();
|
||||
component.message = 'Test comment';
|
||||
component.add();
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should close add dialog when close button clicked', () => {
|
||||
let dialogEl = fixture.debugElement.query(By.css('.mdl-dialog')).nativeElement;
|
||||
let closeSpy: jasmine.Spy = spyOn(dialogEl, 'close');
|
||||
component.showDialog();
|
||||
component.cancel();
|
||||
expect(closeSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Input, OnInit, ViewChild, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, Output, OnInit, ViewChild, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
|
||||
import { ActivitiProcessService } from './../services/activiti-process.service';
|
||||
import { Comment } from 'ng2-activiti-tasklist';
|
||||
@@ -23,6 +23,7 @@ import { Observer } from 'rxjs/Observer';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
declare let componentHandler: any;
|
||||
declare let dialogPolyfill: any;
|
||||
|
||||
@Component({
|
||||
selector: 'activiti-process-instance-comments',
|
||||
@@ -36,6 +37,9 @@ export class ActivitiComments implements OnInit, OnChanges {
|
||||
@Input()
|
||||
processInstanceId: string;
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@ViewChild('dialog')
|
||||
dialog: any;
|
||||
|
||||
@@ -48,8 +52,8 @@ export class ActivitiComments implements OnInit, OnChanges {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param auth
|
||||
* @param translate
|
||||
* @param translate Translation service
|
||||
* @param activitiProcess Process service
|
||||
*/
|
||||
constructor(private translate: AlfrescoTranslationService,
|
||||
private activitiProcess: ActivitiProcessService) {
|
||||
@@ -66,17 +70,24 @@ export class ActivitiComments implements OnInit, OnChanges {
|
||||
this.comment$.subscribe((comment: Comment) => {
|
||||
this.comments.push(comment);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
let processInstanceId = changes['processInstanceId'];
|
||||
if (processInstanceId && processInstanceId.currentValue) {
|
||||
this.getProcessComments(processInstanceId.currentValue);
|
||||
if (this.processInstanceId) {
|
||||
this.getProcessComments(this.processInstanceId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public getProcessComments(processInstanceId: string) {
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
let processInstanceId = changes['processInstanceId'];
|
||||
if (processInstanceId) {
|
||||
if (processInstanceId.currentValue) {
|
||||
this.getProcessComments(processInstanceId.currentValue);
|
||||
} else {
|
||||
this.resetComments();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getProcessComments(processInstanceId: string) {
|
||||
this.comments = [];
|
||||
if (processInstanceId) {
|
||||
this.activitiProcess.getProcessInstanceComments(processInstanceId).subscribe(
|
||||
@@ -86,15 +97,22 @@ export class ActivitiComments implements OnInit, OnChanges {
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
this.error.emit(err);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.comments = [];
|
||||
this.resetComments();
|
||||
}
|
||||
}
|
||||
|
||||
private resetComments() {
|
||||
this.comments = [];
|
||||
}
|
||||
|
||||
public showDialog() {
|
||||
if (!this.dialog.nativeElement.showModal) {
|
||||
dialogPolyfill.registerDialog(this.dialog.nativeElement);
|
||||
}
|
||||
if (this.dialog) {
|
||||
this.dialog.nativeElement.showModal();
|
||||
}
|
||||
@@ -107,7 +125,7 @@ export class ActivitiComments implements OnInit, OnChanges {
|
||||
this.message = '';
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
this.error.emit(err);
|
||||
}
|
||||
);
|
||||
this.cancel();
|
||||
|
@@ -0,0 +1,160 @@
|
||||
/*!
|
||||
* @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 { SimpleChange } from '@angular/core';
|
||||
import { ActivitiProcessFilters } from './activiti-filters.component';
|
||||
import { ActivitiProcessService } from '../services/activiti-process.service';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { FilterRepresentationModel } from 'ng2-activiti-tasklist';
|
||||
|
||||
describe('ActivitiFilters', () => {
|
||||
|
||||
let filterList: ActivitiProcessFilters;
|
||||
let activitiService: ActivitiProcessService;
|
||||
|
||||
let fakeGlobalFilter = [];
|
||||
fakeGlobalFilter.push(new FilterRepresentationModel({name: 'FakeInvolvedTasks', filter: { state: 'open', assignment: 'fake-involved'}}));
|
||||
fakeGlobalFilter.push(new FilterRepresentationModel({name: 'FakeMyTasks', filter: { state: 'open', assignment: 'fake-assignee'}}));
|
||||
|
||||
let fakeGlobalFilterPromise = new Promise(function (resolve, reject) {
|
||||
resolve(fakeGlobalFilter);
|
||||
});
|
||||
|
||||
let fakeErrorFilterList = {
|
||||
error: 'wrong request'
|
||||
};
|
||||
|
||||
let fakeErrorFilterPromise = new Promise(function (resolve, reject) {
|
||||
reject(fakeErrorFilterList);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
activitiService = new ActivitiProcessService(null);
|
||||
filterList = new ActivitiProcessFilters(null, activitiService);
|
||||
});
|
||||
|
||||
it('should return the filter task list', (done) => {
|
||||
spyOn(activitiService, 'getProcessFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
|
||||
|
||||
filterList.onSuccess.subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(filterList.filters).toBeDefined();
|
||||
expect(filterList.filters.length).toEqual(2);
|
||||
expect(filterList.filters[0].name).toEqual('FakeInvolvedTasks');
|
||||
expect(filterList.filters[1].name).toEqual('FakeMyTasks');
|
||||
done();
|
||||
});
|
||||
|
||||
filterList.ngOnInit();
|
||||
});
|
||||
|
||||
it('should return the filter task list, filtered By Name', (done) => {
|
||||
|
||||
let fakeDeployedApplicationsPromise = new Promise(function (resolve, reject) {
|
||||
resolve({});
|
||||
});
|
||||
|
||||
spyOn(activitiService, 'getDeployedApplications').and.returnValue(Observable.fromPromise(fakeDeployedApplicationsPromise));
|
||||
spyOn(activitiService, 'getProcessFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
|
||||
|
||||
filterList.appName = 'test';
|
||||
|
||||
filterList.onSuccess.subscribe((res) => {
|
||||
let deployApp: any = activitiService.getDeployedApplications;
|
||||
expect(deployApp.calls.count()).toEqual(1);
|
||||
expect(res).toBeDefined();
|
||||
done();
|
||||
});
|
||||
|
||||
filterList.ngOnInit();
|
||||
});
|
||||
|
||||
it('should emit an error with a bad response', (done) => {
|
||||
filterList.appId = '1';
|
||||
spyOn(activitiService, 'getProcessFilters').and.returnValue(Observable.fromPromise(fakeErrorFilterPromise));
|
||||
|
||||
filterList.onError.subscribe((err) => {
|
||||
expect(err).toBeDefined();
|
||||
done();
|
||||
});
|
||||
|
||||
filterList.ngOnInit();
|
||||
});
|
||||
|
||||
it('should emit an error with a bad response', (done) => {
|
||||
filterList.appName = 'fake-app';
|
||||
spyOn(activitiService, 'getDeployedApplications').and.returnValue(Observable.fromPromise(fakeErrorFilterPromise));
|
||||
|
||||
filterList.onError.subscribe((err) => {
|
||||
expect(err).toBeDefined();
|
||||
done();
|
||||
});
|
||||
|
||||
filterList.ngOnInit();
|
||||
});
|
||||
|
||||
it('should emit an event when a filter is selected', (done) => {
|
||||
let currentFilter = new FilterRepresentationModel({filter: { state: 'open', assignment: 'fake-involved'}});
|
||||
|
||||
filterList.filterClick.subscribe((filter: FilterRepresentationModel) => {
|
||||
expect(filter).toBeDefined();
|
||||
expect(filter).toEqual(currentFilter);
|
||||
expect(filterList.currentFilter).toEqual(currentFilter);
|
||||
done();
|
||||
});
|
||||
|
||||
filterList.selectFilter(currentFilter);
|
||||
});
|
||||
|
||||
it('should reload filters by appId on binding changes', () => {
|
||||
spyOn(filterList, 'getFiltersByAppId').and.stub();
|
||||
const appId = '1';
|
||||
|
||||
let change = new SimpleChange(null, appId);
|
||||
filterList.ngOnChanges({ 'appId': change });
|
||||
|
||||
expect(filterList.getFiltersByAppId).toHaveBeenCalledWith(appId);
|
||||
});
|
||||
|
||||
it('should reload filters by appId null on binding changes', () => {
|
||||
spyOn(filterList, 'getFiltersByAppId').and.stub();
|
||||
const appId = null;
|
||||
|
||||
let change = new SimpleChange(null, appId);
|
||||
filterList.ngOnChanges({ 'appId': change });
|
||||
|
||||
expect(filterList.getFiltersByAppId).toHaveBeenCalledWith(appId);
|
||||
});
|
||||
|
||||
it('should reload filters by app name on binding changes', () => {
|
||||
spyOn(filterList, 'getFiltersByAppName').and.stub();
|
||||
const appName = 'fake-app-name';
|
||||
|
||||
let change = new SimpleChange(null, appName);
|
||||
filterList.ngOnChanges({ 'appName': change });
|
||||
|
||||
expect(filterList.getFiltersByAppName).toHaveBeenCalledWith(appName);
|
||||
});
|
||||
|
||||
it('should return the current filter after one is selected', () => {
|
||||
let filter = new FilterRepresentationModel({name: 'FakeMyTasks', filter: { state: 'open', assignment: 'fake-assignee'}});
|
||||
expect(filterList.currentFilter).toBeUndefined();
|
||||
filterList.selectFilter(filter);
|
||||
expect(filterList.getCurrentFilter()).toBe(filter);
|
||||
});
|
||||
|
||||
});
|
@@ -4,7 +4,11 @@
|
||||
<activiti-process-instance-header [processInstance]="processInstanceDetails" (processCancelled)="bubbleProcessCancelled()" #activitiprocessheader></activiti-process-instance-header>
|
||||
<div class="mdl-grid">
|
||||
<div class="mdl-cell mdl-cell--8-col">
|
||||
<<<<<<< HEAD
|
||||
<activiti-process-instance-tasks [processInstanceDetails]="processInstanceDetails" (taskFormCompleted)="bubbleTaskFormCompleted()" #activitiprocesstasks></activiti-process-instance-tasks>
|
||||
=======
|
||||
<activiti-process-instance-tasks [processInstanceId]="processInstanceDetails.id" (taskFormCompleted)="onTaskFormCompleted()" #activitiprocesstasks></activiti-process-instance-tasks>
|
||||
>>>>>>> New tests for processlist components
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<activiti-process-instance-comments [processInstanceId]="processInstanceDetails.id" #activitiprocesscomments></activiti-process-instance-comments>
|
||||
|
@@ -0,0 +1,165 @@
|
||||
/*!
|
||||
* @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 { NO_ERRORS_SCHEMA, DebugElement, SimpleChange } from '@angular/core';
|
||||
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
||||
import { ActivitiFormModule, FormModel, FormOutcomeEvent, FormOutcomeModel, FormService } from 'ng2-activiti-form';
|
||||
import { ActivitiTaskListModule } from 'ng2-activiti-tasklist';
|
||||
|
||||
import { ActivitiProcessInstanceDetails } from './activiti-process-instance-details.component';
|
||||
import { ActivitiProcessService } from './../services/activiti-process.service';
|
||||
import { TranslationMock } from './../assets/translation.service.mock';
|
||||
import { exampleProcess } from './../assets/activiti-process.model.mock';
|
||||
|
||||
describe('ActivitiProcessInstanceDetails', () => {
|
||||
|
||||
let componentHandler: any;
|
||||
let service: ActivitiProcessService;
|
||||
let formService: FormService;
|
||||
let component: ActivitiProcessInstanceDetails;
|
||||
let fixture: ComponentFixture<ActivitiProcessInstanceDetails>;
|
||||
let getProcessSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule,
|
||||
ActivitiFormModule,
|
||||
ActivitiTaskListModule
|
||||
],
|
||||
declarations: [
|
||||
ActivitiProcessInstanceDetails
|
||||
],
|
||||
providers: [
|
||||
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
|
||||
ActivitiProcessService
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
fixture = TestBed.createComponent(ActivitiProcessInstanceDetails);
|
||||
component = fixture.componentInstance;
|
||||
service = fixture.debugElement.injector.get(ActivitiProcessService);
|
||||
formService = fixture.debugElement.injector.get(FormService);
|
||||
|
||||
getProcessSpy = spyOn(service, 'getProcess').and.returnValue(Observable.of(exampleProcess));
|
||||
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered',
|
||||
'upgradeElement'
|
||||
]);
|
||||
window['componentHandler'] = componentHandler;
|
||||
});
|
||||
|
||||
it('should load task details when processInstanceId specified', () => {
|
||||
component.processInstanceId = '123';
|
||||
fixture.detectChanges();
|
||||
expect(getProcessSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not load task details when no processInstanceId is specified', () => {
|
||||
fixture.detectChanges();
|
||||
expect(getProcessSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set a placeholder message when processInstanceId not initialised', () => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerText).toBe('DETAILS.MESSAGES.NONE');
|
||||
});
|
||||
|
||||
it('should display a header when the processInstanceId is provided', async(() => {
|
||||
component.processInstanceId = '123';
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
let headerEl: DebugElement = fixture.debugElement.query(By.css('h2'));
|
||||
expect(headerEl).not.toBeNull();
|
||||
expect(headerEl.nativeElement.innerText).toBe('Process 123');
|
||||
});
|
||||
}));
|
||||
|
||||
describe('change detection', () => {
|
||||
|
||||
let change = new SimpleChange('123', '456');
|
||||
let nullChange = new SimpleChange('123', null);
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.processInstanceId = '123';
|
||||
fixture.detectChanges();
|
||||
component.tasksList = jasmine.createSpyObj('tasksList', ['load']);
|
||||
fixture.whenStable().then(() => {
|
||||
getProcessSpy.calls.reset();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fetch new process details when processInstanceId changed', () => {
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
expect(getProcessSpy).toHaveBeenCalledWith('456');
|
||||
});
|
||||
|
||||
it('should reload tasks list when processInstanceId changed', () => {
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
expect(component.tasksList.load).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT fetch new process details when empty changeset made', () => {
|
||||
component.ngOnChanges({});
|
||||
expect(getProcessSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT fetch new process details when processInstanceId changed to null', () => {
|
||||
component.ngOnChanges({ 'processInstanceId': nullChange });
|
||||
expect(getProcessSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set a placeholder message when processInstanceId changed to null', () => {
|
||||
component.ngOnChanges({ 'processInstanceId': nullChange });
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerText).toBe('DETAILS.MESSAGES.NONE');
|
||||
});
|
||||
});
|
||||
|
||||
describe('events', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.processInstanceId = '123';
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable();
|
||||
}));
|
||||
|
||||
it('should emit a task form completed event when task form completed', () => {
|
||||
let emitSpy: jasmine.Spy = spyOn(component.taskFormCompleted, 'emit');
|
||||
component.bubbleTaskFormCompleted(new FormModel());
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit a outcome execution event when task form outcome executed', () => {
|
||||
let emitSpy: jasmine.Spy = spyOn(component.processCancelled, 'emit');
|
||||
component.bubbleProcessCancelled(new FormOutcomeEvent(new FormOutcomeModel(new FormModel())));
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@@ -61,9 +61,8 @@ export class ActivitiProcessInstanceDetails implements OnInit, OnChanges {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param auth
|
||||
* @param translate
|
||||
* @param activitiProcess
|
||||
* @param translate Translation service
|
||||
* @param activitiProcess Process service
|
||||
*/
|
||||
constructor(private translate: AlfrescoTranslationService,
|
||||
private activitiProcess: ActivitiProcessService) {
|
||||
|
@@ -1,15 +1,19 @@
|
||||
<div *ngIf="processInstance">
|
||||
<div class="mdl-grid">
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<div class="mdl-cell mdl-cell--4-col" data-automation-id="header-started-by">
|
||||
<span class="activiti-label">{{ 'DETAILS.LABELS.STARTED_BY' | translate }}</span>:
|
||||
{{getStartedByFullName()}}
|
||||
<span class="activiti-process-header__value">{{getStartedByFullName()}}</span>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<div class="mdl-cell mdl-cell--4-col" data-automation-id="header-started">
|
||||
<span class="activiti-label">{{ 'DETAILS.LABELS.STARTED' | translate }}</span>:
|
||||
{{getFormatDate(processInstance.started, 'medium')}}
|
||||
<span class="activiti-process-header__value">{{getFormatDate(processInstance.started, 'medium')}}</span>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<div class="mdl-cell mdl-cell--4-col" data-automation-id="header-status" *ngIf="isRunning()">
|
||||
<button type="button" (click)="cancelProcess()" class="mdl-button">{{ 'DETAILS.BUTTON.CANCEL' | translate }}</button>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--4-col" data-automation-id="header-status" *ngIf="!isRunning()">
|
||||
<span class="activiti-label">{{ 'DETAILS.LABELS.ENDED' | translate }}</span>:
|
||||
<span class="activiti-process-header__value">{{getFormatDate(processInstance.ended, 'medium')}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -0,0 +1,108 @@
|
||||
/*!
|
||||
* @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 { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
|
||||
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
||||
|
||||
import { ActivitiProcessInstanceHeader } from './activiti-process-instance-header.component';
|
||||
import { TranslationMock } from './../assets/translation.service.mock';
|
||||
import { exampleProcess } from './../assets/activiti-process.model.mock';
|
||||
import { ProcessInstance } from './../models/process-instance';
|
||||
import { ActivitiProcessService } from './../services/activiti-process.service';
|
||||
|
||||
describe('ActivitiProcessInstanceHeader', () => {
|
||||
|
||||
let componentHandler: any;
|
||||
let component: ActivitiProcessInstanceHeader;
|
||||
let fixture: ComponentFixture<ActivitiProcessInstanceHeader>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule
|
||||
],
|
||||
declarations: [
|
||||
ActivitiProcessInstanceHeader
|
||||
],
|
||||
providers: [
|
||||
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
|
||||
ActivitiProcessService
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
fixture = TestBed.createComponent(ActivitiProcessInstanceHeader);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
component.processInstance = new ProcessInstance(exampleProcess);
|
||||
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered',
|
||||
'upgradeElement'
|
||||
]);
|
||||
window['componentHandler'] = componentHandler;
|
||||
});
|
||||
|
||||
it('should render empty component if no form details provided', () => {
|
||||
component.processInstance = undefined;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.children.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should display started by user', () => {
|
||||
fixture.detectChanges();
|
||||
let formValueEl = fixture.debugElement.query(By.css('[data-automation-id="header-started-by"] .activiti-process-header__value'));
|
||||
expect(formValueEl).not.toBeNull();
|
||||
expect(formValueEl.nativeElement.innerText).toBe('Bob Jones');
|
||||
});
|
||||
|
||||
it('should display empty started by user if user unknown', () => {
|
||||
component.processInstance.startedBy = null;
|
||||
fixture.detectChanges();
|
||||
let formValueEl = fixture.debugElement.query(By.css('[data-automation-id="header-started-by"] .activiti-process-header__value'));
|
||||
expect(formValueEl).not.toBeNull();
|
||||
expect(formValueEl.nativeElement.innerText).toBe('');
|
||||
});
|
||||
|
||||
it('should display process start date', () => {
|
||||
component.processInstance.started = '2016-11-10T03:37:30.010+0000';
|
||||
fixture.detectChanges();
|
||||
let formValueEl = fixture.debugElement.query(By.css('[data-automation-id="header-started"] .activiti-process-header__value'));
|
||||
expect(formValueEl).not.toBeNull();
|
||||
expect(formValueEl.nativeElement.innerText).toBe('Nov 10, 2016, 3:37:30 AM');
|
||||
});
|
||||
|
||||
it('should display cancel button if process is running', () => {
|
||||
component.processInstance.ended = null;
|
||||
fixture.detectChanges();
|
||||
let buttonEl = fixture.debugElement.query(By.css('[data-automation-id="header-status"] button'));
|
||||
expect(buttonEl).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should display ended date if process is ended', () => {
|
||||
component.processInstance.ended = '2016-11-10T03:37:30.010+0000';
|
||||
fixture.detectChanges();
|
||||
let formValueEl = fixture.debugElement.query(By.css('[data-automation-id="header-status"] .activiti-process-header__value'));
|
||||
expect(formValueEl).not.toBeNull();
|
||||
expect(formValueEl.nativeElement.innerText).toBe('Nov 10, 2016, 3:37:30 AM');
|
||||
});
|
||||
|
||||
});
|
@@ -48,7 +48,7 @@ export class ActivitiProcessInstanceHeader {
|
||||
}
|
||||
}
|
||||
|
||||
getStartedByFullName() {
|
||||
getStartedByFullName(): string {
|
||||
if (this.processInstance && this.processInstance.startedBy) {
|
||||
return (this.processInstance.startedBy.firstName && this.processInstance.startedBy.firstName !== 'null'
|
||||
? this.processInstance.startedBy.firstName + ' ' : '') +
|
||||
@@ -66,6 +66,10 @@ export class ActivitiProcessInstanceHeader {
|
||||
}
|
||||
}
|
||||
|
||||
isRunning(): boolean {
|
||||
return this.processInstance && !this.processInstance.ended;
|
||||
}
|
||||
|
||||
cancelProcess() {
|
||||
this.activitiProcess.cancelProcess(this.processInstance.id).subscribe(
|
||||
(res) => {
|
||||
|
@@ -10,7 +10,7 @@
|
||||
<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">
|
||||
<div class="menu-container" *ngIf="activeTasks?.length > 0" data-automation-id="active-tasks">
|
||||
<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)">
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
<!-- START FORM -->
|
||||
|
||||
<div *ngIf="activeTasks?.length === 0">
|
||||
<div *ngIf="activeTasks?.length === 0" data-automation-id="active-tasks-none">
|
||||
{{ 'DETAILS.TASKS.NO_ACTIVE' | translate }}
|
||||
</div>
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<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">
|
||||
<div class="menu-container" *ngIf="completedTasks?.length > 0" data-automation-id="completed-tasks">
|
||||
<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)">
|
||||
@@ -64,7 +64,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div *ngIf="completedTasks?.length === 0">
|
||||
<div *ngIf="completedTasks?.length === 0" data-automation-id="completed-tasks-none">
|
||||
{{ 'DETAILS.TASKS.NO_COMPLETED' | translate }}
|
||||
</div>
|
||||
|
||||
|
@@ -0,0 +1,206 @@
|
||||
/*!
|
||||
* @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 { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
||||
import { TaskDetailsModel } from 'ng2-activiti-tasklist';
|
||||
|
||||
import { ActivitiProcessInstanceTasks } from './activiti-process-instance-tasks.component';
|
||||
import { TranslationMock } from './../assets/translation.service.mock';
|
||||
import { taskDetailsMock } from './../assets/task-details.mock';
|
||||
import { ProcessInstance } from './../models/process-instance';
|
||||
import { ActivitiProcessService } from './../services/activiti-process.service';
|
||||
|
||||
describe('ActivitiProcessInstanceTasks', () => {
|
||||
|
||||
let componentHandler: any;
|
||||
let component: ActivitiProcessInstanceTasks;
|
||||
let fixture: ComponentFixture<ActivitiProcessInstanceTasks>;
|
||||
let service: ActivitiProcessService;
|
||||
let getProcessTasksSpy: jasmine.Spy;
|
||||
|
||||
let exampleProcessInstance = new ProcessInstance({ id: '123' });
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule
|
||||
],
|
||||
declarations: [
|
||||
ActivitiProcessInstanceTasks
|
||||
],
|
||||
providers: [
|
||||
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
|
||||
ActivitiProcessService
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
fixture = TestBed.createComponent(ActivitiProcessInstanceTasks);
|
||||
component = fixture.componentInstance;
|
||||
service = fixture.debugElement.injector.get(ActivitiProcessService);
|
||||
getProcessTasksSpy = spyOn(service, 'getProcessTasks').and.returnValue(Observable.of([new TaskDetailsModel(taskDetailsMock)]));
|
||||
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered',
|
||||
'upgradeElement'
|
||||
]);
|
||||
window['componentHandler'] = componentHandler;
|
||||
});
|
||||
|
||||
it('should initially render message about no active tasks if no process instance ID provided', async(() => {
|
||||
component.processInstanceDetails = undefined;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
let msgEl = fixture.debugElement.query(By.css('[data-automation-id="active-tasks-none"]'));
|
||||
expect(msgEl).not.toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should initially render message about no completed tasks if no process instance ID provided', async(() => {
|
||||
component.processInstanceDetails = undefined;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
let msgEl = fixture.debugElement.query(By.css('[data-automation-id="completed-tasks-none"]'));
|
||||
expect(msgEl).not.toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not render active tasks list if no process instance ID provided', () => {
|
||||
component.processInstanceDetails = undefined;
|
||||
fixture.detectChanges();
|
||||
let listEl = fixture.debugElement.query(By.css('[data-automation-id="active-tasks"]'));
|
||||
expect(listEl).toBeNull();
|
||||
});
|
||||
|
||||
it('should not render completed tasks list if no process instance ID provided', () => {
|
||||
component.processInstanceDetails = undefined;
|
||||
fixture.detectChanges();
|
||||
let listEl = fixture.debugElement.query(By.css('[data-automation-id="completed-tasks"]'));
|
||||
expect(listEl).toBeNull();
|
||||
});
|
||||
|
||||
it('should call service to get tasks on init', () => {
|
||||
component.processInstanceDetails = exampleProcessInstance;
|
||||
fixture.detectChanges();
|
||||
expect(getProcessTasksSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should display active tasks', () => {
|
||||
component.processInstanceDetails = exampleProcessInstance;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
let listEl = fixture.debugElement.query(By.css('[data-automation-id="active-tasks"]'));
|
||||
expect(listEl).not.toBeNull();
|
||||
expect(listEl.queryAll(By.css('li')).length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should display completed tasks', () => {
|
||||
component.processInstanceDetails = exampleProcessInstance;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
let listEl = fixture.debugElement.query(By.css('[data-automation-id="completed-tasks"]'));
|
||||
expect(listEl).not.toBeNull();
|
||||
expect(listEl.queryAll(By.css('li')).length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('task reloading', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.processInstanceDetails = exampleProcessInstance;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable();
|
||||
}));
|
||||
|
||||
it('should render a refresh button by default', () => {
|
||||
expect(fixture.debugElement.query(By.css('.process-tasks-refresh'))).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should render a refresh button if configured to', () => {
|
||||
component.showRefreshButton = true;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.query(By.css('.process-tasks-refresh'))).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should NOT render a refresh button if configured not to', () => {
|
||||
component.showRefreshButton = false;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.query(By.css('.process-tasks-refresh'))).toBeNull();
|
||||
});
|
||||
|
||||
it('should call service to get tasks when reload button clicked', () => {
|
||||
getProcessTasksSpy.calls.reset();
|
||||
component.onRefreshClicked();
|
||||
expect(getProcessTasksSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('task details', () => {
|
||||
|
||||
let closeSpy;
|
||||
|
||||
beforeEach(async(() => {
|
||||
closeSpy = spyOn(component.dialog.nativeElement, 'close');
|
||||
component.processInstanceDetails = exampleProcessInstance;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable();
|
||||
component.taskdetails = jasmine.createSpyObj('taskdetails', [
|
||||
'loadDetails'
|
||||
]);
|
||||
}));
|
||||
|
||||
it('should display task details dialog when task clicked', () => {
|
||||
let showModalSpy = spyOn(component.dialog.nativeElement, 'showModal');
|
||||
component.clickTask({}, new TaskDetailsModel(taskDetailsMock));
|
||||
expect(showModalSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should close the task details dialog when close button clicked', () => {
|
||||
component.clickTask({}, new TaskDetailsModel(taskDetailsMock));
|
||||
fixture.detectChanges();
|
||||
component.cancelDialog();
|
||||
expect(closeSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should output event when task form completed', async(() => {
|
||||
let emitSpy = spyOn(component.taskFormCompleted, 'emit');
|
||||
fixture.detectChanges();
|
||||
component.clickTask({}, new TaskDetailsModel(taskDetailsMock));
|
||||
fixture.detectChanges();
|
||||
component.onTaskFormCompleted();
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should close dialog when task form completed', async(() => {
|
||||
component.clickTask({}, new TaskDetailsModel(taskDetailsMock));
|
||||
fixture.detectChanges();
|
||||
component.onTaskFormCompleted();
|
||||
expect(closeSpy).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
@@ -41,7 +41,7 @@ export class ActivitiProcessInstanceTasks implements OnInit {
|
||||
showRefreshButton: boolean = true;
|
||||
|
||||
@Output()
|
||||
taskFormCompletedEmitter = new EventEmitter();
|
||||
taskFormCompleted = new EventEmitter();
|
||||
|
||||
activeTasks: TaskDetailsModel[] = [];
|
||||
completedTasks: TaskDetailsModel[] = [];
|
||||
@@ -191,10 +191,10 @@ export class ActivitiProcessInstanceTasks implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
public taskFormCompleted() {
|
||||
public onTaskFormCompleted() {
|
||||
this.closeDialog();
|
||||
this.load(this.processInstanceDetails.id);
|
||||
this.taskFormCompletedEmitter.emit(this.processInstanceDetails.id);
|
||||
this.taskFormCompleted.emit(this.processInstanceDetails.id);
|
||||
}
|
||||
|
||||
public onRefreshClicked() {
|
||||
|
@@ -20,6 +20,7 @@ import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { ActivitiProcessInstanceListComponent } from './activiti-processlist.component';
|
||||
import { TranslationMock } from './../assets/translation.service.mock';
|
||||
import { ObjectDataTableAdapter } from 'ng2-alfresco-datatable';
|
||||
import { FilterRepresentationModel } from 'ng2-activiti-tasklist';
|
||||
import { ActivitiProcessService } from '../services/activiti-process.service';
|
||||
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
||||
@@ -60,8 +61,23 @@ describe('ActivitiProcessInstanceListComponent', () => {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should initialise data table', () => {
|
||||
fixture.detectChanges();
|
||||
it('should use the default schemaColumn as default', () => {
|
||||
component.ngOnInit();
|
||||
expect(component.data.getColumns()).toBeDefined();
|
||||
expect(component.data.getColumns().length).toEqual(4);
|
||||
});
|
||||
|
||||
it('should use the schemaColumn passed in input', () => {
|
||||
component.data = new ObjectDataTableAdapter(
|
||||
[],
|
||||
[
|
||||
{type: 'text', key: 'fake-id', title: 'Name'}
|
||||
]
|
||||
);
|
||||
|
||||
component.ngOnInit();
|
||||
expect(component.data.getColumns()).toBeDefined();
|
||||
expect(component.data.getColumns().length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should fetch process instances when a filter is provided', () => {
|
||||
|
@@ -1,22 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
describe('Placeholder', () => {
|
||||
it('test placeholder', () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
@@ -16,6 +16,7 @@
|
||||
"LABELS": {
|
||||
"STARTED_BY": "Started by",
|
||||
"STARTED": "Started",
|
||||
"ENDED": "Ended",
|
||||
"COMMENTS": "Comments",
|
||||
"START_FORM": "Start Form",
|
||||
"TASKS_ACTIVE": "Active Tasks",
|
||||
|
@@ -36,4 +36,25 @@ export class ProcessInstance {
|
||||
public tenantId: string;
|
||||
public variables: any;
|
||||
|
||||
constructor(data?: any) {
|
||||
this.businessKey = data && data.businessKey !== undefined ? data.businessKey : null;
|
||||
this.ended = data && data.ended !== undefined ? data.ended : null;
|
||||
this.graphicalNotationDefined = data && data.graphicalNotationDefined !== undefined ? data.graphicalNotationDefined : null;
|
||||
this.id = data && data.id !== undefined ? data.id : null;
|
||||
this.name = data && data.name !== undefined ? data.name : null;
|
||||
this.processDefinitionCategory = data && data.processDefinitionCategory !== undefined ? data.processDefinitionCategory : null;
|
||||
this.processDefinitionDeploymentId = data && data.processDefinitionDeploymentId !== undefined ? data.processDefinitionDeploymentId : null;
|
||||
this.processDefinitionDescription = data && data.processDefinitionDescription !== undefined ? data.processDefinitionDescription : null;
|
||||
this.processDefinitionId = data && data.processDefinitionId !== undefined ? data.processDefinitionId : null;
|
||||
this.processDefinitionKey = data && data.processDefinitionKey !== undefined ? data.processDefinitionKey : null;
|
||||
this.processDefinitionName = data && data.processDefinitionName !== undefined ? data.processDefinitionName : null;
|
||||
this.processDefinitionVersion = data && data.processDefinitionVersion !== undefined ? data.processDefinitionVersion : null;
|
||||
this.startFormDefined = data && data.startFormDefined !== undefined ? data.startFormDefined : null;
|
||||
this.started = data && data.started !== undefined ? data.started : null;
|
||||
this.startedBy = data && data.startedBy !== undefined ? data.startedBy : null;
|
||||
this.suspended = data && data.suspended !== undefined ? data.suspended : null;
|
||||
this.tenantId = data && data.tenantId !== undefined ? data.tenantId : null;
|
||||
this.variables = data && data.variables !== undefined ? data.variables : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user