From e846a15aa8df9a2829aa78fd981681397eb8c01c Mon Sep 17 00:00:00 2001 From: Will Abson Date: Tue, 24 Jan 2017 00:56:23 +0000 Subject: [PATCH] Display name and date for process instances if no name present (#1515) * Display name and date for process instances if no name present Refs #1461 * Re-work tests for processlist and process details to reflect changes Refs #1461 --- .../activiti-process-instances-list.mock.ts | 74 +++++++++ .../src/assets/activiti-process.model.mock.ts | 13 ++ ...ti-process-instance-details.component.html | 2 +- ...process-instance-details.component.spec.ts | 14 +- ...viti-process-instance-details.component.ts | 19 +++ .../activiti-processlist.component.spec.ts | 145 +++++++++++++----- .../activiti-processlist.component.ts | 24 ++- 7 files changed, 248 insertions(+), 43 deletions(-) create mode 100644 ng2-components/ng2-activiti-processlist/src/assets/activiti-process-instances-list.mock.ts diff --git a/ng2-components/ng2-activiti-processlist/src/assets/activiti-process-instances-list.mock.ts b/ng2-components/ng2-activiti-processlist/src/assets/activiti-process-instances-list.mock.ts new file mode 100644 index 0000000000..1181b9df2d --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/assets/activiti-process-instances-list.mock.ts @@ -0,0 +1,74 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ProcessInstance } from '../models/process-instance.model'; + +export var fakeProcessInstances = [ + new ProcessInstance({ + id: 1, + name: 'Process 773443333', + processDefinitionId: 'fakeprocess:5:7507', + processDefinitionKey: 'fakeprocess', + processDefinitionName: 'Fake Process Name', + description: null, category: null, + started: '2015-11-09T12:36:14.184+0000', + startedBy: { + id: 3, firstName: 'tenant2', lastName: 'tenantLastname', email: 'tenant2@tenant' + } + }), + new ProcessInstance({ + id: 2, + name: 'Process 382927392', + processDefinitionId: 'fakeprocess:5:7507', + processDefinitionKey: 'fakeprocess', + processDefinitionName: 'Fake Process Name', + description: null, + category: null, + started: '2017-11-09T12:37:25.184+0000', + startedBy: { + id: 3, firstName: 'tenant2', lastName: 'tenantLastname', email: 'tenant2@tenant' + } + }) +]; + +export var fakeProcessInstancesWithNoName = [ + new ProcessInstance({ + id: 1, + name: null, + processDefinitionId: 'fakeprocess:5:7507', + processDefinitionKey: 'fakeprocess', + processDefinitionName: 'Fake Process Name', + description: null, category: null, + started: '2017-11-09T12:36:14.184+0000', + startedBy: { + id: 3, firstName: 'tenant2', lastName: 'tenantLastname', email: 'tenant2@tenant' + } + }), + new ProcessInstance({ + id: 2, + name: '', + processDefinitionId: 'fakeprocess:5:7507', + processDefinitionKey: 'fakeprocess', + processDefinitionName: 'Fake Process Name', + description: null, + category: null, + started: '2017-11-09T12:37:25.184+0000', + startedBy: { + id: 3, firstName: 'tenant2', lastName: 'tenantLastname', email: 'tenant2@tenant' + } + }) +]; diff --git a/ng2-components/ng2-activiti-processlist/src/assets/activiti-process.model.mock.ts b/ng2-components/ng2-activiti-processlist/src/assets/activiti-process.model.mock.ts index 202b62cf69..bbcf650f15 100644 --- a/ng2-components/ng2-activiti-processlist/src/assets/activiti-process.model.mock.ts +++ b/ng2-components/ng2-activiti-processlist/src/assets/activiti-process.model.mock.ts @@ -50,3 +50,16 @@ export var exampleProcess = new ProcessInstance({ email: 'bob@app.activiti.com' } }); + +export var exampleProcessNoName = new ProcessInstance({ + id: '123', + name: null, + started: '2016-11-10T03:37:30.010+0000', + startedBy: { + id: 1001, + firstName: 'Bob', + lastName: 'Jones', + email: 'bob@app.activiti.com' + }, + processDefinitionName: 'My Process' +}); diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.html b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.html index 67fb465d4a..18ca467cf2 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.html +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.html @@ -1,6 +1,6 @@
{{ 'DETAILS.MESSAGES.NONE'|translate }}
-

{{processInstanceDetails.name}}

+

{{ getProcessNameOrDescription('medium') }}

diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.spec.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.spec.ts index ba4ff24006..f7e3016d46 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.spec.ts +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.spec.ts @@ -27,7 +27,7 @@ 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'; +import { exampleProcess, exampleProcessNoName } from './../assets/activiti-process.model.mock'; import { ProcessInstance } from '../models/process-instance.model'; describe('ActivitiProcessInstanceDetails', () => { @@ -94,6 +94,18 @@ describe('ActivitiProcessInstanceDetails', () => { }); })); + it('should display default details when the process instance has no name', async(() => { + getProcessSpy = getProcessSpy.and.returnValue(Observable.of(exampleProcessNoName)); + fixture.detectChanges(); + component.ngOnChanges({ 'processInstanceId': new SimpleChange(null, '123') }); + fixture.whenStable().then(() => { + fixture.detectChanges(); + let headerEl: DebugElement = fixture.debugElement.query(By.css('h2')); + expect(headerEl).not.toBeNull(); + expect(headerEl.nativeElement.innerText).toBe('My Process - Nov 10, 2016, 3:37:30 AM'); + }); + })); + describe('change detection', () => { let change = new SimpleChange('123', '456'); diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.ts index b4edb2d997..b39ae9ca56 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.ts +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-process-instance-details.component.ts @@ -15,6 +15,7 @@ * limitations under the License. */ +import { DatePipe } from '@angular/common'; import { Component, Input, ViewChild, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core'; import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core'; import { TaskDetailsEvent } from 'ng2-activiti-tasklist'; @@ -115,4 +116,22 @@ export class ActivitiProcessInstanceDetails implements OnChanges { onTaskClicked(event: TaskDetailsEvent) { this.taskClick.emit(event); } + + getProcessNameOrDescription(dateFormat): string { + let name = ''; + if (this.processInstanceDetails) { + name = this.processInstanceDetails.name || + this.processInstanceDetails.processDefinitionName + ' - ' + this.getFormatDate(this.processInstanceDetails.started, dateFormat); + } + return name; + } + + getFormatDate(value, format: string) { + let datePipe = new DatePipe('en-US'); + try { + return datePipe.transform(value, format); + } catch (err) { + this.logService.error(`ProcessListInstanceHeader: error parsing date ${value} to format ${format}`); + } + } } diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.spec.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.spec.ts index f4b548b15c..a6f71829f0 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.spec.ts +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.spec.ts @@ -23,33 +23,12 @@ import { ActivitiProcessInstanceListComponent } from './activiti-processlist.com import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; import { DataTableModule, ObjectDataRow, DataRowEvent, ObjectDataTableAdapter, DataSorting } from 'ng2-alfresco-datatable'; +import { fakeProcessInstances, fakeProcessInstancesWithNoName } from '../assets/activiti-process-instances-list.mock'; import { TranslationMock } from './../assets/translation.service.mock'; -import { ProcessInstance } from '../models/process-instance.model'; import { ActivitiProcessService } from '../services/activiti-process.service'; describe('ActivitiProcessInstanceListComponent', () => { - let fakeGlobalProcesses = [ - new ProcessInstance({ - id: 1, name: 'process-name', - processDefinitionId: 'fakeprocess:5:7507', - processDefinitionKey: 'fakeprocess', - processDefinitionName: 'Fake Process Name', - description: null, category: null, - started: '2017-11-09T12:37:25.184+0000', - startedBy: { - id: 3, firstName: 'tenant2', lastName: 'tenantLastname', email: 'tenant2@tenant' - } - }), - new ProcessInstance({ - id: 2, name: '', description: null, category: null, - started: '2015-11-09T12:37:25.184+0000', - startedBy: { - id: 3, firstName: 'tenant2', lastName: 'tenantLastname', email: 'tenant2@tenant' - } - }) - ]; - let componentHandler: any; let fixture: ComponentFixture; let component: ActivitiProcessInstanceListComponent; @@ -72,7 +51,7 @@ describe('ActivitiProcessInstanceListComponent', () => { component = fixture.componentInstance; service = fixture.debugElement.injector.get(ActivitiProcessService); - getProcessInstancesSpy = spyOn(service, 'getProcessInstances').and.returnValue(Observable.of(fakeGlobalProcesses)); + getProcessInstancesSpy = spyOn(service, 'getProcessInstances').and.returnValue(Observable.of(fakeProcessInstances)); componentHandler = jasmine.createSpyObj('componentHandler', [ 'upgradeAllRegistered', @@ -114,34 +93,122 @@ describe('ActivitiProcessInstanceListComponent', () => { component.processDefinitionKey = null; fixture.detectChanges(); tick(); - expect(emitSpy).toHaveBeenCalledWith(fakeGlobalProcesses); + expect(emitSpy).toHaveBeenCalledWith(fakeProcessInstances); })); - it('should return the process instances list', (done) => { + it('should return the process instances list in original order when datalist passed non-existent columns', (done) => { + component.data = new ObjectDataTableAdapter( + [], + [ + {type: 'text', key: 'fake-id', title: 'Name'} + ] + ); component.appId = '1'; component.state = 'open'; component.processDefinitionKey = null; - component.onSuccess.subscribe( (res) => { + component.onSuccess.subscribe((res) => { expect(res).toBeDefined(); expect(component.data).toBeDefined(); expect(component.isListEmpty()).not.toBeTruthy(); expect(component.data.getRows().length).toEqual(2); - expect(component.data.getRows()[0].getValue('name')).toEqual('No name'); + expect(component.data.getRows()[0].getValue('name')).toEqual('Process 773443333'); + expect(component.data.getRows()[1].getValue('name')).toEqual('Process 382927392'); + done(); + }); + fixture.detectChanges(); + }); + + it('should order the process instances by name column when no sort passed', (done) => { + component.appId = '1'; + component.state = 'open'; + component.processDefinitionKey = null; + component.onSuccess.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.data).toBeDefined(); + expect(component.isListEmpty()).not.toBeTruthy(); + expect(component.data.getRows().length).toEqual(2); + expect(component.data.getRows()[0].getValue('name')).toEqual('Process 382927392'); + expect(component.data.getRows()[1].getValue('name')).toEqual('Process 773443333'); + done(); + }); + fixture.detectChanges(); + }); + + it('should order the process instances by descending column when specified', (done) => { + component.appId = '1'; + component.state = 'open'; + component.processDefinitionKey = null; + component.sort = 'name-desc'; + component.onSuccess.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.data).toBeDefined(); + expect(component.isListEmpty()).not.toBeTruthy(); + expect(component.data.getRows().length).toEqual(2); + expect(component.data.getRows()[0].getValue('name')).toEqual('Process 773443333'); + expect(component.data.getRows()[1].getValue('name')).toEqual('Process 382927392'); + done(); + }); + fixture.detectChanges(); + }); + + it('should order the process instances by ascending column when specified', (done) => { + component.appId = '1'; + component.state = 'open'; + component.processDefinitionKey = null; + component.sort = 'started-asc'; + component.onSuccess.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.data).toBeDefined(); + expect(component.isListEmpty()).not.toBeTruthy(); + expect(component.data.getRows().length).toEqual(2); + expect(component.data.getRows()[0].getValue('name')).toEqual('Process 773443333'); + expect(component.data.getRows()[1].getValue('name')).toEqual('Process 382927392'); + done(); + }); + fixture.detectChanges(); + }); + + it('should order the process instances by descending start date when specified', (done) => { + component.appId = '1'; + component.state = 'open'; + component.processDefinitionKey = null; + component.sort = 'started-desc'; + component.onSuccess.subscribe((res) => { + expect(res).toBeDefined(); + expect(component.data).toBeDefined(); + expect(component.isListEmpty()).not.toBeTruthy(); + expect(component.data.getRows().length).toEqual(2); + expect(component.data.getRows()[0].getValue('name')).toEqual('Process 382927392'); + expect(component.data.getRows()[1].getValue('name')).toEqual('Process 773443333'); done(); }); fixture.detectChanges(); }); it('should return the process instances list filtered by processDefinitionKey', (done) => { + let key = 'fakeprocess'; + component.appId = '1'; + component.state = 'open'; + component.processDefinitionKey = key; + component.onSuccess.subscribe((res) => { + let lastCall = getProcessInstancesSpy.calls.mostRecent(); + expect(lastCall).toBeDefined(); + let lastCallArgs = lastCall.args; + expect(lastCallArgs[0]).toBeDefined(); + expect(lastCallArgs[0].processDefinitionKey).toEqual(key); + done(); + }); + fixture.detectChanges(); + }); + + it('should return a default name if no name is specified on the process', (done) => { + getProcessInstancesSpy = getProcessInstancesSpy.and.returnValue(Observable.of(fakeProcessInstancesWithNoName)); component.appId = '1'; component.state = 'open'; component.processDefinitionKey = 'fakeprocess'; component.onSuccess.subscribe( (res) => { - expect(res).toBeDefined(); - expect(component.data).toBeDefined(); - expect(component.isListEmpty()).not.toBeTruthy(); - expect(component.data.getRows().length).toEqual(2); - expect(component.data.getRows()[0].getValue('name')).toEqual('No name'); + expect(component.data.getRows()[0].getValue('name')).toEqual('Fake Process Name - Nov 9, 2017, 12:36:14 PM'); + expect(component.data.getRows()[1].getValue('name')).toEqual('Fake Process Name - Nov 9, 2017, 12:37:25 PM'); done(); }); fixture.detectChanges(); @@ -172,7 +239,7 @@ describe('ActivitiProcessInstanceListComponent', () => { let emitSpy = spyOn(component.onSuccess, 'emit'); component.reload(); tick(); - expect(emitSpy).toHaveBeenCalledWith(fakeGlobalProcesses); + expect(emitSpy).toHaveBeenCalledWith(fakeProcessInstances); })); it('should reload processes when reload() is called', (done) => { @@ -188,7 +255,7 @@ describe('ActivitiProcessInstanceListComponent', () => { expect(component.data).toBeDefined(); expect(component.isListEmpty()).not.toBeTruthy(); expect(component.data.getRows().length).toEqual(2); - expect(component.data.getRows()[1].getValue('name')).toEqual('No name'); + expect(component.data.getRows()[0].getValue('name')).toEqual('Process 773443333'); done(); }); component.reload(); @@ -235,7 +302,7 @@ describe('ActivitiProcessInstanceListComponent', () => { expect(component.data).toBeDefined(); expect(component.isListEmpty()).not.toBeTruthy(); expect(component.data.getRows().length).toEqual(2); - expect(component.data.getRows()[1].getValue('name')).toEqual('No name'); + expect(component.data.getRows()[0].getValue('name')).toEqual('Process 773443333'); done(); }); @@ -251,7 +318,7 @@ describe('ActivitiProcessInstanceListComponent', () => { expect(component.data).toBeDefined(); expect(component.isListEmpty()).not.toBeTruthy(); expect(component.data.getRows().length).toEqual(2); - expect(component.data.getRows()[1].getValue('name')).toEqual('No name'); + expect(component.data.getRows()[0].getValue('name')).toEqual('Process 773443333'); done(); }); @@ -267,7 +334,7 @@ describe('ActivitiProcessInstanceListComponent', () => { expect(component.data).toBeDefined(); expect(component.isListEmpty()).not.toBeTruthy(); expect(component.data.getRows().length).toEqual(2); - expect(component.data.getRows()[1].getValue('name')).toEqual('No name'); + expect(component.data.getRows()[0].getValue('name')).toEqual('Process 773443333'); done(); }); @@ -283,7 +350,7 @@ describe('ActivitiProcessInstanceListComponent', () => { expect(component.data).toBeDefined(); expect(component.isListEmpty()).not.toBeTruthy(); expect(component.data.getRows().length).toEqual(2); - expect(component.data.getRows()[1].getValue('name')).toEqual('No name'); + expect(component.data.getRows()[0].getValue('name')).toEqual('Process 773443333'); done(); }); @@ -314,7 +381,7 @@ describe('ActivitiProcessInstanceListComponent', () => { expect(component.data).toBeDefined(); expect(component.isListEmpty()).not.toBeTruthy(); expect(component.data.getRows().length).toEqual(2); - expect(component.data.getRows()[1].getValue('name')).toEqual('No name'); + expect(component.data.getRows()[0].getValue('name')).toEqual('Process 773443333'); done(); }); diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.ts index d40af83976..426b1aca24 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.ts +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-processlist.component.ts @@ -15,6 +15,7 @@ * limitations under the License. */ +import { DatePipe } from '@angular/common'; import { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core'; import { AlfrescoTranslationService } from 'ng2-alfresco-core'; import { ObjectDataTableAdapter, DataTableAdapter, DataRowEvent, ObjectDataRow, DataSorting } from 'ng2-alfresco-datatable'; @@ -154,7 +155,8 @@ export class ActivitiProcessInstanceListComponent implements OnInit, OnChanges { instancesRows.push(new ObjectDataRow({ id: row.id, name: row.name, - started: row.started + started: row.started, + processDefinitionName: row.processDefinitionName })); }); return instancesRows; @@ -236,12 +238,30 @@ export class ActivitiProcessInstanceListComponent implements OnInit, OnChanges { */ private optimizeNames(instances: any[]) { instances = instances.map(t => { - t.obj.name = t.obj.name || 'No name'; + t.obj.name = this.getProcessNameOrDescription(t.obj, 'medium'); return t; }); return instances; } + getProcessNameOrDescription(processInstance, dateFormat): string { + let name = ''; + if (processInstance) { + name = processInstance.name || + processInstance.processDefinitionName + ' - ' + this.getFormatDate(processInstance.started, dateFormat); + } + return name; + } + + getFormatDate(value, format: string) { + let datePipe = new DatePipe('en-US'); + try { + return datePipe.transform(value, format); + } catch (err) { + return ''; + } + } + private createRequestNode() { let requestNode = { appDefinitionId: this.appId,