[ADF-1711] The <adf-task-attachment-list component displays drag-and-drop area that is not working (#2658)

* [ADF-1711] The <adf-task-attachment-list component displays drag-and-drop area that is not working

* Made the drag and drop area working in demo shell for task attachment

* Provided a way to pass custom no content template for drag and drop to the user

* Updated the task-attachment README file for the user to know how to use drag and drop component with task-attachment component

* [ADF-1711] The <adf-task-attachment-list component displays drag-and-drop area that is not working

* Made the drag and drop area working in demo shell for task attachment

* Provided a way to pass custom no content template for drag and drop to the user

* Updated the task-attachment README file for the user to know how to use drag and drop component with task-attachment component
This commit is contained in:
madhukar23 2017-11-21 16:03:56 +05:30 committed by Eugenio Romano
parent bf6d0284e0
commit aa8b2a28f3
8 changed files with 167 additions and 76 deletions

View File

@ -85,10 +85,20 @@
</div>
<mat-card>
<mat-card-content>
<adf-task-attachment-list
[taskId]="currentTaskId"
(attachmentClick)="onContentClick($event)">
</adf-task-attachment-list>
<adf-upload-drag-area
[parentId]="currentTaskId"
[showNotificationBar]="false">
<adf-task-attachment-list #taskAttachList
[taskId]="currentTaskId">
<div adf-empty-list>
<div adf-empty-list-header class="adf-empty-list-header"> {{'ADF_TASK_LIST.ATTACHMENT.EMPTY.HEADER' | translate}} </div>
<div adf-empty-list-body>
<div fxHide.lt-md="true" class="adf-empty-list-drag_drop">{{'ADF_TASK_LIST.ATTACHMENT.EMPTY.DRAG-AND-DROP.TITLE' | translate}}</div>
<div fxHide.lt-md="true" class="adf-empty-list__any-files-here-to-add"> {{'ADF_TASK_LIST.ATTACHMENT.EMPTY.DRAG-AND-DROP.SUBTITLE' | translate}} </div>
</div>
</div>
</adf-task-attachment-list>
</adf-upload-drag-area>
</mat-card-content>
</mat-card>
</div>

View File

@ -49,10 +49,12 @@ import {
TaskDetailsEvent,
TaskFiltersComponent,
TaskListComponent,
TaskListService
TaskListService,
TaskAttachmentListComponent,
ProcessUploadService
} from '@alfresco/adf-process-services';
import { LogService } from '@alfresco/adf-core';
import { AlfrescoApiService } from '@alfresco/adf-core';
import { AlfrescoApiService, UploadService } from '@alfresco/adf-core';
import {
DataSorting,
ObjectDataRow,
@ -69,6 +71,9 @@ const currentTaskIdNew = '__NEW__';
selector: 'adf-activiti',
templateUrl: './activiti.component.html',
styleUrls: ['./activiti.component.scss'],
providers: [
{ provide: UploadService, useClass: ProcessUploadService }
],
encapsulation: ViewEncapsulation.None
})
export class ActivitiComponent implements AfterViewInit, OnDestroy, OnInit {
@ -79,6 +84,9 @@ export class ActivitiComponent implements AfterViewInit, OnDestroy, OnInit {
@ViewChild(TaskListComponent)
taskList: TaskListComponent;
@ViewChild(TaskAttachmentListComponent)
taskAttachList: TaskAttachmentListComponent;
@ViewChild(ProcessFiltersComponent)
activitiprocessfilter: ProcessFiltersComponent;
@ -147,7 +155,8 @@ export class ActivitiComponent implements AfterViewInit, OnDestroy, OnInit {
private apiService: AlfrescoApiService,
private logService: LogService,
formRenderingService: FormRenderingService,
formService: FormService) {
formService: FormService,
private uploadService: UploadService) {
this.dataTasks = new ObjectDataTableAdapter();
this.dataTasks.setSorting(new DataSorting('created', 'desc'));
@ -247,6 +256,7 @@ export class ActivitiComponent implements AfterViewInit, OnDestroy, OnInit {
this.currentProcessInstanceId = null;
});
this.layoutType = AppsListComponent.LAYOUT_GRID;
this.uploadService.fileUploadComplete.subscribe(value => this.onTaskFileUploadComplete(value.data));
}
@ -480,4 +490,8 @@ export class ActivitiComponent implements AfterViewInit, OnDestroy, OnInit {
this.taskList.reload();
this.currentTaskId = null;
}
onTaskFileUploadComplete(content: any) {
this.taskAttachList.add(content);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -1,6 +1,6 @@
# Task Attachment List Component
Displays attached documents on a specified task
Displays attached documents on a specified task.
![task-attachment-list-sample](docassets/images/task-attachment-list.png)
@ -9,6 +9,7 @@ Displays attached documents on a specified task
<!-- toc -->
- [Basic Usage](#basic-usage)
* [Drag and Drop Functionality](#how-to-add-drag-and-drop-functionality)
* [Properties](#properties)
* [Events](#events)
@ -24,6 +25,38 @@ Displays attached documents on a specified task
(attachmentClick)="YOUR_HANDLER">
</adf-task-attachment-list>
```
If the List is empty, a default no content template is displayed.
![default-no-content-template-sample](docassets/images/default-no-content-template.png)
### How to Add Drag and Drop Functionality
If we want user to be able to upload attachments for empty lists, We can wrap our component with upload drag area component. In that case, We should also pass a custom *no content template* as shown below with our component urging the user to drag files to upload whenever the list is empty.
```html
<adf-upload-drag-area
[parentId]="YOUR_TASK_ID"
[showNotificationBar]="BOOLEAN">
<adf-task-attachment-list
[taskId]="YOUR_TASK_ID"
(attachmentClick)="YOUR_HANDLER">
<div adf-empty-list> //no content template
<adf-empty-list>
<div adf-empty-list-header>{{This List is empty}}</div>
<div adf-empty-list-body>{{Drag and drop to upload}}</div>
<div adf-empty-list-footer>
<img [src]="Your custom image URL"></div>
</adf-empty-list>
</div>
</adf-task-attachment-list>
</adf-upload-drag-area>
```
[Upload Drag Area Component](./upload-drag-area.component.md)
If the List is empty, the custom no-content template we passed is displayed.
![custom-no-content-drag-drop-template-sample](docassets/images/custom-no-content-drag-drop-template.png)
### Properties

View File

@ -1,25 +1,29 @@
<adf-datatable [rows]="attachments" [actions]="true" [loading]="isLoading" (rowDblClick)="openContent($event)" (showRowActionsMenu)="onShowRowActionsMenu($event)"
(executeRowAction)="onExecuteRowAction($event)">
<adf-empty-list *ngIf="isEmpty()">
<div adf-empty-list-header class="adf-empty-list-header"> {{'ADF_TASK_LIST.ATTACHMENT.EMPTY.HEADER' | translate}} </div>
<div adf-empty-list-body *ngIf="!isDisabled()">
<div fxHide.lt-md="true" class="adf-empty-list-drag_drop">{{'ADF_TASK_LIST.ATTACHMENT.EMPTY.DRAG-AND-DROP.TITLE' | translate}}</div>
<div fxHide.lt-md="true" class="adf-empty-list__any-files-here-to-add"> {{'ADF_TASK_LIST.ATTACHMENT.EMPTY.DRAG-AND-DROP.SUBTITLE' | translate}} </div>
</div>
<div adf-empty-list-footer *ngIf="!isDisabled()">
<img class="adf-empty-list__empty_doc_lib" [src]="emptyListImageUrl">
</div>
</adf-empty-list>
<data-columns>
<data-column key="icon" type="image" srTitle="ADF_TASK_LIST.PROPERTIES.THUMBNAIL" [sortable]="false"></data-column>
<data-column key="name" type="text" title="ADF_TASK_LIST.PROPERTIES.NAME" class="full-width ellipsis-cell" [sortable]="true"></data-column>
<data-column key="created" type="date" format="shortDate" title="ADF_TASK_LIST.PROPERTIES.CREATED"></data-column>
</data-columns>
<loading-content-template>
<ng-template>
<!--Add your custom loading template here-->
<mat-progress-spinner class="adf-attachment-list-loading-margin" [color]="'primary'" [mode]="'indeterminate'">
</mat-progress-spinner>
</ng-template>
</loading-content-template>
<adf-datatable [rows]="attachments"
[actions]="true"
[loading]="isLoading"
(rowDblClick)="openContent($event)"
(showRowActionsMenu)="onShowRowActionsMenu($event)"
(executeRowAction)="onExecuteRowAction($event)">
<adf-empty-list *ngIf="isEmpty()">
<div adf-empty-list-header class="adf-empty-list-header" *ngIf="!isCustomTemplateDefined()">
{{'ADF_TASK_LIST.ATTACHMENT.EMPTY.HEADER' | translate}}
</div>
<div *ngIf="!isDisabled()" #customEmptyListTemplate class="adf-custom-empty-template">
<ng-content select="[adf-empty-list]"></ng-content>
</div>
</adf-empty-list>
<data-columns>
<data-column key="icon" type="icon" srTitle="ADF_TASK_LIST.PROPERTIES.THUMBNAIL" [sortable]="false"></data-column>
<data-column key="name" type="text" title="ADF_TASK_LIST.PROPERTIES.NAME" class="full-width ellipsis-cell" [sortable]="true"></data-column>
<data-column key="created" type="date" format="shortDate" title="ADF_TASK_LIST.PROPERTIES.CREATED"></data-column>
</data-columns>
<loading-content-template>
<ng-template>
<!--Add your custom loading template here-->
<mat-progress-spinner class="adf-attachment-list-loading-margin" [color]="'primary'" [mode]="'indeterminate'">
</mat-progress-spinner>
</ng-template>
</loading-content-template>
</adf-datatable>

View File

@ -141,7 +141,54 @@ describe('TaskAttachmentList', () => {
});
}));
it('should display all actions if attachements are not read only', () => {
it('emit document when a user wants to view the document', () => {
component.emitDocumentContent(mockAttachment.data[1]);
fixture.detectChanges();
expect(getFileRawContentSpy).toHaveBeenCalled();
});
it('download document when a user wants to view the document', () => {
component.downloadContent(mockAttachment.data[1]);
fixture.detectChanges();
expect(getFileRawContentSpy).toHaveBeenCalled();
});
it('should show the empty list drag and drop component when the task is not completed', async(() => {
getTaskRelatedContentSpy.and.returnValue(Observable.of({
'size': 0,
'total': 0,
'start': 0,
'data': []
}));
let change = new SimpleChange(null, '123', true);
component.ngOnChanges({'taskId': change});
component.disabled = false;
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('.adf-custom-empty-template')).not.toBeNull();
});
}));
it('should not show the empty list drag and drop component when is disabled', async(() => {
getTaskRelatedContentSpy.and.returnValue(Observable.of({
'size': 0,
'total': 0,
'start': 0,
'data': []
}));
let change = new SimpleChange(null, '123', true);
component.ngOnChanges({'taskId': change});
component.disabled = true;
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('.adf-custom-empty-template')).toBeNull();
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim()).toEqual('ADF_TASK_LIST.ATTACHMENT.EMPTY.HEADER');
});
}));
it('should display all actions if attachments are not read only', () => {
let change = new SimpleChange(null, '123', true);
component.ngOnChanges({'taskId': change});
fixture.detectChanges();
@ -190,40 +237,6 @@ describe('TaskAttachmentList', () => {
});
}));
it('should show the empty list drag and drop component when the task is not completed', async(() => {
getTaskRelatedContentSpy.and.returnValue(Observable.of({
'size': 0,
'total': 0,
'start': 0,
'data': []
}));
let change = new SimpleChange(null, '123', true);
component.ngOnChanges({'taskId': change});
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('adf-empty-list .adf-empty-list-drag_drop').innerText.trim()).toEqual('ADF_TASK_LIST.ATTACHMENT.EMPTY.DRAG-AND-DROP.TITLE');
});
}));
it('should not show the empty list drag and drop component when is disabled', async(() => {
getTaskRelatedContentSpy.and.returnValue(Observable.of({
'size': 0,
'total': 0,
'start': 0,
'data': []
}));
let change = new SimpleChange(null, '123', true);
component.ngOnChanges({'taskId': change});
component.disabled = true;
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('adf-empty-list .adf-empty-list-drag_drop')).toBeNull();
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim()).toEqual('ADF_TASK_LIST.ATTACHMENT.EMPTY.HEADER');
});
}));
it('should show the empty list component when the attachments list is empty for completed task', async(() => {
getTaskRelatedContentSpy.and.returnValue(Observable.of({
'size': 0,
@ -270,7 +283,7 @@ describe('TaskAttachmentList', () => {
expect(getTaskRelatedContentSpy).toHaveBeenCalledWith('456');
});
it('should NOT fetch new attachments when empty changeset made', () => {
it('should NOT fetch new attachments when empty change set made', () => {
component.ngOnChanges({});
expect(getTaskRelatedContentSpy).not.toHaveBeenCalled();
});
@ -292,5 +305,11 @@ describe('TaskAttachmentList', () => {
expect(true).toBe(true);
});
it('delete content by contentId', () => {
component.deleteAttachmentById(5);
fixture.detectChanges();
expect(deleteContentSpy).toHaveBeenCalled();
});
});
});

View File

@ -16,17 +16,16 @@
*/
import { ContentService, ThumbnailService } from '@alfresco/adf-core';
import { Component, EventEmitter, Input, NgZone, OnChanges, Output, SimpleChanges } from '@angular/core';
import { AfterViewInit, Component, ElementRef, EventEmitter, Input, NgZone, OnChanges, Output, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core';
import { ProcessContentService } from '@alfresco/adf-core';
declare var require: any;
@Component({
selector: 'adf-task-attachment-list',
styleUrls: ['./task-attachment-list.component.scss'],
templateUrl: './task-attachment-list.component.html'
templateUrl: './task-attachment-list.component.html',
encapsulation: ViewEncapsulation.None
})
export class TaskAttachmentListComponent implements OnChanges {
export class TaskAttachmentListComponent implements OnChanges, AfterViewInit {
@Input()
taskId: string;
@ -43,8 +42,9 @@ export class TaskAttachmentListComponent implements OnChanges {
@Output()
error: EventEmitter<any> = new EventEmitter<any>();
@Input()
emptyListImageUrl: string = require('../assets/images/empty_doc_lib.svg');
hasCustomTemplate: boolean;
@ViewChild('customEmptyListTemplate') customTemplateRef: ElementRef;
attachments: any[] = [];
isLoading: boolean = true;
@ -61,6 +61,13 @@ export class TaskAttachmentListComponent implements OnChanges {
}
}
ngAfterViewInit() {
if (this.customTemplateRef && this.customTemplateRef.nativeElement &&
this.customTemplateRef.nativeElement.children && this.customTemplateRef.nativeElement.children.length > 0) {
this.hasCustomTemplate = true;
}
}
reset(): void {
this.attachments = [];
}
@ -110,7 +117,7 @@ export class TaskAttachmentListComponent implements OnChanges {
}
}
private deleteAttachmentById(contentId: number) {
deleteAttachmentById(contentId: number) {
if (contentId) {
this.activitiContentService.deleteRelatedContent(contentId).subscribe(
(res: any) => {
@ -128,6 +135,10 @@ export class TaskAttachmentListComponent implements OnChanges {
return this.attachments && this.attachments.length === 0;
}
isCustomTemplateDefined(): boolean {
return this.hasCustomTemplate;
}
onShowRowActionsMenu(event: any) {
let viewAction = {
title: 'ADF_TASK_LIST.MENU_ACTIONS.VIEW_CONTENT',