diff --git a/ng2-components/ng2-activiti-processlist/README.md b/ng2-components/ng2-activiti-processlist/README.md index 7bb510cfcb..d802be2613 100644 --- a/ng2-components/ng2-activiti-processlist/README.md +++ b/ng2-components/ng2-activiti-processlist/README.md @@ -24,6 +24,7 @@ - [Process Instance Details Header component](#process-instance-details-header-component) * [Properties](#properties-4) * [Events](#events-4) +- [ProcessInstanceModel](#processinstancemodel) - [Process Instance Tasks component](#process-instance-tasks-component) * [Properties](#properties-5) * [Events](#events-5) @@ -239,19 +240,17 @@ This is a sub-component of the process details component, which renders some gen processInstance="localProcessDetails"> ``` +![adf-process-instance-header](docs/assets/adf-process-instance-header-attachment.png) ### Properties | Name | Type| Description | | --- | --- | --- | -| processInstance | string | (**required**): Full details of the process instance to display information about | -| showDiagram | boolean | If the value is true the button show diagram is shown | +| processInstance | [ProcessInstanceModel](https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-activiti-processlist/src/models/process-instance.model.ts) | (**required**): Full details of the process instance to display information about | ### Events -| Name | Description | -| --- | --- | -| showProcessDiagram | Raised when the show diagram button is clicked | +No events ## Process Instance Tasks component diff --git a/ng2-components/ng2-activiti-processlist/docs/assets/adf-process-instance-header-attachment.png b/ng2-components/ng2-activiti-processlist/docs/assets/adf-process-instance-header-attachment.png new file mode 100644 index 0000000000..c6a876471a Binary files /dev/null and b/ng2-components/ng2-activiti-processlist/docs/assets/adf-process-instance-header-attachment.png differ diff --git a/ng2-components/ng2-activiti-processlist/index.ts b/ng2-components/ng2-activiti-processlist/index.ts index 2416c2f9b6..7848f52cca 100644 --- a/ng2-components/ng2-activiti-processlist/index.ts +++ b/ng2-components/ng2-activiti-processlist/index.ts @@ -19,7 +19,7 @@ import { ModuleWithProviders, NgModule } from '@angular/core'; import { MdProgressSpinnerModule } from '@angular/material'; import { ActivitiFormModule } from 'ng2-activiti-form'; import { ActivitiTaskListModule } from 'ng2-activiti-tasklist'; -import { CoreModule } from 'ng2-alfresco-core'; +import { CoreModule, CardViewUpdateService } from 'ng2-alfresco-core'; import { DataTableModule } from 'ng2-alfresco-datatable'; import { CreateProcessAttachmentComponent } from './src/components/create-process-attachment.component'; @@ -106,6 +106,7 @@ export const ACTIVITI_PROCESSLIST_DIRECTIVES: [any] = [ export const ACTIVITI_PROCESSLIST_PROVIDERS: [any] = [ ProcessService, ProcessUploadService, + CardViewUpdateService, // Old Deprecated import ActivitiProcessService diff --git a/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.css b/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.css index 15b522136a..d5af0b0328 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.css +++ b/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.css @@ -2,10 +2,8 @@ width: 100%; } -.activiti-label { - font-weight: bolder; -} - -.activiti-process-header__value { - color: rgb(68, 138, 255); +.adf-card-container { + font-family: inherit; + height: 19em; + padding: 8px; } diff --git a/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.html b/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.html index 8d8aa72980..8cb8c70d01 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.html +++ b/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.html @@ -1,22 +1,5 @@
-
-
- {{ 'DETAILS.LABELS.STARTED_BY' | translate }}: - {{getStartedByFullName()}} -
-
- {{ 'DETAILS.LABELS.STARTED' | translate }}: - {{getFormatDate(processInstance.started, 'medium')}} -
-
- -
-
- {{ 'DETAILS.LABELS.ENDED' | translate }}: - {{getFormatDate(processInstance.ended, 'medium')}} -
- -
+ + +
diff --git a/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.spec.ts b/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.spec.ts index 92d5748b7f..5ceec4d1a4 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.spec.ts +++ b/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.spec.ts @@ -16,21 +16,21 @@ */ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; -import { exampleProcess, processEnded } from './../assets/process.model.mock'; -import { TranslationMock } from './../assets/translation.service.mock'; -import { ProcessInstance } from './../models/process-instance.model'; +import { AlfrescoTranslationService, CardViewUpdateService, CoreModule } from 'ng2-alfresco-core'; +import { Observable } from 'rxjs/Rx'; + +import { ProcessInstance } from '../models/process-instance.model'; +import { exampleProcess } from './../assets/process.model.mock'; import { ProcessService } from './../services/process.service'; import { ProcessCommentsComponent } from './process-comments.component'; import { ProcessInstanceHeaderComponent } from './process-instance-header.component'; describe('ProcessInstanceHeaderComponent', () => { + let service: ProcessService; let componentHandler: any; let component: ProcessInstanceHeaderComponent; let fixture: ComponentFixture; - let element: HTMLElement; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -43,16 +43,20 @@ describe('ProcessInstanceHeaderComponent', () => { ], providers: [ ProcessService, - {provide: AlfrescoTranslationService, useClass: TranslationMock} + CardViewUpdateService ] }).compileComponents(); + + let translateService = TestBed.get(AlfrescoTranslationService); + spyOn(translateService, 'addTranslationFolder').and.stub(); + spyOn(translateService.translate, 'get').and.callFake((key) => { return Observable.of(key); }); })); beforeEach(() => { fixture = TestBed.createComponent(ProcessInstanceHeaderComponent); component = fixture.componentInstance; - element = fixture.nativeElement; + service = TestBed.get(ProcessService); component.processInstance = new ProcessInstance(exampleProcess); @@ -63,71 +67,97 @@ describe('ProcessInstanceHeaderComponent', () => { window['componentHandler'] = componentHandler; }); - it('should render empty component if no form details provided', () => { + it('should render empty component if no process details provided', () => { component.processInstance = undefined; fixture.detectChanges(); expect(fixture.debugElement.children.length).toBe(0); }); - it('should display started by user', () => { + it('should display status as running when process is not complete', () => { + component.processInstance.ended = null; + component.ngOnChanges({}); 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'); + let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-status"]'); + expect(valueEl.innerText).toBe('Running'); }); - it('should display empty started by user if user unknown', () => { - component.processInstance.startedBy = null; + it('should display status as completed when process is complete', () => { + component.processInstance.ended = '2016-11-03'; + component.ngOnChanges({}); 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(''); + let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-status"]'); + expect(valueEl.innerText).toBe('Completed'); }); - it('should display process start date', () => { - component.processInstance.started = '2016-11-10T03:37:30.010+0000'; + it('should display due date', () => { + component.processInstance.ended = '2016-11-03'; + component.ngOnChanges({}); 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'); + let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-dateitem-dueDate"]'); + expect(valueEl.innerText).toBe('Nov 03 2016'); }); - it('should display ended date if process is ended', () => { - component.processInstance.ended = '2016-11-10T03:37:30.010+0000'; + it('should display placeholder if no due date', () => { + component.processInstance.ended = null; + component.ngOnChanges({}); 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'); + let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-dateitem-dueDate"]'); + expect(valueEl.innerText).toBe('No date'); }); - it('should render the button show diagram as default', () => { + it('should display process category', () => { + component.processInstance.processDefinitionCategory = 'Accounts'; + component.ngOnChanges({}); fixture.detectChanges(); - let formValueEl = fixture.debugElement.query(By.css('[data-automation-id="header-show-diagram"]')); - expect(formValueEl).not.toBeNull(); + let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-category"]'); + expect(valueEl.innerText).toBe('Accounts'); }); - it('should render the button show diagram enabled as default', () => { + it('should display placeholder if no process category', () => { + component.processInstance.processDefinitionCategory = null; + component.ngOnChanges({}); fixture.detectChanges(); - let showButton: HTMLButtonElement = element.querySelector('#show-diagram-button'); - expect(showButton).toBeDefined(); - expect(showButton.disabled).toBeFalsy(); + let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-category"]'); + expect(valueEl.innerText).toBe('No category'); }); - it('should render the button show diagram disabled', () => { - component.processInstance = new ProcessInstance(processEnded); + it('should display created date', () => { + component.processInstance.started = '2016-11-03'; + component.ngOnChanges({}); fixture.detectChanges(); - fixture.whenStable().then(() => { - let showButton: HTMLButtonElement = element.querySelector('#show-diagram-button'); - expect(showButton).toBeDefined(); - expect(showButton.disabled).toBeTruthy(); - }); + let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-dateitem-created"]'); + expect(valueEl.innerText).toBe('Nov 03 2016'); }); - it('should NOT render the button show diagram is the property showDiagram is false', () => { - component.showDiagram = false; + it('should display started by', () => { + component.processInstance.startedBy = {firstName: 'Admin', lastName: 'User'}; + component.ngOnChanges({}); fixture.detectChanges(); - let formValueEl = fixture.debugElement.query(By.css('[data-automation-id="header-show-pippo"]')); - expect(formValueEl).toBeNull(); + let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-assignee"]'); + expect(valueEl.innerText).toBe('Admin User'); }); + it('should display process instance id', () => { + component.processInstance.id = '123'; + component.ngOnChanges({}); + fixture.detectChanges(); + let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-id"]'); + expect(valueEl.innerText).toBe('123'); + }); + + it('should display description', () => { + component.processInstance.processDefinitionDescription = 'Test process'; + component.ngOnChanges({}); + fixture.detectChanges(); + let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-description"]'); + expect(valueEl.innerText).toBe('Test process'); + }); + + it('should display placeholder if no description', () => { + component.processInstance.processDefinitionDescription = null; + component.ngOnChanges({}); + fixture.detectChanges(); + let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-description"]'); + expect(valueEl.innerText).toBe('No description'); + }); }); diff --git a/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.ts b/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.ts index 7dfceac75b..c14cfa1974 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.ts +++ b/ng2-components/ng2-activiti-processlist/src/components/process-instance-header.component.ts @@ -15,9 +15,8 @@ * limitations under the License. */ -import { DatePipe } from '@angular/common'; -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core'; +import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { AlfrescoTranslationService, CardViewDateItemModel, CardViewItem, CardViewTextItemModel, LogService } from 'ng2-alfresco-core'; import { ProcessInstance } from '../models/process-instance.model'; declare let componentHandler: any; @@ -27,19 +26,12 @@ declare let componentHandler: any; templateUrl: './process-instance-header.component.html', styleUrls: ['./process-instance-header.component.css'] }) -export class ProcessInstanceHeaderComponent { - - @Input() - showDiagram: boolean = true; +export class ProcessInstanceHeaderComponent implements OnChanges { @Input() processInstance: ProcessInstance; - @Output() - onError: EventEmitter = new EventEmitter(); - - @Output() - showProcessDiagram: EventEmitter = new EventEmitter(); + properties: CardViewItem []; constructor(private translate: AlfrescoTranslationService, private logService: LogService) { @@ -49,37 +41,47 @@ export class ProcessInstanceHeaderComponent { } } - getStartedByFullName(): string { - 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 ''; + ngOnChanges(changes: SimpleChanges) { + this.refreshData(); } - 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}`); + refreshData() { + if (this.processInstance) { + this.properties = [ + new CardViewTextItemModel({label: 'Status:', value: this.getProcessStatus(), key: 'status'}), + new CardViewDateItemModel({label: 'Due Date:', value: this.processInstance.ended, format: 'MMM DD YYYY', key: 'dueDate', default: 'No date'}), + new CardViewTextItemModel({label: 'Category:', value: this.processInstance.processDefinitionCategory, key: 'category', default: 'No category'}), + new CardViewTextItemModel( + { + label: 'Created By:', + value: this.getStartedByFullName(), + key: 'assignee', + default: 'No assignee' + }), + new CardViewDateItemModel({label: 'Created:', value: this.processInstance.started, format: 'MMM DD YYYY', key: 'created'}), + new CardViewTextItemModel({label: 'Id:', value: this.processInstance.id, key: 'id'}), + new CardViewTextItemModel({label: 'Description:', value: this.processInstance.processDefinitionDescription, key: 'description', default: 'No description'}) + ]; } } + getProcessStatus(): string { + if (this.processInstance) { + return this.isRunning() ? 'Running' : 'Completed'; + } + } + + getStartedByFullName(): string { + let fullName = ''; + if (this.processInstance && this.processInstance.startedBy) { + fullName += this.processInstance.startedBy.firstName || ''; + fullName += fullName ? ' ' : ''; + fullName += this.processInstance.startedBy.lastName || ''; + } + return fullName; + } + isRunning(): boolean { return this.processInstance && !this.processInstance.ended; } - - isDiagramDisabled(): boolean { - return !this.isRunning() ? true : undefined; - } - - showDiagramEvent() { - this.showProcessDiagram.emit({value: this.processInstance.id}); - } - - isShowDiagram(): boolean { - return this.showDiagram; - } }