[ADF-571] upload feature rework (#1922)

* upload feature rework

lots of improvements for upload dialog and underlying services

* readme update

- readme cleanup
- remove some old comments from code
- update readme with new events for Upload Service

* restore prerequisites section in readme
This commit is contained in:
Denys Vuika
2017-06-02 14:05:55 +01:00
committed by Eugenio Romano
parent b4c9710e71
commit c2fee79724
23 changed files with 560 additions and 769 deletions

View File

@@ -14,7 +14,7 @@
}
:host .file-dialog {
width: 700px;
width: 550px;
display: none;
-webkit-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, .2);
box-shadow: -2px -1px 8px 3px rgba(0, 0, 0, .2);

View File

@@ -16,12 +16,14 @@
*/
import { DebugElement } from '@angular/core';
import { MdProgressSpinnerModule } from '@angular/material';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { CoreModule } from 'ng2-alfresco-core';
import { FileUploadingDialogComponent } from './file-uploading-dialog.component';
import { FileUploadingListComponent } from './file-uploading-list.component';
import { UploadService } from '../services/upload.service';
import { FileModel } from '../models/file.model';
import { FileUploadCompleteEvent } from '../events/file.event';
describe('FileUploadingDialogComponent', () => {
@@ -35,7 +37,8 @@ describe('FileUploadingDialogComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule.forRoot()
CoreModule.forRoot(),
MdProgressSpinnerModule
],
declarations: [
FileUploadingDialogComponent,
@@ -48,8 +51,6 @@ describe('FileUploadingDialogComponent', () => {
}));
beforeEach(() => {
window['componentHandler'] = null;
const fileFake = new File([''], 'fake-name');
file = new FileModel(fileFake);
@@ -70,7 +71,7 @@ describe('FileUploadingDialogComponent', () => {
});
it('should render completed upload 1 when an element is added to Observer', () => {
uploadService.updateFileCounterStream(1);
uploadService.fileUploadComplete.next(new FileUploadCompleteEvent(null, 1));
fixture.detectChanges();
expect(element.querySelector('#total-upload-completed').innerText).toEqual('1');

View File

@@ -15,24 +15,15 @@
* limitations under the License.
*/
import { Component, Input, ChangeDetectorRef, OnInit, OnDestroy } from '@angular/core';
import { Component, Input, ChangeDetectorRef, OnInit, OnDestroy, ChangeDetectionStrategy } from '@angular/core';
import { FileModel } from '../models/file.model';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
import { UploadService } from '../services/upload.service';
import { FileUploadCompleteEvent } from '../events/file.event';
/**
* <file-uploading-dialog [filesUploadingList]="FileModel[]"></file-uploading-dialog>
*
* This component is a hideable and minimizable wich contains the list of the uploading
* files contained in the filesUploadingList.
*
* @InputParam {FileModel[]} filesUploadingList - list of the uploading files .
*
*
* @returns {FileUploadingDialogComponent} .
*/
@Component({
selector: 'file-uploading-dialog',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './file-uploading-dialog.component.html',
styleUrls: ['./file-uploading-dialog.component.css']
})
@@ -55,27 +46,30 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
if (translateService) {
translateService.addTranslationFolder('ng2-alfresco-upload', 'assets/ng2-alfresco-upload');
}
cd.detach();
}
ngOnInit() {
if (this.uploadService.filesUpload$) {
this.listSubscription = this.uploadService.filesUpload$.subscribe((fileList: FileModel[]) => {
this.filesUploadingList = fileList;
if (this.filesUploadingList.length > 0) {
this.isDialogActive = true;
this.cd.detectChanges();
}
});
}
if (this.uploadService.totalCompleted$) {
this.counterSubscription = this.uploadService.totalCompleted$.subscribe((total: number) => {
this.totalCompleted = total;
if (this.totalCompleted > 1) {
this.totalCompletedMsg = 'FILE_UPLOAD.MESSAGES.COMPLETED';
}
this.listSubscription = this.uploadService.queueChanged.subscribe((fileList: FileModel[]) => {
this.filesUploadingList = fileList;
if (this.filesUploadingList.length > 0) {
this.isDialogActive = true;
this.cd.detectChanges();
});
}
}
});
this.counterSubscription = this.uploadService.fileUploadComplete.subscribe((e: FileUploadCompleteEvent) => {
this.totalCompleted = e.totalComplete;
if (this.totalCompleted > 1) {
this.totalCompletedMsg = 'FILE_UPLOAD.MESSAGES.COMPLETED';
}
this.cd.detectChanges();
});
this.uploadService.fileUpload.subscribe(e => {
console.log(e);
this.cd.detectChanges();
});
}
/**
@@ -83,6 +77,7 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
*/
toggleVisible(): void {
this.isDialogActive = !this.isDialogActive;
this.cd.detectChanges();
}
/**
@@ -90,11 +85,11 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
*/
toggleMinimized(): void {
this.isDialogMinimized = !this.isDialogMinimized;
this.cd.detectChanges();
}
ngOnDestroy() {
this.listSubscription.unsubscribe();
this.counterSubscription.unsubscribe();
this.cd.detach();
}
}

View File

@@ -3,8 +3,8 @@
border: 0px;
}
.cursor {
cursor: pointer;
.center {
text-align: center;
}
.body-dialog-header {
@@ -42,62 +42,40 @@
width: 100%;
}
:host .truncate {
margin-left: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.cancel-upload-button {
cursor: pointer;
}
:host .mdl-progress {
width: 150px;
}
@media (max-device-width: 360px) {
.truncate {
max-width: 50px;
margin-left: 0px;
}
}
@media (max-device-width: 568px) {
.truncate {
width: 60px;
}
.mdl-progress {
width: 60px;
}
}
@media (max-width: 740px) {
.truncate {
max-width: 80px;
}
.mdl-progress {
max-width: 70px;
}
.size-column {
display: none;
}
}
@media (min-width: 740px) {
.truncate {
width: 249px;
}
.size-column {
display: table-cell;
}
.file-progress-spinner {
height: 24px;
width: 100%;
text-align: center;
}
.full-width {
width: 100%;
}
.no-width {
width: 0%;
.ellipsis-cell .cell-container {
height: 1em;
}
/* visible content */
.ellipsis-cell .cell-value {
display: block;
position: absolute;
max-width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1em; /* for vertical align of text */
}
/* cell stretching content */
.ellipsis-cell > div:after {
content: attr(title);
overflow: hidden;
height: 0;
display: block;
}

View File

@@ -6,32 +6,37 @@
</div>
<table class="mdl-data-table mdl-js-data-table mdl-shadow--2dp">
<tr>
<th class="mdl-data-table__cell--non-numeric">{{'FILE_UPLOAD.FILE_INFO.NAME' | translate}}</th>
<th class="mdl-data-table__cell--non-numeric">{{'FILE_UPLOAD.FILE_INFO.PROGRESS' | translate}}</th>
<th class="mdl-data-table__cell--non-numeric mdl-cell--hide-phone size-column">{{'FILE_UPLOAD.FILE_INFO.SIZE' | translate}}</th>
<th class="mdl-data-table__cell--non-numeric">{{'FILE_UPLOAD.FILE_INFO.ACTION' | translate}}</th>
<th class="mdl-data-table__cell--non-numeric full-width">{{'ADF_FILE_UPLOAD.FILE_LIST.NAME' | translate}}</th>
<th class="mdl-data-table__cell center">{{'ADF_FILE_UPLOAD.FILE_LIST.PROGRESS' | translate}}</th>
<th class="mdl-data-table__cell mdl-cell--hide-phone size-column center">{{'ADF_FILE_UPLOAD.FILE_LIST.SIZE' | translate}}</th>
<th class="mdl-data-table__cell center">{{'ADF_FILE_UPLOAD.FILE_LIST.ACTION' | translate}}</th>
</tr>
<tr *ngFor="let file of files" tabindex="0">
<td class="mdl-data-table__cell--non-numeric" attr.data-automation-id="dialog_{{file.name}}">
<div class="truncate">{{file.name}}</div>
</td>
<td class="mdl-data-table__cell--non-numeric">
<div class="mdl-progress mdl-js-progress is-upgraded" id="{{file.id}}">
<div class="progressbar bar bar1" attr.data-automation-id="dialog_progress_{{file.name}}" [style.width.%]="file.progress.percent"></div>
<div class="bufferbar bar bar2" class="full-width"></div>
<div class="auxbar bar bar3" class="no-width"></div>
<td class="mdl-data-table__cell--non-numeric full-width ellipsis-cell" attr.data-automation-id="dialog_{{file.name}}">
<div class="cell-container">
<div class="cell-value" [title]="file.name">{{file.name}}</div>
</div>
</td>
<td class="mdl-data-table__cell--non-numeric mdl-cell--hide-phone size-column" attr.data-automation-id="{{file.name}}_filesize">{{file.size}}</td>
<td class="mdl-data-table__cell--non-numeric">
<span *ngIf="file.done && !file.abort">
<i data-automation-id="done_icon" class="material-icons action-icons">done</i>
<td class="mdl-data-table__cell center">
<md-icon *ngIf="file.status === FileUploadStatus.Error || file.status === FileUploadStatus.Aborted">error_outline</md-icon>
<md-icon *ngIf="file.status === FileUploadStatus.Cancelled">block</md-icon>
<ng-container *ngIf="file.status === FileUploadStatus.Progress">
<md-progress-spinner
class="file-progress-spinner"
[mode]="'determinate'"
[value]="file.progress.percent">
</md-progress-spinner>
</ng-container>
</td>
<td class="mdl-data-table__cell mdl-cell--hide-phone size-column center" attr.data-automation-id="{{file.name}}_filesize">
{{ file.size | adfFileSize }}
</td>
<td class="mdl-data-table__cell center">
<span *ngIf="file.status === FileUploadStatus.Complete">
<md-icon>done</md-icon>
</span>
<span *ngIf="file.uploading" (click)="cancelFileUpload(file)" class="cursor" tabindex="0">
<i data-automation-id="abort_cancel_upload" class="material-icons action-icons">remove_circle_outline</i>
</span>
<span *ngIf="file.abort">
<i class="material-icons action-icons" data-automation-id="upload_stopped" tabindex="0">remove_circle</i>
<span *ngIf="file.status === FileUploadStatus.Progress" (click)="cancelFileUpload(file)" tabindex="0" class="cancel-upload-button">
<md-icon>remove_circle_outline</md-icon>
</span>
</td>
</tr>

View File

@@ -16,18 +16,9 @@
*/
import { Component, Input } from '@angular/core';
import { FileModel } from '../models/file.model';
import { FileModel, FileUploadStatus } from '../models/file.model';
import { UploadService } from '../services/upload.service';
/**
* <alfresco-file-uploading-list [files]="files"></alfresco-file-uploading-list>
*
* This component show a list of the uploading files contained in the filesUploadingList.
*
* @InputParam {FileModel[]} filesUploadingList - list of the uploading files .
*
*
* @returns {FileUploadingListComponent} .
*/
@Component({
selector: 'alfresco-file-uploading-list',
templateUrl: './file-uploading-list.component.html',
@@ -35,9 +26,14 @@ import { FileModel } from '../models/file.model';
})
export class FileUploadingListComponent {
FileUploadStatus = FileUploadStatus;
@Input()
files: FileModel[];
constructor(private uploadService: UploadService) {
}
/**
* Cancel file upload
*
@@ -46,9 +42,7 @@ export class FileUploadingListComponent {
* @memberOf FileUploadingListComponent
*/
cancelFileUpload(file: FileModel): void {
if (file) {
file.emitAbort();
}
this.uploadService.cancelUpload(file);
}
/**
@@ -58,21 +52,20 @@ export class FileUploadingListComponent {
if (event) {
event.preventDefault();
}
this.files.forEach((uploadingFileModel: FileModel) => {
uploadingFileModel.emitAbort();
});
this.uploadService.cancelUpload(...this.files);
}
/**
* Verify if all the files are in state done or abort
* @returns {boolean} - false if there is a file in progress
* Check if all the files are not in the Progress state.
* @returns {boolean} - false if there is at least one file in Progress
*/
isUploadCompleted(): boolean {
let isPending = false;
let isAllCompleted = true;
for (let i = 0; i < this.files.length && !isPending; i++) {
let file = this.files[i];
if (!file.done && !file.abort) {
if (file.status === FileUploadStatus.Progress) {
isPending = true;
isAllCompleted = false;
}

View File

@@ -15,10 +15,10 @@
* limitations under the License.
*/
import { DebugElement, SimpleChange } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { UploadButtonComponent } from './upload-button.component';
import { DebugElement, SimpleChange } from '@angular/core';
import { CoreModule, AlfrescoTranslationService, NotificationService } from 'ng2-alfresco-core';
import { CoreModule, AlfrescoTranslationService, AlfrescoContentService} from 'ng2-alfresco-core';
import { TranslationMock } from '../assets/translation.service.mock';
import { UploadService } from '../services/upload.service';
import { Observable } from 'rxjs/Rx';
@@ -33,27 +33,6 @@ describe('UploadButtonComponent', () => {
target: {value: 'fake-name-1'}
};
let fakeResolveRest = {
entry: {
isFile: false,
isFolder: true,
name: 'fake-folder1'
}
};
let fakeResolvePromise = new Promise(function (resolve, reject) {
resolve(fakeResolveRest);
});
let fakeRejectRest = {
response: {
body: {
error: {
statusCode: 409
}
}
}
};
let fakeFolderNodeWithoutPermission = {
allowableOperations: [
'update'
@@ -73,15 +52,12 @@ describe('UploadButtonComponent', () => {
nodeType: 'cm:folder'
};
let fakeRejectPromise = new Promise(function (resolve, reject) {
reject(fakeRejectRest);
});
let component: UploadButtonComponent;
let fixture: ComponentFixture<UploadButtonComponent>;
let debug: DebugElement;
let element: HTMLElement;
let uploadService: UploadService;
let contentService: AlfrescoContentService;
beforeEach(async(() => {
TestBed.configureTestingModule({
@@ -93,7 +69,6 @@ describe('UploadButtonComponent', () => {
],
providers: [
UploadService,
NotificationService,
{provide: AlfrescoTranslationService, useClass: TranslationMock}
]
}).compileComponents();
@@ -104,6 +79,7 @@ describe('UploadButtonComponent', () => {
fixture = TestBed.createComponent(UploadButtonComponent);
uploadService = TestBed.get(UploadService);
contentService = TestBed.get(AlfrescoContentService);
debug = fixture.debugElement;
element = fixture.nativeElement;
@@ -141,7 +117,7 @@ describe('UploadButtonComponent', () => {
component.rootFolderId = '-my-';
component.disableWithNoPermission = false;
spyOn(uploadService, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithoutPermission));
spyOn(component, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithoutPermission));
fixture.detectChanges();
@@ -160,7 +136,7 @@ describe('UploadButtonComponent', () => {
component.rootFolderId = '-my-';
component.disableWithNoPermission = true;
spyOn(uploadService, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithoutPermission));
spyOn(component, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithoutPermission));
component.onFilesAdded(fakeEvent);
let compiled = fixture.debugElement.nativeElement;
@@ -173,7 +149,7 @@ describe('UploadButtonComponent', () => {
component.rootFolderId = '-my-';
component.disableWithNoPermission = true;
spyOn(uploadService, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithPermission));
spyOn(component, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithPermission));
component.ngOnChanges({ rootFolderId: new SimpleChange(null, component.rootFolderId, true) });
component.onFilesAdded(fakeEvent);
@@ -187,7 +163,7 @@ describe('UploadButtonComponent', () => {
component.rootFolderId = '-my-';
component.disableWithNoPermission = false;
spyOn(uploadService, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithPermission));
spyOn(component, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithPermission));
component.ngOnChanges({ rootFolderId: new SimpleChange(null, component.rootFolderId, true) });
component.onFilesAdded(fakeEvent);
@@ -202,7 +178,7 @@ describe('UploadButtonComponent', () => {
component.currentFolderPath = '/root-fake-/sites-fake/folder-fake';
component.onSuccess = null;
spyOn(uploadService, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithPermission));
spyOn(component, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithPermission));
component.ngOnChanges({ rootFolderId: new SimpleChange(null, component.rootFolderId, true) });
uploadService.uploadFilesInTheQueue = jasmine.createSpy('uploadFilesInTheQueue');
@@ -218,7 +194,7 @@ describe('UploadButtonComponent', () => {
component.rootFolderId = '-my-';
component.onSuccess = null;
spyOn(uploadService, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithPermission));
spyOn(component, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithPermission));
component.ngOnChanges({ rootFolderId: new SimpleChange(null, component.rootFolderId, true) });
uploadService.uploadFilesInTheQueue = jasmine.createSpy('uploadFilesInTheQueue');
@@ -233,11 +209,12 @@ describe('UploadButtonComponent', () => {
component.rootFolderId = '-my-';
component.currentFolderPath = '/fake-root-path';
spyOn(uploadService, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithPermission));
spyOn(uploadService, 'callApiCreateFolder').and.returnValue(fakeResolvePromise);
spyOn(contentService, 'createFolder').and.returnValue(Observable.of(true));
spyOn(component, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithPermission));
component.ngOnChanges({ rootFolderId: new SimpleChange(null, component.rootFolderId, true) });
fixture.detectChanges();
component.onSuccess.subscribe(e => {
expect(e.value).toEqual('File uploaded');
done();
@@ -245,22 +222,21 @@ describe('UploadButtonComponent', () => {
spyOn(component, 'uploadFiles').and.callFake(() => {
component.onSuccess.emit({
value: 'File uploaded'
}
);
value: 'File uploaded'
});
});
component.onDirectoryAdded(fakeEvent);
});
it('should emit an onError event when the folder already exist', (done) => {
component.rootFolderId = '-my-';
spyOn(uploadService, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithPermission));
spyOn(uploadService, 'callApiCreateFolder').and.returnValue(fakeRejectPromise);
spyOn(contentService, 'createFolder').and.returnValue(Observable.throw(new Error('')));
spyOn(component, 'getFolderNode').and.returnValue(Observable.of(fakeFolderNodeWithPermission));
component.ngOnChanges({ rootFolderId: new SimpleChange(null, component.rootFolderId, true) });
component.onError.subscribe(e => {
expect(e.value).toEqual('FILE_UPLOAD.MESSAGES.FOLDER_ALREADY_EXIST');
expect(e.value).toEqual('Error');
done();
});

View File

@@ -16,36 +16,15 @@
*/
import { Component, ElementRef, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core';
import { Subject } from 'rxjs/Rx';
import { AlfrescoTranslationService, LogService, NotificationService, AlfrescoSettingsService } from 'ng2-alfresco-core';
import { Observable, Subject } from 'rxjs/Rx';
import { AlfrescoApiService, AlfrescoContentService, AlfrescoTranslationService, LogService, NotificationService, AlfrescoSettingsService } from 'ng2-alfresco-core';
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
import { UploadService } from '../services/upload.service';
import { FileModel } from '../models/file.model';
import { PermissionModel } from '../models/permissions.model';
declare let componentHandler: any;
const ERROR_FOLDER_ALREADY_EXIST = 409;
/**
* <alfresco-upload-button [showNotificationBar]="boolean"
* [uploadFolders]="boolean"
* [multipleFiles]="boolean"
* [acceptedFilesType]="string"
* (onSuccess)="customMethod($event)">
* </alfresco-upload-button>
*
* This component, provide a set of buttons to upload files to alfresco.
*
* @InputParam {boolean} [true] showNotificationBar - hide/show notification bar.
* @InputParam {boolean} [false] versioning - true to indicate that a major version should be created
* @InputParam {boolean} [false] uploadFolders - allow/disallow upload folders (only for chrome).
* @InputParam {boolean} [false] multipleFiles - allow/disallow multiple files.
* @InputParam {string} [*] acceptedFilesType - array of allowed file extensions.
* @InputParam {boolean} [false] versioning - true to indicate that a major version should be created
* @Output - onSuccess - The event is emitted when the file is uploaded
*
* @returns {UploadButtonComponent} .
*/
@Component({
selector: 'alfresco-upload-button',
templateUrl: './upload-button.component.html',
@@ -106,7 +85,9 @@ export class UploadButtonComponent implements OnInit, OnChanges {
private translateService: AlfrescoTranslationService,
private logService: LogService,
private notificationService: NotificationService,
private settingsService: AlfrescoSettingsService) {
private settingsService: AlfrescoSettingsService,
private apiService: AlfrescoApiService,
private contentService: AlfrescoContentService) {
if (translateService) {
translateService.addTranslationFolder('ng2-alfresco-upload', 'assets/ng2-alfresco-upload');
}
@@ -172,9 +153,9 @@ export class UploadButtonComponent implements OnInit, OnChanges {
let directoryName = this.getDirectoryName(directoryPath);
let absolutePath = this.currentFolderPath + this.getDirectoryPath(directoryPath);
this.uploadService.createFolder(absolutePath, directoryName, this.rootFolderId)
this.contentService.createFolder(absolutePath, directoryName, this.rootFolderId)
.subscribe(
res => {
_ => {
let relativeDir = this.currentFolderPath + '/' + directoryPath;
this.uploadFiles(relativeDir, filesDir);
},
@@ -269,10 +250,8 @@ export class UploadButtonComponent implements OnInit, OnChanges {
messageTranslate = this.translateService.get('FILE_UPLOAD.MESSAGES.PROGRESS');
actionTranslate = this.translateService.get('FILE_UPLOAD.ACTION.UNDO');
this.notificationService.openSnackMessageAction(messageTranslate.value, actionTranslate.value, 3000).afterDismissed().subscribe(() => {
latestFilesAdded.forEach((uploadingFileModel: FileModel) => {
uploadingFileModel.emitAbort();
});
this.notificationService.openSnackMessageAction(messageTranslate.value, actionTranslate.value, 3000).onAction().subscribe(() => {
this.uploadService.cancelUpload(...latestFilesAdded);
});
}
@@ -282,11 +261,12 @@ export class UploadButtonComponent implements OnInit, OnChanges {
* @returns {string}
*/
private getErrorMessage(response: any): string {
if (response.body && response.body.error.statusCode === ERROR_FOLDER_ALREADY_EXIST) {
if (response && response.body && response.body.error.statusCode === ERROR_FOLDER_ALREADY_EXIST) {
let errorMessage: any;
errorMessage = this.translateService.get('FILE_UPLOAD.MESSAGES.FOLDER_ALREADY_EXIST');
return errorMessage.value;
}
return 'Error';
}
/**
@@ -314,17 +294,30 @@ export class UploadButtonComponent implements OnInit, OnChanges {
checkPermission() {
if (this.rootFolderId) {
this.uploadService.getFolderNode(this.rootFolderId).subscribe(
(res) => {
this.permissionValue.next(this.hasCreatePermission(res));
},
(error) => {
this.onError.emit(error);
}
this.getFolderNode(this.rootFolderId).subscribe(
res => this.permissionValue.next(this.hasCreatePermission(res)),
error => this.onError.emit(error)
);
}
}
getFolderNode(nodeId: string): Observable<MinimalNodeEntryEntity> {
let opts: any = {
includeSource: true,
include: ['allowableOperations']
};
return Observable.fromPromise(this.apiService.getInstance().nodes.getNodeInfo(nodeId, opts))
.catch(err => this.handleError(err));
}
private handleError(error: Response) {
// in a real world app, we may send the error to some remote logging infrastructure
// instead of just logging it to the console
this.logService.error(error);
return Observable.throw(error || 'Server error');
}
private hasCreatePermission(node: any): boolean {
if (this.hasPermissions(node)) {
return node.allowableOperations.find(permision => permision === 'create') ? true : false;

View File

@@ -17,7 +17,7 @@
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { EventEmitter, DebugElement } from '@angular/core';
import { AlfrescoTranslationService, CoreModule, LogService, LogServiceMock, NotificationService } from 'ng2-alfresco-core';
import { AlfrescoTranslationService, CoreModule, LogService, LogServiceMock } from 'ng2-alfresco-core';
import { UploadDragAreaComponent } from './upload-drag-area.component';
import { FileDraggableDirective } from '../directives/file-draggable.directive';
@@ -45,7 +45,6 @@ describe('UploadDragAreaComponent', () => {
],
providers: [
UploadService,
NotificationService,
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
{ provide: LogService, useClass: LogServiceMock }
]
@@ -147,92 +146,4 @@ describe('UploadDragAreaComponent', () => {
expect(uploadService.uploadFilesInTheQueue)
.toHaveBeenCalledWith('-my-', '/root-fake-/sites-fake/document-library-fake/folder-fake/', null);
});
xit('should throws an exception and show it in the notification bar when the folder already exist', done => {
component.currentFolderPath = '/root-fake-/sites-fake/folder-fake';
component.showNotificationBar = true;
fixture.detectChanges();
let fakeRest = {
response: {
body: {
error: {
statusCode: 409
}
}
}
};
let fakePromise = new Promise(function (resolve, reject) {
reject(fakeRest);
});
spyOn(uploadService, 'callApiCreateFolder').and.returnValue(fakePromise);
spyOn(component, 'showErrorNotificationBar').and.callFake( () => {
expect(component.showErrorNotificationBar).toHaveBeenCalledWith('FILE_UPLOAD.MESSAGES.FOLDER_ALREADY_EXIST');
done();
});
let folderEntry = {
fullPath: '/folder-duplicate-fake',
isDirectory: true,
isFile: false,
name: 'folder-duplicate-fake'
};
component.onFolderEntityDropped(folderEntry);
});
it('should create a folder and call onFilesEntityDropped with the file inside the folder', done => {
component.currentFolderPath = '/root-fake-/sites-fake/document-library-fake';
component.onSuccess = new EventEmitter();
fixture.detectChanges();
let itemEntity = {
fullPath: '/folder-fake/file-fake.png',
isDirectory: false,
isFile: true,
name: 'file-fake.png',
file: (callbackFile) => {
let fileFake = new File(['fakefake'], 'file-fake.png', {type: 'image/png'});
callbackFile(fileFake);
}
};
let fakeRest = {
entry: {
isFile: false,
isFolder: true,
name: 'folder-fake'
}
};
let fakePromise = new Promise(function (resolve, reject) {
resolve(fakeRest);
});
spyOn(uploadService, 'callApiCreateFolder').and.returnValue(fakePromise);
spyOn(component, 'onFilesEntityDropped').and.callFake( () => {
expect(component.onFilesEntityDropped).toHaveBeenCalledWith(itemEntity);
});
spyOn(component, 'showUndoNotificationBar').and.callFake( () => {
expect(component.showUndoNotificationBar).toHaveBeenCalled();
done();
});
let folderEntry = {
fullPath: '/folder-fake',
isDirectory: true,
isFile: false,
name: 'folder-fake',
createReader: () => {
return {
readEntries: (callback) => {
let entries = [itemEntity, itemEntity];
callback(entries);
}
};
}
};
component.onFolderEntityDropped(folderEntry);
});
});

View File

@@ -16,21 +16,12 @@
*/
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { AlfrescoTranslationService, LogService, NotificationService } from 'ng2-alfresco-core';
import { AlfrescoTranslationService, AlfrescoContentService, LogService, NotificationService } from 'ng2-alfresco-core';
import { UploadService } from '../services/upload.service';
import { FileModel } from '../models/file.model';
const ERROR_FOLDER_ALREADY_EXIST = 409;
/**
* <alfresco-upload-drag-area (onSuccess)="customMethod($event)></alfresco-upload-drag-area>
*
* This component, provide a drag and drop are to upload files to alfresco.
*
* @Output - onSuccess - The event is emitted when the file is uploaded
*
* @returns {UploadDragAreaComponent} .
*/
@Component({
selector: 'alfresco-upload-drag-area',
templateUrl: './upload-drag-area.component.html',
@@ -61,7 +52,8 @@ export class UploadDragAreaComponent {
constructor(private uploadService: UploadService,
private translateService: AlfrescoTranslationService,
private logService: LogService,
private notificationService: NotificationService) {
private notificationService: NotificationService,
private contentService: AlfrescoContentService) {
if (translateService) {
translateService.addTranslationFolder('ng2-alfresco-upload', 'assets/ng2-alfresco-upload');
}
@@ -129,7 +121,7 @@ export class UploadDragAreaComponent {
let relativePath = folder.fullPath.replace(folder.name, '');
relativePath = this.currentFolderPath + relativePath;
this.uploadService.createFolder(relativePath, folder.name, this.rootFolderId)
this.contentService.createFolder(relativePath, folder.name, this.rootFolderId)
.subscribe(
message => {
this.onSuccess.emit({
@@ -186,9 +178,7 @@ export class UploadDragAreaComponent {
actionTranslate = this.translateService.get('FILE_UPLOAD.ACTION.UNDO');
this.notificationService.openSnackMessageAction(messageTranslate.value, actionTranslate.value, 3000).onAction().subscribe(() => {
latestFilesAdded.forEach((uploadingFileModel: FileModel) => {
uploadingFileModel.emitAbort();
});
this.uploadService.cancelUpload(...latestFilesAdded);
});
}