diff --git a/demo-shell-ng2/app/components/activiti/activiti-demo.component.html b/demo-shell-ng2/app/components/activiti/activiti-demo.component.html
index 022f38e635..b8e2a99653 100644
--- a/demo-shell-ng2/app/components/activiti/activiti-demo.component.html
+++ b/demo-shell-ng2/app/components/activiti/activiti-demo.component.html
@@ -162,6 +162,18 @@
(taskClick)="onProcessDetailsTaskClick($event)">
+
+ Process Audit log
+
+
+
+ assignment_ind
+
+```
+
+
+
+### Properties
+
+| Name | Type | Default | Description |
+| --- | --- | --- | --- |
+| taskId | string | | (**required**) The id of the task. |
+| format | string | pdf | In whitch format you want the task audit information (pdf or json). |
+| download | boolean | false | True If you want download the file on the click event. |
+| fileName | string | Audit | Represent the name of the file to download in case the format is pdf. |
+
+#### Events
+
+| Name | Description |
+| --- | --- |
+| clicked | Raised when the task audit info is ready |
+| error | Raised if there is an error during fetching task information |
+
## Build from sources
You can build component from sources with the following commands:
diff --git a/ng2-components/ng2-activiti-processlist/docs/assets/adf-process-audit-directive.png b/ng2-components/ng2-activiti-processlist/docs/assets/adf-process-audit-directive.png
new file mode 100644
index 0000000000..720d164b65
Binary files /dev/null and b/ng2-components/ng2-activiti-processlist/docs/assets/adf-process-audit-directive.png differ
diff --git a/ng2-components/ng2-activiti-processlist/index.ts b/ng2-components/ng2-activiti-processlist/index.ts
index 5dd5af071b..13caa3ef86 100644
--- a/ng2-components/ng2-activiti-processlist/index.ts
+++ b/ng2-components/ng2-activiti-processlist/index.ts
@@ -32,6 +32,7 @@ import { ProcessAttachmentListComponent } from './src/components/process-attachm
import { ProcessCommentsComponent } from './src/components/process-comments.component';
import { ProcessFiltersComponent } from './src/components/process-filters.component';
import { ProcessInstanceDetailsComponent } from './src/components/process-instance-details.component';
+import { ProcessAuditDirective } from './src/components/process-audit.directive';
import { ProcessInstanceHeaderComponent } from './src/components/process-instance-header.component';
import { ProcessInstanceTasksComponent } from './src/components/process-instance-tasks.component';
import { ProcessInstanceVariablesComponent } from './src/components/process-instance-variables.component';
@@ -41,6 +42,7 @@ export {ProcessAttachmentListComponent} from './src/components/process-attachmen
export {ProcessCommentsComponent} from './src/components/process-comments.component';
export {ProcessFiltersComponent} from './src/components/process-filters.component';
export {ProcessInstanceDetailsComponent} from './src/components/process-instance-details.component';
+export {ProcessAuditDirective} from './src/components/process-audit.directive';
export {ProcessInstanceHeaderComponent} from './src/components/process-instance-header.component';
export {ProcessInstanceTasksComponent} from './src/components/process-instance-tasks.component';
export {ProcessInstanceVariablesComponent} from './src/components/process-instance-variables.component';
@@ -87,6 +89,7 @@ export const ACTIVITI_PROCESSLIST_DIRECTIVES: [any] = [
ProcessInstanceListComponent,
ProcessFiltersComponent,
ProcessInstanceDetailsComponent,
+ ProcessAuditDirective,
ProcessInstanceHeaderComponent,
ProcessInstanceTasksComponent,
ProcessInstanceVariablesComponent,
diff --git a/ng2-components/ng2-activiti-processlist/src/components/process-audit.directive.spec.ts b/ng2-components/ng2-activiti-processlist/src/components/process-audit.directive.spec.ts
new file mode 100644
index 0000000000..ba369c664c
--- /dev/null
+++ b/ng2-components/ng2-activiti-processlist/src/components/process-audit.directive.spec.ts
@@ -0,0 +1,178 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Component } from '@angular/core';
+import {
+ async,
+ ComponentFixture,
+ fakeAsync,
+ TestBed
+} from '@angular/core/testing';
+import { CoreModule } from 'ng2-alfresco-core';
+import { Observable } from 'rxjs/Rx';
+import { ProcessService } from './../services/process.service';
+import { ProcessAuditDirective } from './process-audit.directive';
+
+declare let jasmine: any;
+
+describe('ProcessAuditDirective', () => {
+
+ let fixture: ComponentFixture;
+ let component: BasicButtonComponent;
+ let service: ProcessService;
+
+ function createFakePdfBlob(): Blob {
+ let pdfData = atob(
+ 'JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwog' +
+ 'IC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAv' +
+ 'TWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0K' +
+ 'Pj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAg' +
+ 'L1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+' +
+ 'PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9u' +
+ 'dAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2Jq' +
+ 'Cgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJU' +
+ 'CjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVu' +
+ 'ZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4g' +
+ 'CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw' +
+ 'MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v' +
+ 'dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G');
+ return new Blob([pdfData], {type: 'application/pdf'});
+ }
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [CoreModule.forRoot()],
+ declarations: [BasicButtonComponent, ProcessAuditDirective],
+ providers: [ProcessService]
+ });
+
+ TestBed.compileComponents();
+
+ fixture = TestBed.createComponent(BasicButtonComponent);
+ component = fixture.componentInstance;
+ service = TestBed.get(ProcessService);
+
+ jasmine.Ajax.install();
+ }));
+
+ afterEach(() => {
+ jasmine.Ajax.uninstall();
+ });
+
+ it('should fetch the pdf Blob when the format is pdf', fakeAsync(() => {
+ component.fileName = 'FakeAuditName';
+ component.format = 'pdf';
+ let blob = createFakePdfBlob();
+ spyOn(service, 'fetchProcessAuditPdfById').and.returnValue(Observable.of(blob));
+ spyOn(component, 'onAuditClick').and.callThrough();
+
+ fixture.detectChanges();
+
+ let button = fixture.nativeElement.querySelector('#auditButton');
+
+ fixture.whenStable().then(() => {
+ fixture.detectChanges();
+ expect(component.onAuditClick).toHaveBeenCalledWith({ format: 'pdf', value: blob, fileName: 'FakeAuditName' });
+ });
+
+ button.click();
+
+ }));
+
+ it('should fetch the json info when the format is json', fakeAsync(() => {
+ component.fileName = 'FakeAuditName';
+ component.format = 'json';
+ component.download = true;
+ const auditJson = {
+ processInstanceId: 42516, processInstanceName: 'Fake Process - August 3rd 2017',
+ processDefinitionName: 'Claim Approval Process', processDefinitionVersion: 1, processInstanceStartTime: 'Thu Aug 03 15:32:47 UTC 2017', processInstanceEndTime: null,
+ processInstanceDurationInMillis: null,
+ processInstanceInitiator: 'MyName MyLastname',
+ entries: [{
+ index: 1, type: 'startForm',
+ selectedOutcome: null, formData: [{
+ fieldName: 'User Name',
+ fieldId: 'username', value: 'dsassd'
+ },
+ { fieldName: 'Claim Amount', fieldId: 'claimamount', value: '22' }], taskName: null, taskAssignee: null, activityId: null,
+ activityName: null, activityType: null, startTime: null, endTime: null, durationInMillis: null
+ }
+ ], decisionInfo: { calculatedValues: [], appliedRules: [] }
+ };
+ spyOn(service, 'fetchProcessAuditJsonById').and.returnValue(Observable.of(auditJson));
+ spyOn(component, 'onAuditClick').and.callThrough();
+
+ fixture.detectChanges();
+
+ let button = fixture.nativeElement.querySelector('#auditButton');
+
+ fixture.whenStable().then(() => {
+ fixture.detectChanges();
+ expect(component.onAuditClick).toHaveBeenCalledWith({ format: 'json', value: auditJson, fileName: 'FakeAuditName' });
+ });
+
+ button.click();
+
+ }));
+
+ it('should fetch the pdf Blob as default when the format is UNKNOW', fakeAsync(() => {
+ component.fileName = 'FakeAuditName';
+ component.format = 'fakeFormat';
+ let blob = createFakePdfBlob();
+ spyOn(service, 'fetchProcessAuditPdfById').and.returnValue(Observable.of(blob));
+ spyOn(component, 'onAuditClick').and.callThrough();
+
+ fixture.detectChanges();
+
+ let button = fixture.nativeElement.querySelector('#auditButton');
+
+ fixture.whenStable().then(() => {
+ fixture.detectChanges();
+ expect(component.onAuditClick).toHaveBeenCalledWith({ format: 'pdf', value: blob, fileName: 'FakeAuditName' });
+ });
+
+ button.click();
+
+ }));
+
+});
+
+@Component({
+ selector: 'adf-basic-button',
+ template: `
+ `
+})
+class BasicButtonComponent {
+
+ download: boolean = false;
+ fileName: string;
+ format: string;
+ constructor() {
+
+ }
+
+ onAuditClick(event: any) {
+ console.log(event);
+ }
+}
diff --git a/ng2-components/ng2-activiti-processlist/src/components/process-audit.directive.ts b/ng2-components/ng2-activiti-processlist/src/components/process-audit.directive.ts
new file mode 100644
index 0000000000..ce4f6f4edb
--- /dev/null
+++ b/ng2-components/ng2-activiti-processlist/src/components/process-audit.directive.ts
@@ -0,0 +1,123 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Directive, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
+import { ContentService } from 'ng2-alfresco-core';
+import { ProcessService } from './../services/process.service';
+
+const JSON_FORMAT: string = 'json';
+const PDF_FORMAT: string = 'pdf';
+
+@Directive({
+ selector: 'button[adf-process-audit]',
+ host: {
+ 'role': 'button',
+ '(click)': 'onClickAudit()'
+ }
+})
+export class ProcessAuditDirective implements OnInit, OnChanges {
+
+ @Input('process-id')
+ processId: string;
+
+ @Input()
+ fileName: string = 'Audit';
+
+ @Input()
+ format: string = 'pdf';
+
+ @Input()
+ download: boolean = true;
+
+ @Output()
+ clicked: EventEmitter = new EventEmitter();
+
+ @Output()
+ error: EventEmitter = new EventEmitter();
+
+ public audit: any;
+
+ /**
+ *
+ * @param translateService
+ * @param processListService
+ */
+ constructor(private contentService: ContentService,
+ private processListService: ProcessService) {
+ }
+
+ ngOnInit() {
+ console.log('OnInit');
+ }
+ ngOnChanges(changes: SimpleChanges): void {
+ if (!this.isValidType()) {
+ this.setDefaultFormatType();
+ }
+ }
+
+ isValidType() {
+ if (this.format && (this.isJsonFormat() || this.isPdfFormat())) {
+ return true;
+ }
+ return false;
+ }
+
+ setDefaultFormatType(): void {
+ this.format = PDF_FORMAT;
+ }
+
+ /**
+ * fetch the audit information in the requested format
+ */
+ fetchAuditInfo(): void {
+ if (this.isPdfFormat()) {
+ this.processListService.fetchProcessAuditPdfById(this.processId).subscribe(
+ (blob: Blob) => {
+ this.audit = blob;
+ if (this.download) {
+ this.contentService.downloadBlob(this.audit, this.fileName + '.pdf');
+ }
+ this.clicked.emit({ format: this.format, value: this.audit, fileName: this.fileName });
+ },
+ (err) => {
+ this.error.emit(err);
+ });
+ } else {
+ this.processListService.fetchProcessAuditJsonById(this.processId).subscribe(
+ (res) => {
+ this.audit = res;
+ this.clicked.emit({ format: this.format, value: this.audit, fileName: this.fileName });
+ },
+ (err) => {
+ this.error.emit(err);
+ });
+ }
+ }
+
+ onClickAudit() {
+ this.fetchAuditInfo();
+ }
+
+ isJsonFormat() {
+ return this.format === JSON_FORMAT;
+ }
+
+ isPdfFormat() {
+ return this.format === PDF_FORMAT;
+ }
+
+}
diff --git a/ng2-components/ng2-activiti-processlist/src/services/process.service.ts b/ng2-components/ng2-activiti-processlist/src/services/process.service.ts
index c06570aed2..46724367eb 100644
--- a/ng2-components/ng2-activiti-processlist/src/services/process.service.ts
+++ b/ng2-components/ng2-activiti-processlist/src/services/process.service.ts
@@ -90,6 +90,24 @@ export class ProcessService extends TaskListService {
}).catch(err => this.handleProcessError(err));
}
+ /**
+ * fetch the Process Audit information as a pdf
+ * @param processId - the process id
+ */
+ fetchProcessAuditPdfById(processId: string): Observable {
+ return Observable.fromPromise(this.alfrescoApiService.getInstance().activiti.processApi.getProcessAuditPdf(processId))
+ .catch(err => this.handleProcessError(err));
+ }
+
+ /**
+ * fetch the Process Audit information in a json format
+ * @param processId - the process id
+ */
+ fetchProcessAuditJsonById(processId: string): Observable {
+ return Observable.fromPromise(this.alfrescoApiService.getInstance().activiti.processApi.getProcessAuditJson(processId))
+ .catch(err => this.handleProcessError(err));
+ }
+
/**
* Create and return the default filters
* @param appId