[ASD-2483] Validate folder name on change (#3088)

* notify service refactoring
get translate eliminitation in favor of instant
add error event where necessary
fix config problem during test

* fix delete notify test

* remove fdescribe

* fix core test

* errors

* fix types
This commit is contained in:
Eugenio Romano
2018-03-21 16:55:52 +00:00
committed by GitHub
parent de0fdd9ab4
commit 2951374cc0
25 changed files with 357 additions and 260 deletions

View File

@@ -60,6 +60,7 @@
class="upload-dialog__content"
[class.upload-dialog--padding]="isConfirmation">
<adf-file-uploading-list
(error)="onError($event)"
[class.upload-dialog--hide]="isConfirmation"
#uploadList
[files]="filesUploadingList">

View File

@@ -15,14 +15,17 @@
* limitations under the License.
*/
import { FileModel, FileUploadCompleteEvent, FileUploadDeleteEvent,
FileUploadErrorEvent, FileUploadStatus, UploadService } from '@alfresco/adf-core';
import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import {
FileModel, FileUploadCompleteEvent, FileUploadDeleteEvent,
FileUploadErrorEvent, FileUploadStatus, UploadService
} from '@alfresco/adf-core';
import { ChangeDetectorRef, Component, Input, Output, EventEmitter, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import { FileUploadingListComponent } from './file-uploading-list.component';
import 'rxjs/add/observable/merge';
// @deprecated file-uploading-dialog TODO remove in 3.0.0
@Component({
selector: 'adf-file-uploading-dialog, file-uploading-dialog',
templateUrl: './file-uploading-dialog.component.html',
@@ -36,6 +39,10 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
@Input()
position: string = 'right';
/** Emitted when a file in the list has an error. */
@Output()
error: EventEmitter<any> = new EventEmitter();
filesUploadingList: FileModel[] = [];
isDialogActive: boolean = false;
totalCompleted: number = 0;
@@ -48,9 +55,9 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
private fileUploadSubscription: Subscription;
private errorSubscription: Subscription;
constructor(
private uploadService: UploadService,
private changeDetecor: ChangeDetectorRef) {}
constructor(private uploadService: UploadService,
private changeDetecor: ChangeDetectorRef) {
}
ngOnInit() {
this.listSubscription = this.uploadService
@@ -60,14 +67,14 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
if (this.filesUploadingList.length) {
this.isDialogActive = true;
}
});
});
this.counterSubscription = Observable
.merge(
this.uploadService.fileUploadComplete,
this.uploadService.fileUploadDeleted
)
.subscribe((event: (FileUploadDeleteEvent|FileUploadCompleteEvent)) => {
.subscribe((event: (FileUploadDeleteEvent | FileUploadCompleteEvent)) => {
this.totalCompleted = event.totalComplete;
this.changeDetecor.detectChanges();
});

View File

@@ -16,7 +16,7 @@
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TranslationService, FileUploadStatus, NodesApiService, NotificationService, UploadService } from '@alfresco/adf-core';
import { TranslationService, FileUploadStatus, NodesApiService, UploadService } from '@alfresco/adf-core';
import { Observable } from 'rxjs/Observable';
import { UploadModule } from '../upload.module';
import { FileUploadingListComponent } from './file-uploading-list.component';
@@ -26,7 +26,6 @@ describe('FileUploadingListComponent', () => {
let component: FileUploadingListComponent;
let uploadService: UploadService;
let nodesApiService: NodesApiService;
let notificationService: NotificationService;
let translateService: TranslationService;
let file: any;
@@ -45,13 +44,11 @@ describe('FileUploadingListComponent', () => {
beforeEach(() => {
nodesApiService = TestBed.get(NodesApiService);
uploadService = TestBed.get(UploadService);
notificationService = TestBed.get(NotificationService);
translateService = TestBed.get(TranslationService);
fixture = TestBed.createComponent(FileUploadingListComponent);
component = fixture.componentInstance;
spyOn(translateService, 'get').and.returnValue(Observable.of('some error message'));
spyOn(notificationService, 'openSnackMessage');
spyOn(uploadService, 'cancelUpload');
});
@@ -82,15 +79,6 @@ describe('FileUploadingListComponent', () => {
expect(file.status).toBe(FileUploadStatus.Error);
});
it('should notify fail when api returns error', () => {
spyOn(nodesApiService, 'deleteNode').and.returnValue(Observable.throw(file));
component.removeFile(file);
fixture.detectChanges();
expect(notificationService.openSnackMessage).toHaveBeenCalled();
});
it('should call uploadService on error', () => {
spyOn(nodesApiService, 'deleteNode').and.returnValue(Observable.throw(file));
@@ -108,6 +96,19 @@ describe('FileUploadingListComponent', () => {
expect(uploadService.cancelUpload).toHaveBeenCalled();
});
describe('Events', () => {
it('should throw an error event if delete file goes wrong', (done) => {
spyOn(nodesApiService, 'deleteNode').and.returnValue(Observable.throw(file));
component.error.subscribe(() => {
done();
});
component.removeFile(file);
});
});
});
describe('cancelAllFiles()', () => {
@@ -159,15 +160,6 @@ describe('FileUploadingListComponent', () => {
expect(uploadService.cancelUpload).toHaveBeenCalled();
});
it('should notify on deleting file error', () => {
spyOn(nodesApiService, 'deleteNode').and.returnValue(Observable.throw({}));
component.files[0].status = FileUploadStatus.Complete;
component.cancelAllFiles();
expect(notificationService.openSnackMessage).toHaveBeenCalled();
});
});
describe('isUploadCompleted()', () => {

View File

@@ -15,8 +15,8 @@
* limitations under the License.
*/
import { FileModel, FileUploadStatus, NodesApiService, NotificationService, TranslationService, UploadService } from '@alfresco/adf-core';
import { Component, ContentChild, Input, TemplateRef } from '@angular/core';
import { FileModel, FileUploadStatus, NodesApiService, TranslationService, UploadService } from '@alfresco/adf-core';
import { Component, ContentChild, Input, Output, TemplateRef, EventEmitter } from '@angular/core';
import { Observable } from 'rxjs/Observable';
@Component({
@@ -34,10 +34,13 @@ export class FileUploadingListComponent {
@Input()
files: FileModel[] = [];
/** Emitted when a file in the list has an error. */
@Output()
error: EventEmitter<any> = new EventEmitter();
constructor(
private uploadService: UploadService,
private nodesApi: NodesApiService,
private notificationService: NotificationService,
private translateService: TranslationService) {
}
@@ -130,24 +133,23 @@ export class FileUploadingListComponent {
}
private notifyError(...files: FileModel[]) {
let translateSubscription = null;
let messageError: string = null;
if (files.length === 1) {
translateSubscription = this.translateService
.get(
messageError = this.translateService
.instant(
'FILE_UPLOAD.MESSAGES.REMOVE_FILE_ERROR',
{ fileName: files[0].name}
);
} else {
translateSubscription = this.translateService
.get(
messageError = this.translateService
.instant(
'FILE_UPLOAD.MESSAGES.REMOVE_FILES_ERROR',
{ total: files.length }
);
}
translateSubscription
.subscribe(message => this.notificationService.openSnackMessage(message, 4000));
this.error.emit(messageError);
}
private getUploadingFiles() {

View File

@@ -20,6 +20,7 @@ import { FileModel, LogService, UploadService } from '@alfresco/adf-core';
import { FileDraggableDirective } from '../directives/file-draggable.directive';
import { UploadDragAreaComponent } from './upload-drag-area.component';
import { Observable } from 'rxjs/Observable';
function getFakeShareDataRow(allowableOperations = ['delete', 'update', 'create']) {
return {
@@ -95,7 +96,7 @@ describe('UploadDragAreaComponent', () => {
spyOn(uploadService, 'uploadFilesInTheQueue');
fixture.detectChanges();
const file = <File> {name: 'fake-name-1', size: 10, webkitRelativePath: 'fake-folder1/fake-name-1.json'};
const file = <File> { name: 'fake-name-1', size: 10, webkitRelativePath: 'fake-folder1/fake-name-1.json' };
let filesList = [file];
component.onFilesDropped(filesList);
@@ -115,7 +116,7 @@ describe('UploadDragAreaComponent', () => {
isFile: true,
name: 'file-fake.png',
file: (callbackFile) => {
let fileFake = new File(['fakefake'], 'file-fake.png', {type: 'image/png'});
let fileFake = new File(['fakefake'], 'file-fake.png', { type: 'image/png' });
callbackFile(fileFake);
}
};
@@ -161,7 +162,7 @@ describe('UploadDragAreaComponent', () => {
isFile: true,
name: 'file-fake.png',
file: (callbackFile) => {
let fileFake = new File(['fakefake'], 'file-fake.png', {type: 'image/png'});
let fileFake = new File(['fakefake'], 'file-fake.png', { type: 'image/png' });
callbackFile(fileFake);
}
};
@@ -182,7 +183,7 @@ describe('UploadDragAreaComponent', () => {
uploadService.uploadFilesInTheQueue = jasmine.createSpy('uploadFilesInTheQueue');
fixture.detectChanges();
const file = <File> {name: 'fake-name-1', size: 10, webkitRelativePath: 'fake-folder1/fake-name-1.json'};
const file = <File> { name: 'fake-name-1', size: 10, webkitRelativePath: 'fake-folder1/fake-name-1.json' };
let filesList = [file];
spyOn(uploadService, 'addToQueue').and.callFake((f: FileModel) => {
@@ -205,7 +206,7 @@ describe('UploadDragAreaComponent', () => {
isFile: true,
name: 'file-fake.png',
file: (callbackFile) => {
let fileFake = new File(['fakefake'], 'file-fake.png', {type: 'image/png'});
let fileFake = new File(['fakefake'], 'file-fake.png', { type: 'image/png' });
callbackFile(fileFake);
}
};
@@ -226,7 +227,7 @@ describe('UploadDragAreaComponent', () => {
isFile: true,
name: 'file-fake.png',
file: (callbackFile) => {
let fileFake = new File(['fakefake'], 'file-fake.png', {type: 'image/png'});
let fileFake = new File(['fakefake'], 'file-fake.png', { type: 'image/png' });
callbackFile(fileFake);
}
};
@@ -242,7 +243,7 @@ describe('UploadDragAreaComponent', () => {
isFile: true,
name: 'file-fake.png',
file: (callbackFile) => {
let fileFake = new File(['fakefake'], 'file-fake.png', {type: 'image/png'});
let fileFake = new File(['fakefake'], 'file-fake.png', { type: 'image/png' });
callbackFile(fileFake);
}
};
@@ -262,4 +263,36 @@ describe('UploadDragAreaComponent', () => {
component.onUploadFiles(fakeCustomEvent);
}));
describe('Events', () => {
it('should raise an error if upload a file goes wrong', (done) => {
let fakeItem = {
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);
}
};
fixture.detectChanges();
spyOn(uploadService, 'fileUploadError').and.returnValue(Observable.throw(new Error()));
component.error.subscribe((error) => {
expect(error).not.toBeNull();
done();
});
let fakeCustomEvent: CustomEvent = new CustomEvent('CustomEvent', {
detail: {
data: getFakeShareDataRow(),
files: [fakeItem]
}
});
component.onUploadFiles(fakeCustomEvent);
});
});
});

View File

@@ -32,7 +32,7 @@ import { Component, EventEmitter, forwardRef, Input, Output, ViewEncapsulation }
templateUrl: './upload-drag-area.component.html',
styleUrls: ['./upload-drag-area.component.css'],
viewProviders: [
{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadDragAreaComponent)}
{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadDragAreaComponent) }
],
encapsulation: ViewEncapsulation.None
})
@@ -56,6 +56,10 @@ export class UploadDragAreaComponent implements NodePermissionSubject {
@Output()
success = new EventEmitter();
/** Raised when the file upload goes in error. */
@Output()
error = new EventEmitter();
constructor(private uploadService: UploadService,
private translateService: TranslationService,
private notificationService: NotificationService) {
@@ -91,8 +95,8 @@ export class UploadDragAreaComponent implements NodePermissionSubject {
parentId: this.parentId,
path: item.fullPath.replace(item.name, '')
});
this.uploadService.addToQueue(fileModel);
this.uploadService.uploadFilesInTheQueue(this.success);
this.addNodeInUploadQueue([fileModel]);
});
}
}
@@ -112,8 +116,18 @@ export class UploadDragAreaComponent implements NodePermissionSubject {
path: entry.relativeFolder
});
});
this.uploadService.addToQueue(...files);
this.uploadService.uploadFilesInTheQueue(this.success);
this.addNodeInUploadQueue(files);
});
}
}
private addNodeInUploadQueue(files: FileModel[]) {
if (files.length) {
this.uploadService.addToQueue(...files);
this.uploadService.uploadFilesInTheQueue(this.success);
this.uploadService.fileUploadError.subscribe((error) => {
this.error.emit(error);
});
}
}
@@ -133,15 +147,6 @@ export class UploadDragAreaComponent implements NodePermissionSubject {
});
}
/**
* Show the error inside Notification bar
*
* @param Error message
*/
showErrorNotificationBar(errorMessage: string) {
this.notificationService.openSnackMessage(errorMessage, 3000);
}
/** Returns true or false considering the component options and node permissions */
isDroppable(): boolean {
return !this.disabled;
@@ -168,23 +173,11 @@ export class UploadDragAreaComponent implements NodePermissionSubject {
path: fileInfo.relativeFolder,
parentId: parentId
}));
this.uploadFiles(fileModels);
this.addNodeInUploadQueue(fileModels);
}
}
}
/**
* Does the actual file uploading and show the notification
*
* @param files
*/
private uploadFiles(files: FileModel[]): void {
if (files.length) {
this.uploadService.addToQueue(...files);
this.uploadService.uploadFilesInTheQueue(this.success);
}
}
/**
* Check if "create" permission is present on the given node
*