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 3bd65059d7..a8ea49a6dd 100644
--- a/demo-shell-ng2/app/components/activiti/activiti-demo.component.html
+++ b/demo-shell-ng2/app/components/activiti/activiti-demo.component.html
@@ -74,6 +74,17 @@
(taskDeleted)="onTaskDeleted($event)">
+ Task Audit log
+
+
+ Download
+
+ 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-tasklist/docs/assets/adf-task-audit-directive.png b/ng2-components/ng2-activiti-tasklist/docs/assets/adf-task-audit-directive.png
new file mode 100644
index 0000000000..acf07e2c4a
Binary files /dev/null and b/ng2-components/ng2-activiti-tasklist/docs/assets/adf-task-audit-directive.png differ
diff --git a/ng2-components/ng2-activiti-tasklist/index.ts b/ng2-components/ng2-activiti-tasklist/index.ts
index b98e003e70..917202478c 100644
--- a/ng2-components/ng2-activiti-tasklist/index.ts
+++ b/ng2-components/ng2-activiti-tasklist/index.ts
@@ -38,6 +38,7 @@ import { PeopleComponent } from './src/components/people.component';
import { StartTaskComponent } from './src/components/start-task.component';
import { TaskAttachmentListComponent } from './src/components/task-attachment-list.component';
import { TaskDetailsComponent } from './src/components/task-details.component';
+import { TaskAuditDirective } from './src/components/task-audit.directive';
import { TaskFiltersComponent } from './src/components/task-filters.component';
import { TaskHeaderComponent } from './src/components/task-header.component';
import { TaskListComponent } from './src/components/tasklist.component';
@@ -52,6 +53,7 @@ export {TaskHeaderComponent } from './src/components/task-header.component';
export {NoTaskDetailsTemplateDirective } from './src/components/no-task-detail-template.directive';
export {TaskFiltersComponent } from './src/components/task-filters.component';
export {TaskDetailsComponent } from './src/components/task-details.component';
+export {TaskAuditDirective } from './src/components/task-audit.directive';
export {StartTaskComponent } from './src/components/start-task.component';
export {PeopleSearchComponent } from './src/components/people-search.component';
export {AttachmentComponent } from './src/components/create-task-attachment.component';
@@ -109,6 +111,7 @@ export const ACTIVITI_TASKLIST_DIRECTIVES: any[] = [
TaskFiltersComponent,
TaskListComponent,
TaskDetailsComponent,
+ TaskAuditDirective,
ChecklistComponent,
CommentsComponent,
PeopleComponent,
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/task-audit.directive.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/task-audit.directive.spec.ts
new file mode 100644
index 0000000000..341df401cb
--- /dev/null
+++ b/ng2-components/ng2-activiti-tasklist/src/components/task-audit.directive.spec.ts
@@ -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 { Component } from '@angular/core';
+import {
+ async,
+ ComponentFixture,
+ fakeAsync,
+ TestBed
+} from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { CoreModule } from 'ng2-alfresco-core';
+import { Observable } from 'rxjs/Rx';
+import { TaskListService } from './../services/tasklist.service';
+import { TaskAuditDirective } from './task-audit.directive';
+
+declare let jasmine: any;
+
+describe('TaskAuditDirective', () => {
+
+ let fixture: ComponentFixture;
+ let component: BasicButtonComponent;
+ let auditDirective: TaskAuditDirective;
+ let service: TaskListService;
+
+ 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, TaskAuditDirective],
+ providers: [TaskListService]
+ });
+
+ TestBed.compileComponents();
+
+ fixture = TestBed.createComponent(BasicButtonComponent);
+ component = fixture.componentInstance;
+ service = TestBed.get(TaskListService);
+
+ 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, 'fetchTaskAuditPdfById').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 = { taskId: '77', taskName: 'Fake Task Naem', assignee: 'FirstName LastName', formData: [], selectedOutcome: null, comments: [] };
+ spyOn(service, 'fetchTaskAuditJsonById').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, 'fetchTaskAuditPdfById').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-tasklist/src/components/task-audit.directive.ts b/ng2-components/ng2-activiti-tasklist/src/components/task-audit.directive.ts
new file mode 100644
index 0000000000..d08e584802
--- /dev/null
+++ b/ng2-components/ng2-activiti-tasklist/src/components/task-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 { TaskListService } from './../services/tasklist.service';
+
+const JSON_FORMAT: string = 'json';
+const PDF_FORMAT: string = 'pdf';
+
+@Directive({
+ selector: 'button[adf-task-audit]',
+ host: {
+ 'role': 'button',
+ '(click)': 'onClickAudit()'
+ }
+})
+export class TaskAuditDirective implements OnInit, OnChanges {
+
+ @Input('task-id')
+ taskId: 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 taskListService
+ */
+ constructor(private contentService: ContentService,
+ private taskListService: TaskListService) {
+ }
+
+ 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.taskListService.fetchTaskAuditPdfById(this.taskId).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.taskListService.fetchTaskAuditJsonById(this.taskId).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-tasklist/src/services/tasklist.service.ts b/ng2-components/ng2-activiti-tasklist/src/services/tasklist.service.ts
index d2c110d80f..8eec2d7443 100644
--- a/ng2-components/ng2-activiti-tasklist/src/services/tasklist.service.ts
+++ b/ng2-components/ng2-activiti-tasklist/src/services/tasklist.service.ts
@@ -398,6 +398,24 @@ export class TaskListService {
.catch(err => this.handleError(err));
}
+ /**
+ * fetch the Task Audit information as a pdf
+ * @param taskId - the task id
+ */
+ fetchTaskAuditPdfById(taskId: string): Observable {
+ return Observable.fromPromise(this.apiService.getInstance().activiti.taskApi.getTaskAuditPdf(taskId))
+ .catch(err => this.handleError(err));
+ }
+
+ /**
+ * fetch the Task Audit information in a json format
+ * @param taskId - the task id
+ */
+ fetchTaskAuditJsonById(taskId: string): Observable {
+ return Observable.fromPromise(this.apiService.getInstance().activiti.taskApi.getTaskAuditJson(taskId))
+ .catch(err => this.handleError(err));
+ }
+
private callApiTasksFiltered(requestNode: TaskQueryRequestRepresentationModel) {
return this.apiService.getInstance().activiti.taskApi.listTasks(requestNode);
}