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 + +``` + +![adf-task-audit-directive](docs/assets/adf-task-audit-directive.png) + +### 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); }