diff --git a/demo-shell-ng2/app/components/files/files.component.ts b/demo-shell-ng2/app/components/files/files.component.ts
index 37ef65ce3d..5b6ab18b44 100644
--- a/demo-shell-ng2/app/components/files/files.component.ts
+++ b/demo-shell-ng2/app/components/files/files.component.ts
@@ -17,10 +17,10 @@
import { Component, Input, OnInit, AfterViewInit, Optional, ViewChild, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router';
-import { AlfrescoAuthenticationService, LogService, NotificationService } from 'ng2-alfresco-core';
+import { AlfrescoAuthenticationService, AlfrescoContentService, FolderCreatedEvent, LogService, NotificationService } from 'ng2-alfresco-core';
import { DocumentActionsService, DocumentListComponent, ContentActionHandler, DocumentActionModel, FolderActionModel } from 'ng2-alfresco-documentlist';
import { FormService } from 'ng2-activiti-form';
-import { UploadService, UploadButtonComponent, UploadDragAreaComponent, FolderCreatedEvent } from 'ng2-alfresco-upload';
+import { UploadService, UploadButtonComponent, UploadDragAreaComponent } from 'ng2-alfresco-upload';
@Component({
selector: 'files-component',
@@ -73,6 +73,7 @@ export class FilesComponent implements OnInit, AfterViewInit {
private router: Router,
private notificationService: NotificationService,
private uploadService: UploadService,
+ private contentService: AlfrescoContentService,
@Optional() private route: ActivatedRoute) {
documentActions.setHandler('my-handler', this.myDocumentActionHandler.bind(this));
}
@@ -122,7 +123,7 @@ export class FilesComponent implements OnInit, AfterViewInit {
this.logService.warn('You are not logged in to BPM');
}
- this.uploadService.folderCreated.subscribe(value => this.onFolderCreated(value));
+ this.contentService.folderCreated.subscribe(value => this.onFolderCreated(value));
}
ngAfterViewInit() {
diff --git a/ng2-components/ng2-alfresco-core/index.ts b/ng2-components/ng2-alfresco-core/index.ts
index 89f4c9aec1..000aa15d84 100644
--- a/ng2-components/ng2-alfresco-core/index.ts
+++ b/ng2-components/ng2-alfresco-core/index.ts
@@ -41,6 +41,7 @@ import {
ContentService
} from './src/services/index';
+import { FileSizePipe } from './src/pipes/file-size.pipe';
import { UploadDirective } from './src/directives/upload.directive';
import { DataColumnComponent } from './src/components/data-column/data-column.component';
import { DataColumnListComponent } from './src/components/data-column/data-column-list.component';
@@ -57,6 +58,7 @@ export * from './src/directives/upload.directive';
export * from './src/utils/index';
export * from './src/events/base.event';
export * from './src/events/base-ui.event';
+export * from './src/events/folder-created.event';
export const ALFRESCO_CORE_PROVIDERS: any[] = [
NotificationService,
@@ -101,7 +103,8 @@ export function createTranslateLoader(http: Http, logService: LogService) {
...COLLAPSABLE_DIRECTIVES,
UploadDirective,
DataColumnComponent,
- DataColumnListComponent
+ DataColumnListComponent,
+ FileSizePipe
],
providers: [
...ALFRESCO_CORE_PROVIDERS
@@ -119,7 +122,8 @@ export function createTranslateLoader(http: Http, logService: LogService) {
UploadDirective,
DataColumnComponent,
DataColumnListComponent,
- MdSnackBarModule
+ MdSnackBarModule,
+ FileSizePipe
]
})
export class CoreModule {
diff --git a/ng2-components/ng2-alfresco-upload/src/events/folder-created.event.ts b/ng2-components/ng2-alfresco-core/src/events/folder-created.event.ts
similarity index 100%
rename from ng2-components/ng2-alfresco-upload/src/events/folder-created.event.ts
rename to ng2-components/ng2-alfresco-core/src/events/folder-created.event.ts
diff --git a/ng2-components/ng2-alfresco-core/src/pipes/file-size.pipe.ts b/ng2-components/ng2-alfresco-core/src/pipes/file-size.pipe.ts
new file mode 100644
index 0000000000..8be85ed2b4
--- /dev/null
+++ b/ng2-components/ng2-alfresco-core/src/pipes/file-size.pipe.ts
@@ -0,0 +1,36 @@
+/*!
+ * @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 { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+ name: 'adfFileSize'
+})
+export class FileSizePipe implements PipeTransform {
+
+ transform(bytes: number = 0, decimals: number = 2): string {
+ if (bytes === 0) {
+ return '0 Bytes';
+ }
+ const k = 1024,
+ dm = decimals || 2,
+ sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
+ i = Math.floor(Math.log(bytes) / Math.log(k));
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
+ }
+
+}
diff --git a/ng2-components/ng2-alfresco-core/src/services/alfresco-content.service.ts b/ng2-components/ng2-alfresco-core/src/services/alfresco-content.service.ts
index ca50c87025..03b950a82f 100644
--- a/ng2-components/ng2-alfresco-core/src/services/alfresco-content.service.ts
+++ b/ng2-components/ng2-alfresco-core/src/services/alfresco-content.service.ts
@@ -16,15 +16,18 @@
*/
import { Injectable } from '@angular/core';
-
+import { Observable, Subject } from 'rxjs/Rx';
+import { MinimalNodeEntity } from 'alfresco-js-api';
import { AlfrescoAuthenticationService } from './alfresco-authentication.service';
import { AlfrescoApiService } from './alfresco-api.service';
-import { LogService } from './log.service.ts';
-import { Observable } from 'rxjs/Rx';
+import { LogService } from './log.service';
+import { FolderCreatedEvent } from '../events/folder-created.event';
@Injectable()
export class AlfrescoContentService {
+ folderCreated: Subject = new Subject();
+
constructor(public authService: AlfrescoAuthenticationService,
public apiService: AlfrescoApiService,
private logService: LogService) {
@@ -70,6 +73,23 @@ export class AlfrescoContentService {
})).catch(this.handleError);
}
+ /**
+ * Create a folder
+ * @param name - the folder name
+ */
+ createFolder(relativePath: string, name: string, parentId?: string): Observable {
+ return Observable.fromPromise(this.apiService.getInstance().nodes.createFolder(name, relativePath, parentId))
+ .do(data => {
+ this.folderCreated.next({
+ relativePath: relativePath,
+ name: name,
+ parentId: parentId,
+ node: data
+ });
+ })
+ .catch(err => this.handleError(err));
+ }
+
private handleError(error: any) {
this.logService.error(error);
return Observable.throw(error || 'Server error');
diff --git a/ng2-components/ng2-alfresco-upload/README.md b/ng2-components/ng2-alfresco-upload/README.md
index fae3b7bbe2..ed6548d593 100644
--- a/ng2-components/ng2-alfresco-upload/README.md
+++ b/ng2-components/ng2-alfresco-upload/README.md
@@ -18,20 +18,25 @@
-
-
-
-
-
-
-
-
-
-
-
-
+## Content
+
+### Components
+
+- [FileUploadingDialogComponent](#fileuploadingdialogcomponent)
+- FileUploadingListComponent
+- [UploadButtonComponent](#uploadbuttoncomponent)
+- [UploadDragAreaComponent](#uploaddragareacomponent)
+
+### Services
+
+- [UploadService](#uploadservice)
+
+### Directives
+
+- FileDraggableDirective
+
## Prerequisites
Before you start using this development framework, make sure you have installed all required software and done all the
@@ -93,19 +98,17 @@ Follow the 3 steps below:
Please refer to the following example file: [systemjs.config.js](demo/systemjs.config.js) .
-
-
-#### Basic usage
-
+## UploadButtonComponent
```html
-
+
```
@@ -121,26 +124,27 @@ import { UploadModule } from 'ng2-alfresco-upload';
@Component({
selector: 'alfresco-app-demo',
- template: `
-
- `
+ template: `
+
+
+
+ `
})
export class MyDemoApp {
- constructor(private authService: AlfrescoAuthenticationService, private settingsService: AlfrescoSettingsService) {
+ constructor(private authService: AlfrescoAuthenticationService,
+ private settingsService: AlfrescoSettingsService) {
settingsService.ecmHost = 'http://localhost:8080';
this.authService.login('admin', 'admin').subscribe(
- ticket => {
- console.log(ticket);
- },
- error => {
- console.log(error);
- });
+ ticket => console.log(ticket),
+ error => console.log(error)
+ );
}
public onSuccess(event: Object): void {
@@ -160,15 +164,15 @@ export class MyDemoApp {
export class AppModule { }
platformBrowserDynamic().bootstrapModule(AppModule);
-
```
-#### Events
+
+### Events
| Name | Description |
| --- | --- |
| `onSuccess` | The event is emitted when the file is uploaded |
-#### Properties
+### Properties
| Name | Type | Default | Description |
| --- | --- | --- | --- |
@@ -182,7 +186,10 @@ platformBrowserDynamic().bootstrapModule(AppModule);
| `staticTitle` | *string* | 'FILE_UPLOAD.BUTTON.UPLOAD_FILE' or 'FILE_UPLOAD.BUTTON.UPLOAD_FOLDER' string in the JSON text file | define the text of the upload button |
| `disableWithNoPermission` | *boolean* | false | If the value is true and the user doesn't have the permission to delete the node the button will be disabled |
-### How to show notification message with no permission
+### Advanced usage
+
+#### How to show notification message with no permission
+
You can show a notification error when the user doesn't have the right permission to perform the action.
The UploadButtonComponent provides the event permissionEvent that is raised when the delete permission is missing
You can subscribe to this event from your component and use the NotificationService to show a message.
@@ -195,9 +202,11 @@ You can subscribe to this event from your component and use the NotificationServ
export class MyComponent {
-onUploadPermissionFailed(event: any) {
- this.notificationService.openSnackMessage(`you don't have the ${event.permission} permission to ${event.action} the ${event.type} `, 4000);
-}
+ onUploadPermissionFailed(event: any) {
+ this.notificationService.openSnackMessage(
+ `you don't have the ${event.permission} permission to ${event.action} the ${event.type} `, 4000
+ );
+ }
}
```
@@ -205,6 +214,7 @@ onUploadPermissionFailed(event: any) {

#### How to disable the button when the delete permission is missing
+
You can easily disable the button when the user doesn't own the permission to perform the action.
The UploadButtonComponent provides the property disableWithNoPermission that can be true. In this way the button should be disabled if the delete permission is missing for the node.
@@ -217,19 +227,18 @@ The UploadButtonComponent provides the property disableWithNoPermission that can

+## UploadDragAreaComponent
-
-### Drag and drop
This component, provide a drag and drop are to upload files to alfresco.
-#### Basic usage
-
```html
-
+
+
```
-Example of an App that declares upload drag and drop component :
+Example of an App that declares upload drag and drop component:
```ts
import { NgModule, Component } from '@angular/core';
@@ -240,25 +249,25 @@ import { UploadModule } from 'ng2-alfresco-upload';
@Component({
selector: 'alfresco-app-demo',
- template: `
-
- DRAG HERE
-
-
- `
+ template: `
+
+
+ DRAG HERE
+
+
+
+ `
})
export class MyDemoApp {
- constructor(private authService: AlfrescoAuthenticationService, private settingsService: AlfrescoSettingsService) {
+ constructor(private authService: AlfrescoAuthenticationService,
+ private settingsService: AlfrescoSettingsService) {
settingsService.ecmHost = 'http://localhost:8080';
this.authService.login('admin', 'admin').subscribe(
- ticket => {
- console.log(ticket);
- },
- error => {
- console.log(error);
- });
+ ticket => console.log(ticket),
+ error => console.log(error)
+ );
}
public onSuccess(event: Object): void {
@@ -278,16 +287,15 @@ export class MyDemoApp {
export class AppModule { }
platformBrowserDynamic().bootstrapModule(AppModule);
-
```
-#### Events
+### Events
| Name | Description |
| --- | --- |
| `onSuccess` | The event is emitted when the file is uploaded |
-#### Properties
+### Properties
| Name | Type | Default | Description |
| --- | --- | --- | --- |
@@ -297,27 +305,31 @@ platformBrowserDynamic().bootstrapModule(AppModule);
| `currentFolderPath` | *string* | '/' | define the path where the files are uploaded |
| `versioning` | *boolean* | false | Versioning false is the default uploader behaviour and it rename using an integer suffix if there is a name clash. Versioning true to indicate that a major version should be created |
-
-### Files Dialog
+## FileUploadingDialogComponent
This component provides a dialog that shows all the files uploaded with upload button or drag & drop area components.
This component should be used in combination with upload button or drag & drop area.
-#### Basic usage
-
```html
```
-### UploadService service
+## UploadService
Provides access to various APIs related to file upload features.
-#### Events
+### Events
| Name | Type | Description |
| --- | --- | --- |
-| folderCreated | FolderCreatedEvent | Raised when dropped folder gets created |
+| queueChanged | FileModel[] | Raised every time the file queue changes. |
+| fileUpload | FileUploadEvent | Raised every time a File model changes its state. |
+| fileUploadStarting | FileUploadEvent | Raised when upload starts. |
+| fileUploadCancelled | FileUploadEvent | Raised when upload gets cancelled by user. |
+| fileUploadProgress | FileUploadEvent | Raised during file upload process and contains the current progress for the particular File model. |
+| fileUploadAborted | FileUploadEvent | Raised when file upload gets aborted by the server. |
+| fileUploadError | FileUploadEvent | Raised when an error occurs to file upload. |
+| fileUploadComplete | FileUploadCompleteEvent | Raised when file upload is complete. |
## Build from sources
@@ -331,7 +343,7 @@ npm run build
### Build the files and keep watching for changes
```sh
-$ npm run build:w
+npm run build:w
```
## Running unit tests
diff --git a/ng2-components/ng2-alfresco-upload/index.ts b/ng2-components/ng2-alfresco-upload/index.ts
index cf80ddf32c..feda25c1a6 100644
--- a/ng2-components/ng2-alfresco-upload/index.ts
+++ b/ng2-components/ng2-alfresco-upload/index.ts
@@ -16,7 +16,7 @@
*/
import { NgModule, ModuleWithProviders } from '@angular/core';
-import { MdIconModule } from '@angular/material';
+import { MdIconModule, MdProgressSpinnerModule, MdButtonModule } from '@angular/material';
import { CoreModule } from 'ng2-alfresco-core';
import { UploadDragAreaComponent } from './src/components/upload-drag-area.component';
@@ -26,22 +26,6 @@ import { FileUploadingDialogComponent } from './src/components/file-uploading-di
import { FileUploadingListComponent } from './src/components/file-uploading-list.component';
import { UploadService } from './src/services/upload.service';
-/**
- * ng2-alfresco-upload, provide components to upload files to alfresco repository.
- *
- * Components provided:
- * - A button to upload files
- *
- *
- *
- * - Drag and drop area to upload files:
- *
- */
-
export * from './src/components/upload-button.component';
export * from './src/components/file-uploading-dialog.component';
export * from './src/components/upload-drag-area.component';
@@ -50,7 +34,7 @@ export * from './src/directives/file-draggable.directive';
export * from './src/components/file-uploading-list.component';
export * from './src/models/file.model';
export * from './src/models/permissions.model';
-export * from './src/events/folder-created.event';
+export * from './src/events/file.event';
export const UPLOAD_DIRECTIVES: any[] = [
FileDraggableDirective,
@@ -67,7 +51,9 @@ export const UPLOAD_PROVIDERS: any[] = [
@NgModule({
imports: [
CoreModule,
- MdIconModule
+ MdIconModule,
+ MdProgressSpinnerModule,
+ MdButtonModule
],
declarations: [
...UPLOAD_DIRECTIVES
diff --git a/ng2-components/ng2-alfresco-upload/src/components/file-uploading-dialog.component.css b/ng2-components/ng2-alfresco-upload/src/components/file-uploading-dialog.component.css
index 18f439caa6..18c8d8dc65 100644
--- a/ng2-components/ng2-alfresco-upload/src/components/file-uploading-dialog.component.css
+++ b/ng2-components/ng2-alfresco-upload/src/components/file-uploading-dialog.component.css
@@ -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);
diff --git a/ng2-components/ng2-alfresco-upload/src/components/file-uploading-dialog.component.spec.ts b/ng2-components/ng2-alfresco-upload/src/components/file-uploading-dialog.component.spec.ts
index 9f80049247..11dde66c35 100644
--- a/ng2-components/ng2-alfresco-upload/src/components/file-uploading-dialog.component.spec.ts
+++ b/ng2-components/ng2-alfresco-upload/src/components/file-uploading-dialog.component.spec.ts
@@ -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');
diff --git a/ng2-components/ng2-alfresco-upload/src/components/file-uploading-dialog.component.ts b/ng2-components/ng2-alfresco-upload/src/components/file-uploading-dialog.component.ts
index 08de586a3a..bee9dc6f3e 100644
--- a/ng2-components/ng2-alfresco-upload/src/components/file-uploading-dialog.component.ts
+++ b/ng2-components/ng2-alfresco-upload/src/components/file-uploading-dialog.component.ts
@@ -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';
-/**
- *
- *
- * 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();
}
}
diff --git a/ng2-components/ng2-alfresco-upload/src/components/file-uploading-list.component.css b/ng2-components/ng2-alfresco-upload/src/components/file-uploading-list.component.css
index 6226775cad..c9aa522686 100644
--- a/ng2-components/ng2-alfresco-upload/src/components/file-uploading-list.component.css
+++ b/ng2-components/ng2-alfresco-upload/src/components/file-uploading-list.component.css
@@ -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;
}
diff --git a/ng2-components/ng2-alfresco-upload/src/components/file-uploading-list.component.html b/ng2-components/ng2-alfresco-upload/src/components/file-uploading-list.component.html
index 24b3b87887..00fe97a588 100644
--- a/ng2-components/ng2-alfresco-upload/src/components/file-uploading-list.component.html
+++ b/ng2-components/ng2-alfresco-upload/src/components/file-uploading-list.component.html
@@ -6,32 +6,37 @@
- {{'FILE_UPLOAD.FILE_INFO.NAME' | translate}} |
- {{'FILE_UPLOAD.FILE_INFO.PROGRESS' | translate}} |
- {{'FILE_UPLOAD.FILE_INFO.SIZE' | translate}} |
- {{'FILE_UPLOAD.FILE_INFO.ACTION' | translate}} |
+ {{'ADF_FILE_UPLOAD.FILE_LIST.NAME' | translate}} |
+ {{'ADF_FILE_UPLOAD.FILE_LIST.PROGRESS' | translate}} |
+ {{'ADF_FILE_UPLOAD.FILE_LIST.SIZE' | translate}} |
+ {{'ADF_FILE_UPLOAD.FILE_LIST.ACTION' | translate}} |
-
- {{file.name}}
- |
-
-
-
-
-
+
+
|
- {{file.size}} |
-
-
- done
+ |
+ error_outline
+ block
+
+
+
+
+ |
+
+ {{ file.size | adfFileSize }}
+ |
+
+
+ done
-
- remove_circle_outline
-
-
- remove_circle
+
+ remove_circle_outline
|
|
diff --git a/ng2-components/ng2-alfresco-upload/src/components/file-uploading-list.component.ts b/ng2-components/ng2-alfresco-upload/src/components/file-uploading-list.component.ts
index dc1285fbc1..2b399be04d 100644
--- a/ng2-components/ng2-alfresco-upload/src/components/file-uploading-list.component.ts
+++ b/ng2-components/ng2-alfresco-upload/src/components/file-uploading-list.component.ts
@@ -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';
-/**
- *
- *
- * 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;
}
diff --git a/ng2-components/ng2-alfresco-upload/src/components/upload-button.component.spec.ts b/ng2-components/ng2-alfresco-upload/src/components/upload-button.component.spec.ts
index 4d8dd1fa00..3ade2ab971 100644
--- a/ng2-components/ng2-alfresco-upload/src/components/upload-button.component.spec.ts
+++ b/ng2-components/ng2-alfresco-upload/src/components/upload-button.component.spec.ts
@@ -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;
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();
});
diff --git a/ng2-components/ng2-alfresco-upload/src/components/upload-button.component.ts b/ng2-components/ng2-alfresco-upload/src/components/upload-button.component.ts
index 3c606a91cd..413b76e58d 100644
--- a/ng2-components/ng2-alfresco-upload/src/components/upload-button.component.ts
+++ b/ng2-components/ng2-alfresco-upload/src/components/upload-button.component.ts
@@ -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;
-/**
- *
- *
- *
- * 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 {
+ 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;
diff --git a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.spec.ts b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.spec.ts
index be61774416..cde3898be4 100644
--- a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.spec.ts
+++ b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.spec.ts
@@ -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);
- });
});
diff --git a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.ts b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.ts
index 43cf6efa11..799714a9b1 100644
--- a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.ts
+++ b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.ts
@@ -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;
-/**
- *
- *
- * 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);
});
}
diff --git a/ng2-components/ng2-alfresco-upload/src/directives/file-draggable.directive.ts b/ng2-components/ng2-alfresco-upload/src/directives/file-draggable.directive.ts
index f48dbf04a2..5932e2a5c3 100644
--- a/ng2-components/ng2-alfresco-upload/src/directives/file-draggable.directive.ts
+++ b/ng2-components/ng2-alfresco-upload/src/directives/file-draggable.directive.ts
@@ -17,17 +17,6 @@
import { Directive, EventEmitter, Input, Output, OnInit, OnDestroy, ElementRef, NgZone } from '@angular/core';
-/**
- * [file-draggable]
- *
- * This directive, provide a drag and drop area for files and folders.
- *
- * @OutputEvent {EventEmitter} onFilesDropped(File)- event fired fot each file dropped
- * in the drag and drop area.
- *
- *
- * @returns {FileDraggableDirective} .
- */
@Directive({
selector: '[file-draggable]'
})
diff --git a/ng2-components/ng2-alfresco-upload/src/events/file.event.ts b/ng2-components/ng2-alfresco-upload/src/events/file.event.ts
new file mode 100644
index 0000000000..0e66b1ce65
--- /dev/null
+++ b/ng2-components/ng2-alfresco-upload/src/events/file.event.ts
@@ -0,0 +1,36 @@
+/*!
+ * @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 { FileModel, FileUploadStatus } from '../models/file.model';
+
+export class FileUploadEvent {
+
+ constructor(
+ public readonly file: FileModel,
+ public readonly status: FileUploadStatus = FileUploadStatus.Pending,
+ public readonly error: any = null) {
+ }
+
+}
+
+export class FileUploadCompleteEvent extends FileUploadEvent {
+
+ constructor(file: FileModel, public totalComplete: number = 0) {
+ super(file, FileUploadStatus.Complete);
+ }
+
+}
diff --git a/ng2-components/ng2-alfresco-upload/src/i18n/en.json b/ng2-components/ng2-alfresco-upload/src/i18n/en.json
index 96a5eb086f..b8f19e1f76 100644
--- a/ng2-components/ng2-alfresco-upload/src/i18n/en.json
+++ b/ng2-components/ng2-alfresco-upload/src/i18n/en.json
@@ -1,25 +1,27 @@
{
- "FILE_UPLOAD": {
- "BUTTON": {
- "UPLOAD_FILE": "Upload file",
- "UPLOAD_FOLDER": "Upload folder",
- "CANCEL_ALL": "Cancell all"
+ "ADF_FILE_UPLOAD": {
+ "FILE_LIST": {
+ "NAME": "Name",
+ "PROGRESS": "Progress",
+ "SIZE": "Size",
+ "ACTION": "Action"
+ }
},
- "MESSAGES": {
- "SINGLE_COMPLETED": "upload complete",
- "COMPLETED": "uploads complete",
- "PROGRESS": "Upload in progress...",
- "FOLDER_ALREADY_EXIST": "The folder {0} already exist",
- "FOLDER_NOT_SUPPORTED": "Folder upload isn't supported by your browser"
- },
- "FILE_INFO": {
- "NAME": "File name",
- "PROGRESS": "File progress",
- "SIZE": "File size",
- "ACTION": "Actions"
- },
- "ACTION": {
- "UNDO": "Undo"
+ "FILE_UPLOAD": {
+ "BUTTON": {
+ "UPLOAD_FILE": "Upload file",
+ "UPLOAD_FOLDER": "Upload folder",
+ "CANCEL_ALL": "Cancell all"
+ },
+ "MESSAGES": {
+ "SINGLE_COMPLETED": "upload complete",
+ "COMPLETED": "uploads complete",
+ "PROGRESS": "Upload in progress...",
+ "FOLDER_ALREADY_EXIST": "The folder {0} already exist",
+ "FOLDER_NOT_SUPPORTED": "Folder upload isn't supported by your browser"
+ },
+ "ACTION": {
+ "UNDO": "Undo"
+ }
}
- }
}
diff --git a/ng2-components/ng2-alfresco-upload/src/models/file.model.ts b/ng2-components/ng2-alfresco-upload/src/models/file.model.ts
index eae4b8d054..d9a0e12a8d 100644
--- a/ng2-components/ng2-alfresco-upload/src/models/file.model.ts
+++ b/ng2-components/ng2-alfresco-upload/src/models/file.model.ts
@@ -15,130 +15,58 @@
* limitations under the License.
*/
-/**
- *
- * This object represent the status of an uploading file.
- *
- *
- * @returns {FileModel} .
- */
-export class FileModel {
- id: string;
- status: number;
- statusText: string;
- progress: Object;
- name: string;
- size: string;
- response: string;
- done: boolean = false;
- error: boolean = false;
- abort: boolean = false;
- uploading: boolean = false;
- file: File;
- promiseUpload: any;
-
- options: FileUploadOptions;
-
- constructor(file: File, options?: FileUploadOptions) {
- this.file = file;
- this.options = Object.assign({}, {
- newVersion: false
- }, options);
- this.id = this.generateId();
- this.name = file.name;
- this.size = this.getFileSize(file.size);
- this.progress = {
- loaded: 0,
- total: 0,
- percent: 0
- };
- }
-
- setProgres(progress: any): void {
- this.progress = progress;
- }
-
- /**
- * Emit an event progress on the promise
- */
- emitProgres(progress: any): void {
- this.setProgres(progress);
- this.promiseUpload.emit('progress', progress);
- }
-
- setError(): void {
- this.error = true;
- }
-
- /**
- * Emit an event progress on the promise
- */
- emitError(): void {
- this.setError();
- this.promiseUpload.emit('error');
- }
-
- setUploading() {
- this.uploading = true;
- }
-
- setPromiseUpload(promiseUpload: any) {
- this.promiseUpload = promiseUpload;
- }
-
- /**
- * Stop the uploading of the file.
- */
- setAbort(): void {
- if (!this.done && !this.error) {
- this.abort = true;
- this.uploading = false;
- }
- }
-
- /**
- * Emit an event abort on the promise
- */
- emitAbort(): void {
- this.setAbort();
- this.promiseUpload.abort();
- }
-
- /**
- * Update status of the file when upload finish or is ended.
- */
- onFinished(status: number, statusText: string, response: string): void {
- this.status = status;
- this.statusText = statusText;
- this.response = response;
- this.done = true;
- this.uploading = false;
- }
-
- /**
- * Calculate the size of the file in kb,mb and gb.
- *
- * @param {number} sizeinbytes - size in bytes of the file.
- */
- private getFileSize(sizeinbytes: number): string {
- let fSExt = new Array('Bytes', 'KB', 'MB', 'GB');
- let size = sizeinbytes;
- let i = 0;
- while (size > 900) {
- size /= 1000;
- i++;
- }
- return Math.round((Math.round(size * 100) / 100)) + ' ' + fSExt[i];
- }
-
- private generateId(): string {
- return 'uploading-file-' + 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
- let r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
- return v.toString(16);
- });
- }
+export interface FileUploadProgress {
+ loaded: number;
+ total: number;
+ percent: number;
}
export interface FileUploadOptions {
newVersion?: boolean;
}
+
+export enum FileUploadStatus {
+ Pending = 0,
+ Complete = 1,
+ Starting = 2,
+ Progress = 3,
+ Cancelled = 4,
+ Aborted = 5,
+ Error = 6
+}
+
+export class FileModel {
+ readonly id: string;
+ readonly name: string;
+ readonly size: number;
+ readonly file: File;
+
+ status: FileUploadStatus = FileUploadStatus.Pending;
+ progress: FileUploadProgress;
+ options: FileUploadOptions;
+
+ constructor(file: File, options?: FileUploadOptions) {
+ this.file = file;
+
+ this.id = this.generateId();
+ this.name = file.name;
+ this.size = file.size;
+
+ this.progress = {
+ loaded: 0,
+ total: 0,
+ percent: 0
+ };
+
+ this.options = Object.assign({}, {
+ newVersion: false
+ }, options);
+ }
+
+ private generateId(): string {
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+ let r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
+ return v.toString(16);
+ });
+ }
+}
diff --git a/ng2-components/ng2-alfresco-upload/src/services/upload.service.spec.ts b/ng2-components/ng2-alfresco-upload/src/services/upload.service.spec.ts
index 086d536752..6c4f09faa2 100644
--- a/ng2-components/ng2-alfresco-upload/src/services/upload.service.spec.ts
+++ b/ng2-components/ng2-alfresco-upload/src/services/upload.service.spec.ts
@@ -124,89 +124,7 @@ describe('UploadService', () => {
service.uploadFilesInTheQueue('-root-', '', emitter);
let file = service.getQueue();
- file[0].emitAbort();
- });
-
- it('should make XHR error request after the xhr error is called', (done) => {
- let emitter = new EventEmitter();
-
- emitter.subscribe(e => {
- expect(e.value).toBe('Error file uploaded');
- done();
- });
- let fileFake = new FileModel({name: 'fake-name', size: 10});
- service.addToQueue(fileFake);
- service.uploadFilesInTheQueue('-root-', '', emitter);
-
- let file = service.getQueue();
- file[0].emitError();
- });
-
- it('should make XHR progress request after the onprogress is called', (done) => {
- let fakeProgress = {
- loaded: 500,
- total: 1234,
- percent: 44
- };
- let filesFake = new FileModel({name: 'fake-name', size: 10});
- service.addToQueue(filesFake);
- service.filesUpload$.subscribe((file) => {
- expect(file).toBeDefined();
- expect(file[0]).toBeDefined();
- expect(file[0].progress).toEqual(fakeProgress);
- done();
- });
- service.uploadFilesInTheQueue('-root-', '', null);
-
- let file = service.getQueue();
-
- file[0].emitProgres(fakeProgress);
- });
-
- it('should make XHR done request after the folder is created', (done) => {
- let fakeRest = {
- entry: {
- isFile: false,
- isFolder: true,
- name: 'fake-folder'
- }
- };
- let fakePromise = new Promise(function (resolve, reject) {
- resolve(fakeRest);
- });
- spyOn(service, 'callApiCreateFolder').and.returnValue(fakePromise);
- let defaultPath = '';
- let folderName = 'fake-folder';
- service.createFolder(defaultPath, folderName).subscribe(res => {
- expect(res).toEqual(fakeRest);
- done();
- });
- });
-
- it('should throws an exception when a folder already exist', (done) => {
- let fakeRest = {
- response: {
- body: {
- error: {
- statusCode: 409
- }
- }
- }
- };
- let fakePromise = new Promise(function (resolve, reject) {
- reject(fakeRest);
- });
- spyOn(service, 'callApiCreateFolder').and.returnValue(fakePromise);
- let defaultPath = '';
- let folderName = 'folder-duplicate-fake';
- service.createFolder(defaultPath, folderName).subscribe(
- res => {
- },
- error => {
- expect(error).toEqual(fakeRest);
- done();
- }
- );
+ service.cancelUpload(...file);
});
it('If versioning is true autoRename should not be present and majorVersion should be a param', () => {
diff --git a/ng2-components/ng2-alfresco-upload/src/services/upload.service.ts b/ng2-components/ng2-alfresco-upload/src/services/upload.service.ts
index 5131083e1b..0787f476f9 100644
--- a/ng2-components/ng2-alfresco-upload/src/services/upload.service.ts
+++ b/ng2-components/ng2-alfresco-upload/src/services/upload.service.ts
@@ -16,36 +16,38 @@
*/
import { EventEmitter, Injectable } from '@angular/core';
-import { Response } from '@angular/http';
-import { Observer, Observable, Subject } from 'rxjs/Rx';
+import { Subject } from 'rxjs/Rx';
import { AlfrescoApiService, LogService } from 'ng2-alfresco-core';
-import { FolderCreatedEvent } from '../events/folder-created.event';
-import { FileModel } from '../models/file.model';
-import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api';
+import { FileUploadEvent, FileUploadCompleteEvent } from '../events/file.event';
+import { FileModel, FileUploadProgress, FileUploadStatus } from '../models/file.model';
-/**
- *
- * UploadService keep the queue of the file to upload and uploads them.
- *
- * @returns {UploadService} .
- */
@Injectable()
export class UploadService {
private queue: FileModel[] = [];
- private filesUploadObserverProgressBar: Observer;
- private totalCompletedObserver: Observer;
+ private cache: { [key: string]: any } = {};
+ private totalComplete: number = 0;
- totalCompleted: number = 0;
- filesUpload$: Observable;
- totalCompleted$: Observable;
-
- folderCreated: Subject = new Subject();
+ queueChanged: Subject = new Subject();
+ fileUpload: Subject = new Subject();
+ fileUploadStarting: Subject = new Subject();
+ fileUploadCancelled: Subject = new Subject();
+ fileUploadProgress: Subject = new Subject();
+ fileUploadAborted: Subject = new Subject();
+ fileUploadError: Subject = new Subject();
+ fileUploadComplete: Subject = new Subject();
constructor(private apiService: AlfrescoApiService,
private logService: LogService) {
- this.filesUpload$ = new Observable(observer => this.filesUploadObserverProgressBar = observer).share();
- this.totalCompleted$ = new Observable(observer => this.totalCompletedObserver = observer).share();
+ }
+
+ /**
+ * Returns the file Queue
+ *
+ * @return {FileModel[]} - files in the upload queue.
+ */
+ getQueue(): FileModel[] {
+ return this.queue;
}
/**
@@ -59,9 +61,7 @@ export class UploadService {
addToQueue(...files: FileModel[]): FileModel[] {
const allowedFiles = files.filter(f => !f.name.startsWith('.'));
this.queue = this.queue.concat(allowedFiles);
- if (this.filesUploadObserverProgressBar) {
- this.filesUploadObserverProgressBar.next(this.queue);
- }
+ this.queueChanged.next(this.queue);
return allowedFiles;
}
@@ -69,125 +69,142 @@ export class UploadService {
* Pick all the files in the queue that are not been uploaded yet and upload it into the directory folder.
*/
uploadFilesInTheQueue(rootId: string, directory: string, elementEmit: EventEmitter): void {
- let filesToUpload = this.queue.filter((file) => {
- return !file.uploading && !file.done && !file.abort && !file.error;
- });
+ const files = this.getFilesToUpload();
- filesToUpload.forEach((uploadingFileModel: FileModel) => {
- uploadingFileModel.setUploading();
+ files.forEach((file: FileModel) => {
+ this.onUploadStarting(file);
const opts: any = {
renditions: 'doclib'
};
- if (uploadingFileModel.options.newVersion === true) {
+ if (file.options.newVersion === true) {
opts.overwrite = true;
opts.majorVersion = true;
} else {
opts.autoRename = true;
}
- let promiseUpload = this.apiService.getInstance().upload.uploadFile(uploadingFileModel.file, directory, rootId, null, opts)
- .on('progress', (progress: any) => {
- uploadingFileModel.setProgres(progress);
- this.updateFileListStream(this.queue);
- })
- .on('abort', () => {
- uploadingFileModel.setAbort();
- elementEmit.emit({
- value: 'File aborted'
- });
- })
- .on('error', () => {
- uploadingFileModel.setError();
- elementEmit.emit({
- value: 'Error file uploaded'
- });
- })
- .on('success', (data: any) => {
- elementEmit.emit({
- value: data
- });
- uploadingFileModel.onFinished(
- data.status,
- data.statusText,
- data.response
- );
-
- this.updateFileListStream(this.queue);
- if (!uploadingFileModel.abort && !uploadingFileModel.error) {
- this.updateFileCounterStream(++this.totalCompleted);
- }
+ const promise = this.apiService.getInstance().upload.uploadFile(file.file, directory, rootId, null, opts);
+ promise.on('progress', (progress: FileUploadProgress) => {
+ this.onUploadProgress(file, progress);
+ })
+ .on('abort', () => {
+ this.onUploadAborted(file);
+ elementEmit.emit({
+ value: 'File aborted'
});
+ })
+ .on('error', err => {
+ this.onUploadError(file, err);
+ elementEmit.emit({
+ value: 'Error file uploaded'
+ });
+ })
+ .on('success', data => {
+ this.onUploadComplete(file);
+ elementEmit.emit({
+ value: data
+ });
+ })
+ .catch((err) => {
+ this.onUploadError(file, err);
+ });
- uploadingFileModel.setPromiseUpload(promiseUpload);
+ this.cache[file.id] = promise;
});
}
- /**
- * Return all the files in the uploading queue.
- *
- * @return {FileModel[]} - files in the upload queue.
- */
- getQueue(): FileModel[] {
- return this.queue;
+ cancelUpload(...files: FileModel[]) {
+ files.forEach(file => {
+ file.status = FileUploadStatus.Cancelled;
+
+ const promise = this.cache[file.id];
+ if (promise) {
+ promise.abort();
+ delete this.cache[file.id];
+ }
+
+ const event = new FileUploadEvent(file, FileUploadStatus.Cancelled);
+ this.fileUpload.next(event);
+ this.fileUploadCancelled.next(event);
+ });
}
- /**
- * Create a folder
- * @param name - the folder name
- */
- createFolder(relativePath: string, name: string, parentId?: string): Observable {
- return Observable.fromPromise(this.callApiCreateFolder(relativePath, name, parentId))
- .do(data => {
- this.folderCreated.next({
- relativePath: relativePath,
- name: name,
- parentId: parentId,
- node: data
- });
- })
- .catch(err => this.handleError(err));
- }
-
- callApiCreateFolder(relativePath: string, name: string, parentId?: string): Promise {
- return this.apiService.getInstance().nodes.createFolder(name, relativePath, parentId);
- }
-
- /**
- * Throw the error
- * @param error
- * @returns {ErrorObservable}
- */
- 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 updateFileListStream(fileList: FileModel[]) {
- if (this.filesUploadObserverProgressBar) {
- this.filesUploadObserverProgressBar.next(fileList);
+ private onUploadStarting(file: FileModel): void {
+ if (file) {
+ file.status = FileUploadStatus.Starting;
+ const event = new FileUploadEvent(file, FileUploadStatus.Starting);
+ this.fileUpload.next(event);
+ this.fileUploadStarting.next(event);
}
}
- updateFileCounterStream(total: number) {
- if (this.totalCompletedObserver) {
- this.totalCompletedObserver.next(total);
+ private onUploadProgress(file: FileModel, progress: FileUploadProgress): void {
+ if (file) {
+ file.progress = progress;
+ file.status = FileUploadStatus.Progress;
+
+ const event = new FileUploadEvent(file, FileUploadStatus.Progress);
+ this.fileUpload.next(event);
+ this.fileUploadProgress.next(event);
+
+ this.queueChanged.next(this.queue);
}
}
- getFolderNode(nodeId: string): Observable {
- let opts: any = {
- includeSource: true,
- include: ['allowableOperations']
- };
+ private onUploadError(file: FileModel, error: any): void {
+ if (file) {
+ file.status = FileUploadStatus.Error;
- return Observable.fromPromise(this.apiService.getInstance().nodes.getNodeInfo(nodeId, opts))
- .map((response: any) => {
- return response;
- })
- .catch(err => this.handleError(err));
+ const promise = this.cache[file.id];
+ if (promise) {
+ delete this.cache[file.id];
+ }
+
+ const event = new FileUploadEvent(file, FileUploadStatus.Error, error);
+ this.fileUpload.next(event);
+ this.fileUploadError.next(event);
+ }
+ }
+
+ private onUploadComplete(file: FileModel): void {
+ if (file) {
+ file.status = FileUploadStatus.Complete;
+ this.totalComplete++;
+
+ const promise = this.cache[file.id];
+ if (promise) {
+ delete this.cache[file.id];
+ }
+
+ const event = new FileUploadCompleteEvent(file, this.totalComplete);
+ this.fileUpload.next(event);
+ this.fileUploadComplete.next(event);
+
+ this.queueChanged.next(this.queue);
+ }
+ }
+
+ private onUploadAborted(file: FileModel): void {
+ if (file) {
+ file.status = FileUploadStatus.Aborted;
+
+ const promise = this.cache[file.id];
+ if (promise) {
+ delete this.cache[file.id];
+ }
+
+ const event = new FileUploadEvent(file, FileUploadStatus.Aborted);
+ this.fileUpload.next(event);
+ this.fileUploadAborted.next(event);
+ }
+ }
+
+ private getFilesToUpload(): FileModel[] {
+ let filesToUpload = this.queue.filter(file => {
+ return file.status === FileUploadStatus.Pending;
+ });
+ return filesToUpload;
}
}