From 7007c735e4fd932d92b7be589f1f801ae8f83850 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 2 Nov 2017 18:48:37 +0200 Subject: [PATCH 01/27] [ACA-968] Language Picker --- src/app.config.json | 45 ++++++++++++++++++- .../current-user/current-user.component.html | 9 ++++ .../current-user/current-user.component.ts | 11 ++++- src/assets/i18n/en.json | 1 + 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/app.config.json b/src/app.config.json index cbfca6409..6d3dbe894 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -4,6 +4,7 @@ "name": "Alfresco Example Content Application", "build": "1234" }, + "languagePicker": false, "document-list": { "supportedPageSizes": [ 25, @@ -18,5 +19,47 @@ "thumbs.db", ".git" ] - } + }, + "languages": [ + { + "key": "de", + "label": "German" + }, + { + "key": "en", + "label": "English" + }, + { + "key": "es", + "label": "Spanish" + }, + { + "key": "fr", + "label": "French" + }, + { + "key": "it", + "label": "Italian" + }, + { + "key": "ja", + "label": "Japanese" + }, + { + "key": "nb", + "label": "Norwegian" + }, + { + "key": "nl", + "label": "Dutch" + }, + { + "key": "pt-BR", + "label": "Brazilian Portuguese" + }, + { + "key": "ru", + "label": "Russian" + } + ] } diff --git a/src/app/components/current-user/current-user.component.html b/src/app/components/current-user/current-user.component.html index 461a4e632..29e77d41d 100644 --- a/src/app/components/current-user/current-user.component.html +++ b/src/app/components/current-user/current-user.component.html @@ -11,8 +11,17 @@ + + + + + + diff --git a/src/app/components/current-user/current-user.component.ts b/src/app/components/current-user/current-user.component.ts index cab8804f7..c37397a45 100644 --- a/src/app/components/current-user/current-user.component.ts +++ b/src/app/components/current-user/current-user.component.ts @@ -16,7 +16,7 @@ */ import { Component, OnInit, OnDestroy } from '@angular/core'; -import { PeopleContentService } from 'ng2-alfresco-core'; +import { PeopleContentService, AppConfigService } from 'ng2-alfresco-core'; import { Subscription } from 'rxjs/Rx'; @Component({ @@ -29,7 +29,10 @@ export class CurrentUserComponent implements OnInit, OnDestroy { user: any = null; - constructor(private peopleApi: PeopleContentService) {} + constructor( + private peopleApi: PeopleContentService, + private appConfig: AppConfigService + ) {} ngOnInit() { this.personSubscription = this.peopleApi.getCurrentPerson() @@ -61,4 +64,8 @@ export class CurrentUserComponent implements OnInit, OnDestroy { const { userFirstName: first, userLastName: last } = this; return [ first[0], last[0] ].join(''); } + + get showLanguagePicker() { + return this.appConfig.get('languagePicker') || false; + } } diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 34d7fb1b8..c5483baab 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -1,5 +1,6 @@ { "APP": { + "LANGUAGE": "Language", "SIGN_IN": "Sign in", "SIGN_OUT": "Sign out", "NEW_MENU": { From 8401f939cc0c82c45cf71f8cf68b61b672ded22f Mon Sep 17 00:00:00 2001 From: suzanadirla Date: Thu, 2 Nov 2017 18:50:24 +0200 Subject: [PATCH 02/27] [ACA-9380] fix Incorrect behavior when doing a multiple selection Copy or Move and only some of the items fail to be copied (#31) * [ACA-938] Incorrect behavior when doing a multiple selection Copy or Move and only some of the items fail to be copied * [ACA-938] Incorrect behavior when doing a multiple selection Copy or Move and only some of the items fail to be copied unit tests changes according to partial action changes --- .../directives/node-copy.directive.spec.ts | 76 +++++++++++++++++++ .../common/directives/node-copy.directive.ts | 19 ++++- .../services/node-actions.service.spec.ts | 33 ++++---- .../common/services/node-actions.service.ts | 30 +++----- src/assets/i18n/de.json | 6 +- src/assets/i18n/en.json | 8 +- src/assets/i18n/es.json | 6 +- src/assets/i18n/fr.json | 6 +- src/assets/i18n/it.json | 6 +- src/assets/i18n/ja.json | 6 +- src/assets/i18n/nb.json | 6 +- src/assets/i18n/nl.json | 6 +- src/assets/i18n/pt-BR.json | 6 +- src/assets/i18n/ru.json | 6 +- src/assets/i18n/zh-CN.json | 6 +- 15 files changed, 156 insertions(+), 70 deletions(-) diff --git a/src/app/common/directives/node-copy.directive.spec.ts b/src/app/common/directives/node-copy.directive.spec.ts index 84297332d..113df96da 100644 --- a/src/app/common/directives/node-copy.directive.spec.ts +++ b/src/app/common/directives/node-copy.directive.spec.ts @@ -116,6 +116,82 @@ describe('NodeCopyDirective', () => { ); }); + it('notifies partially copy of one node out of a multiple selection of nodes', () => { + spyOn(service, 'copyNodes').and.returnValue(Observable.of('OPERATION.SUCCES.CONTENT.COPY')); + + component.selection = [ + { entry: { id: 'node-to-copy-1', name: 'name1' } }, + { entry: { id: 'node-to-copy-2', name: 'name2' } }]; + const createdItems = [ + { entry: { id: 'copy-of-node-1', name: 'name1' } }]; + + fixture.detectChanges(); + element.triggerEventHandler('click', null); + service.contentCopied.next(createdItems); + + expect(service.copyNodes).toHaveBeenCalled(); + expect(notificationService.openSnackMessageAction).toHaveBeenCalledWith( + 'APP.MESSAGES.INFO.NODE_COPY.PARTIAL_SINGULAR', 'Undo', 10000 + ); + }); + + it('notifies partially copy of more nodes out of a multiple selection of nodes', () => { + spyOn(service, 'copyNodes').and.returnValue(Observable.of('OPERATION.SUCCES.CONTENT.COPY')); + + component.selection = [ + { entry: { id: 'node-to-copy-0', name: 'name0' } }, + { entry: { id: 'node-to-copy-1', name: 'name1' } }, + { entry: { id: 'node-to-copy-2', name: 'name2' } }]; + const createdItems = [ + { entry: { id: 'copy-of-node-0', name: 'name0' } }, + { entry: { id: 'copy-of-node-1', name: 'name1' } }]; + + fixture.detectChanges(); + element.triggerEventHandler('click', null); + service.contentCopied.next(createdItems); + + expect(service.copyNodes).toHaveBeenCalled(); + expect(notificationService.openSnackMessageAction).toHaveBeenCalledWith( + 'APP.MESSAGES.INFO.NODE_COPY.PARTIAL_PLURAL', 'Undo', 10000 + ); + }); + + it('notifies of failed copy of multiple nodes', () => { + spyOn(service, 'copyNodes').and.returnValue(Observable.of('OPERATION.SUCCES.CONTENT.COPY')); + + component.selection = [ + { entry: { id: 'node-to-copy-0', name: 'name0' } }, + { entry: { id: 'node-to-copy-1', name: 'name1' } }, + { entry: { id: 'node-to-copy-2', name: 'name2' } }]; + const createdItems = []; + + fixture.detectChanges(); + element.triggerEventHandler('click', null); + service.contentCopied.next(createdItems); + + expect(service.copyNodes).toHaveBeenCalled(); + expect(notificationService.openSnackMessageAction).toHaveBeenCalledWith( + 'APP.MESSAGES.INFO.NODE_COPY.FAIL_PLURAL', '', 3000 + ); + }); + + it('notifies of failed copy of one node', () => { + spyOn(service, 'copyNodes').and.returnValue(Observable.of('OPERATION.SUCCES.CONTENT.COPY')); + + component.selection = [ + { entry: { id: 'node-to-copy', name: 'name' } }]; + const createdItems = []; + + fixture.detectChanges(); + element.triggerEventHandler('click', null); + service.contentCopied.next(createdItems); + + expect(service.copyNodes).toHaveBeenCalled(); + expect(notificationService.openSnackMessageAction).toHaveBeenCalledWith( + 'APP.MESSAGES.INFO.NODE_COPY.FAIL_SINGULAR', '', 3000 + ); + }); + it('notifies error if success message was not emitted', () => { spyOn(service, 'copyNodes').and.returnValue(Observable.of('')); diff --git a/src/app/common/directives/node-copy.directive.ts b/src/app/common/directives/node-copy.directive.ts index 23c1b41e3..2e771f252 100644 --- a/src/app/common/directives/node-copy.directive.ts +++ b/src/app/common/directives/node-copy.directive.ts @@ -60,14 +60,27 @@ export class NodeCopyDirective { } private toastMessage(info: any, newItems?: MinimalNodeEntity[]) { - const numberOfCopiedItems = newItems ? newItems.length : ''; + const numberOfCopiedItems = newItems ? newItems.length : 0; + const failedItems = this.selection.length - numberOfCopiedItems; let i18nMessageString = 'APP.MESSAGES.ERRORS.GENERIC'; if (typeof info === 'string') { if (info.toLowerCase().indexOf('succes') !== -1) { + let i18MessageSuffix; + + if (failedItems) { + if (numberOfCopiedItems) { + i18MessageSuffix = ( numberOfCopiedItems === 1 ) ? 'PARTIAL_SINGULAR' : 'PARTIAL_PLURAL'; + + } else { + i18MessageSuffix = ( failedItems === 1 ) ? 'FAIL_SINGULAR' : 'FAIL_PLURAL'; + } + + } else { + i18MessageSuffix = ( numberOfCopiedItems === 1 ) ? 'SINGULAR' : 'PLURAL'; + } - const i18MessageSuffix = ( numberOfCopiedItems === 1 ) ? 'SINGULAR' : 'PLURAL'; i18nMessageString = `APP.MESSAGES.INFO.NODE_COPY.${i18MessageSuffix}`; } @@ -86,7 +99,7 @@ export class NodeCopyDirective { const undo = (numberOfCopiedItems > 0) ? 'Undo' : ''; const withUndo = (numberOfCopiedItems > 0) ? '_WITH_UNDO' : ''; - this.translation.get(i18nMessageString, { number: numberOfCopiedItems }).subscribe(message => { + this.translation.get(i18nMessageString, { success: numberOfCopiedItems, failed: failedItems }).subscribe(message => { this.notification.openSnackMessageAction(message, undo, NodeActionsService[`SNACK_MESSAGE_DURATION${withUndo}`]) .onAction() .subscribe(() => this.deleteCopy(newItems)); diff --git a/src/app/common/services/node-actions.service.spec.ts b/src/app/common/services/node-actions.service.spec.ts index 5de14c8b8..04861ec90 100644 --- a/src/app/common/services/node-actions.service.spec.ts +++ b/src/app/common/services/node-actions.service.spec.ts @@ -369,8 +369,8 @@ describe('NodeActionsService', () => { spyOnSuccess.calls.reset(); spyOnError.calls.reset(); copyObservable.toPromise().then( - () => { - spyOnSuccess(); + (response) => { + spyOnSuccess(response); }, () => { spyOnError(); @@ -382,8 +382,9 @@ describe('NodeActionsService', () => { { targetParentId: folderDestination.entry.id, name: undefined } ); }).then(() => { - expect(spyOnSuccess.calls.count()).toEqual(0); - expect(spyOnError.calls.count()).toEqual(1); + expect(spyOnSuccess.calls.count()).toEqual(1); + expect(spyOnSuccess).toHaveBeenCalledWith(permissionError); + expect(spyOnError.calls.count()).toEqual(0); }); })); @@ -401,16 +402,16 @@ describe('NodeActionsService', () => { spyOnError.calls.reset(); copyObservable.toPromise() .then( - () => { - spyOnSuccess(); + (response) => { + spyOnSuccess(response); }, () => { spyOnError(); }) .then( () => { - expect(spyOnSuccess).not.toHaveBeenCalled(); - expect(spyOnError).toHaveBeenCalled(); + expect(spyOnSuccess).toHaveBeenCalledWith(permissionError); + expect(spyOnError).not.toHaveBeenCalled(); expect(spyContentAction).toHaveBeenCalled(); expect(spyFolderAction).not.toHaveBeenCalled(); @@ -694,7 +695,7 @@ describe('NodeActionsService', () => { }); })); - it('should throw permission error in case it occurs', async(() => { + it('should not throw permission error, to be able to show message in case of partial move of files', async(() => { spyOnDocumentListServiceAction = spyOn(documentListService, 'moveNode').and .returnValue(Observable.throw(permissionError)); @@ -711,8 +712,8 @@ describe('NodeActionsService', () => { .then(() => { expect(spyOnDocumentListServiceAction).toHaveBeenCalled(); - expect(spyOnSuccess).not.toHaveBeenCalledWith(permissionError); - expect(spyOnError).toHaveBeenCalledWith(permissionError); + expect(spyOnSuccess).toHaveBeenCalledWith(permissionError); + expect(spyOnError).not.toHaveBeenCalledWith(permissionError); }); })); @@ -750,15 +751,15 @@ describe('NodeActionsService', () => { spyOnError.calls.reset(); }); - it('should throw permission error in case it occurs on folder move', async(() => { + it('should not throw permission error in case it occurs on folder move', async(() => { spyOnDocumentListServiceAction = spyOn(documentListService, 'moveNode').and .returnValue(Observable.throw(permissionError)); const moveFolderActionObservable = service.moveFolderAction(folderToMove.entry, folderDestinationId); moveFolderActionObservable.toPromise() .then( - () => { - spyOnSuccess(); + (value) => { + spyOnSuccess(value); }, (error) => { spyOnError(error); @@ -766,8 +767,8 @@ describe('NodeActionsService', () => { .then(() => { expect(spyOnDocumentListServiceAction).toHaveBeenCalled(); - expect(spyOnSuccess).not.toHaveBeenCalled(); - expect(spyOnError).toHaveBeenCalledWith(permissionError); + expect(spyOnSuccess).toHaveBeenCalledWith(permissionError); + expect(spyOnError).not.toHaveBeenCalled(); }); })); diff --git a/src/app/common/services/node-actions.service.ts b/src/app/common/services/node-actions.service.ts index 227039904..837274980 100644 --- a/src/app/common/services/node-actions.service.ts +++ b/src/app/common/services/node-actions.service.ts @@ -103,11 +103,11 @@ export class NodeActionsService { (newContent) => { observable.next(`OPERATION.SUCCES.${type.toUpperCase()}.${action.toUpperCase()}`); + const processedData = this.processResponse(newContent); if (action === 'copy') { - this.contentCopied.next(newContent); + this.contentCopied.next(processedData.succeeded); } else if (action === 'move') { - const processedData = this.processResponse(newContent); this.contentMoved.next(processedData); } @@ -219,7 +219,8 @@ export class NodeActionsService { if (errStatusCode && errStatusCode === 409) { return this.copyContentAction(contentEntry, selectionId, this.getNewNameFrom(_oldName, contentEntry.name)); } else { - return Observable.throw(err || 'Server error'); + // do not throw error, to be able to show message in case of partial copy of files + return Observable.of(err || 'Server error'); } }); } @@ -268,7 +269,8 @@ export class NodeActionsService { }); } else { - return Observable.throw(err || 'Server error'); + // do not throw error, to be able to show message in case of partial copy of files + return Observable.of(err || 'Server error'); } }); } @@ -367,7 +369,8 @@ export class NodeActionsService { return Observable.zip(...batch); }); } else { - return Observable.throw(err); + // do not throw error, to be able to show message in case of partial move of files + return Observable.of(err); } }); } @@ -382,19 +385,8 @@ export class NodeActionsService { return { itemMoved, initialParentId }; }) .catch((err) => { - let errStatusCode; - try { - const {error: {statusCode}} = JSON.parse(err.message); - errStatusCode = statusCode; - } catch (e) { // - } - - if (errStatusCode && errStatusCode === 409) { - // do not throw error, to be able to show message in case of partial move of files - return Observable.of(err); - } else { - return Observable.throw(err); - } + // do not throw error, to be able to show message in case of partial move of files + return Observable.of(err); }); } @@ -413,7 +405,7 @@ export class NodeActionsService { } }, (err) => { - return Observable.throw(err || 'Server error'); + return Observable.of(err || 'Server error'); }); return matchedNodes; } diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 319a451dc..9e6753071 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -184,8 +184,8 @@ "PARTIAL_PLURAL": "{{ success }} Elemente gelöscht, {{ failed }} konnte(n) nicht gelöscht werden" }, "NODE_COPY": { - "SINGULAR": "{{ number }} Element kopiert.", - "PLURAL": "{{ number }} Elemente kopiert." + "SINGULAR": "{{ success }} Element kopiert.", + "PLURAL": "{{ success }} Elemente kopiert." }, "NODE_MOVE": { "SINGULAR": "{{ success }} Element verschoben.", @@ -199,4 +199,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index c5483baab..5ad48ea50 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -205,8 +205,12 @@ "PARTIAL_PLURAL": "Deleted {{ success }} items, {{ failed }} couldn't be deleted" }, "NODE_COPY": { - "SINGULAR": "Copied {{ number }} item", - "PLURAL": "Copied {{ number }} items" + "SINGULAR": "Copied {{ success }} item", + "PLURAL": "Copied {{ success }} items", + "PARTIAL_SINGULAR": "Copied {{ success }} item, {{ failed }} couldn't be copied.", + "PARTIAL_PLURAL": "Copied {{ success }} items, {{ failed }} couldn't be copied.", + "FAIL_SINGULAR": "{{ failed }} item couldn't be copied.", + "FAIL_PLURAL": "{{ failed }} items couldn't be copied." }, "NODE_MOVE": { "SINGULAR": "Moved {{ success }} item.", diff --git a/src/assets/i18n/es.json b/src/assets/i18n/es.json index c9a4ca3ca..804d7221d 100644 --- a/src/assets/i18n/es.json +++ b/src/assets/i18n/es.json @@ -184,8 +184,8 @@ "PARTIAL_PLURAL": "Se han eliminado {{ success }} elementos, {{ failed }} no se han podido eliminar" }, "NODE_COPY": { - "SINGULAR": "Se ha copiado {{ number }} elemento", - "PLURAL": "Se han copiado {{ number }} elementos" + "SINGULAR": "Se ha copiado {{ success }} elemento", + "PLURAL": "Se han copiado {{ success }} elementos" }, "NODE_MOVE": { "SINGULAR": "Se ha movido {{ success }} elemento.", @@ -199,4 +199,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index dc8530d04..d4bdfb7de 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -184,8 +184,8 @@ "PARTIAL_PLURAL": "{{ success }} éléments supprimés, {{ failed }} n'a/n'ont pas pu être supprimé(s)" }, "NODE_COPY": { - "SINGULAR": "{{ number }} élément copié", - "PLURAL": "{{ number }} éléments copiés" + "SINGULAR": "{{ success }} élément copié", + "PLURAL": "{{ success }} éléments copiés" }, "NODE_MOVE": { "SINGULAR": "{{ success }} élément déplacé.", @@ -199,4 +199,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/assets/i18n/it.json b/src/assets/i18n/it.json index e30a62882..a6ba1541e 100644 --- a/src/assets/i18n/it.json +++ b/src/assets/i18n/it.json @@ -184,8 +184,8 @@ "PARTIAL_PLURAL": "Elementi {{ success }} eliminati, impossibile eliminare {{ failed }}" }, "NODE_COPY": { - "SINGULAR": "Copiato {{ number }} elemento", - "PLURAL": "Copiati {{ number }} elementi" + "SINGULAR": "Copiato {{ success }} elemento", + "PLURAL": "Copiati {{ success }} elementi" }, "NODE_MOVE": { "SINGULAR": "Spostato {{ success }} elemento.", @@ -199,4 +199,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/assets/i18n/ja.json b/src/assets/i18n/ja.json index d25551c6d..e15849443 100644 --- a/src/assets/i18n/ja.json +++ b/src/assets/i18n/ja.json @@ -184,8 +184,8 @@ "PARTIAL_PLURAL": "{{ success }} 件のアイテムを削除しましたが、{{ failed }} 件は削除できませんでした" }, "NODE_COPY": { - "SINGULAR": "{{ number }} 件のアイテムをコピーしました", - "PLURAL": "{{ number }} 件のアイテムをコピーしました" + "SINGULAR": "{{ success }} 件のアイテムをコピーしました", + "PLURAL": "{{ success }} 件のアイテムをコピーしました" }, "NODE_MOVE": { "SINGULAR": "{{ success }} 件のアイテムを移動しました。", @@ -199,4 +199,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/assets/i18n/nb.json b/src/assets/i18n/nb.json index 6c96cca5a..cc43b70ad 100644 --- a/src/assets/i18n/nb.json +++ b/src/assets/i18n/nb.json @@ -184,8 +184,8 @@ "PARTIAL_PLURAL": "Slettet {{ success }} elementer, {{ failed }} kunne ikke slettes" }, "NODE_COPY": { - "SINGULAR": "Kopierte {{ number }} element", - "PLURAL": "Kopierte {{ number }} elementer" + "SINGULAR": "Kopierte {{ success }} element", + "PLURAL": "Kopierte {{ success }} elementer" }, "NODE_MOVE": { "SINGULAR": "Flyttet {{ success }} element.", @@ -199,4 +199,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/assets/i18n/nl.json b/src/assets/i18n/nl.json index 33b5764c2..95fab1cd9 100644 --- a/src/assets/i18n/nl.json +++ b/src/assets/i18n/nl.json @@ -184,8 +184,8 @@ "PARTIAL_PLURAL": "{{ success }} items verwijderd, kan {{ failed }} niet verwijderen" }, "NODE_COPY": { - "SINGULAR": "{{ number }} item gekopieerd", - "PLURAL": "{{ number }} items gekopieerd" + "SINGULAR": "{{ success }} item gekopieerd", + "PLURAL": "{{ success }} items gekopieerd" }, "NODE_MOVE": { "SINGULAR": "{{ success }} item verplaatst.", @@ -199,4 +199,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/assets/i18n/pt-BR.json b/src/assets/i18n/pt-BR.json index 96e9819a2..351eedb79 100644 --- a/src/assets/i18n/pt-BR.json +++ b/src/assets/i18n/pt-BR.json @@ -184,8 +184,8 @@ "PARTIAL_PLURAL": "Itens {{ success }} excluídos, não foi possível excluir {{ failed }}" }, "NODE_COPY": { - "SINGULAR": "Item {{ number }} copiado", - "PLURAL": "Itens {{ number }} copiados" + "SINGULAR": "Item {{ success }} copiado", + "PLURAL": "Itens {{ success }} copiados" }, "NODE_MOVE": { "SINGULAR": "Item {{ success }} movido.", @@ -199,4 +199,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json index 286f0a988..ad6f834ca 100644 --- a/src/assets/i18n/ru.json +++ b/src/assets/i18n/ru.json @@ -184,8 +184,8 @@ "PARTIAL_PLURAL": "Удалено элементов: {{ success }}, не удалось удалить: {{ failed }}" }, "NODE_COPY": { - "SINGULAR": "Скопирован {{ number }} элемент", - "PLURAL": "Скопировано элементов: {{ number }}" + "SINGULAR": "Скопирован {{ success }} элемент", + "PLURAL": "Скопировано элементов: {{ success }}" }, "NODE_MOVE": { "SINGULAR": "Перемещен {{ success }} элемент.", @@ -199,4 +199,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/assets/i18n/zh-CN.json b/src/assets/i18n/zh-CN.json index aeb79a47b..069508a25 100644 --- a/src/assets/i18n/zh-CN.json +++ b/src/assets/i18n/zh-CN.json @@ -184,8 +184,8 @@ "PARTIAL_PLURAL": "已删除 {{ success }} 项目,{{ failed }} 无法删除" }, "NODE_COPY": { - "SINGULAR": "已复制 {{ number }} 个项目", - "PLURAL": "已复制 {{ number }} 个项目" + "SINGULAR": "已复制 {{ success }} 个项目", + "PLURAL": "已复制 {{ success }} 个项目" }, "NODE_MOVE": { "SINGULAR": "已移动 {{ success }} 项目。", @@ -199,4 +199,4 @@ } } } -} \ No newline at end of file +} From 96239694d7623c04b0c88e16f350c2be2bc88d45 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 2 Nov 2017 16:51:22 +0000 Subject: [PATCH 03/27] [ACA-919] style fixes for search and toolbar (#27) * style fixes for search and toolbar * inherited font family --- src/app/components/header/header.component.scss | 11 ++++++++--- src/app/components/search/search.component.scss | 4 ---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/app/components/header/header.component.scss b/src/app/components/header/header.component.scss index b829d033b..5a35e5378 100644 --- a/src/app/components/header/header.component.scss +++ b/src/app/components/header/header.component.scss @@ -5,7 +5,7 @@ &.adf-toolbar { .mat-toolbar { background-color: #00bcd4; - font-family: 'Muli',"Roboto","Helvetica","Arial",sans-serif !important; + font-family: inherit; min-height: $app-menu-height; height: $app-menu-height; @@ -18,8 +18,13 @@ } } - .adf-toolbar-divider > div { - background-color: $alfresco-white !important; + .adf-toolbar-divider { + margin-left: 5px; + margin-right: 5px; + + & > div { + background-color: $alfresco-white !important; + } } } diff --git a/src/app/components/search/search.component.scss b/src/app/components/search/search.component.scss index 293d94453..e018c6e8e 100644 --- a/src/app/components/search/search.component.scss +++ b/src/app/components/search/search.component.scss @@ -3,7 +3,3 @@ adf-search-control { color: $alfresco-white; } - -:host { - height: $app-menu-height; -} From 4307793a9460eff2393447e4028bbd6a2c9c718b Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 2 Nov 2017 16:51:57 +0000 Subject: [PATCH 04/27] [ACA-937] fix trashcan tooltip --- src/app/components/trashcan/trashcan.component.html | 2 +- src/assets/i18n/en.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/components/trashcan/trashcan.component.html b/src/app/components/trashcan/trashcan.component.html index b56c2d586..107d58efe 100644 --- a/src/app/components/trashcan/trashcan.component.html +++ b/src/app/components/trashcan/trashcan.component.html @@ -9,7 +9,7 @@ [app-permanent-delete-node]="documentList.selection" (selection-node-deleted)="refresh()" *ngIf="documentList.selection.length" - title="{{ 'APP.ACTIONS.DELETE' | translate }}"> + title="{{ 'APP.ACTIONS.DELETE_PERMANENT' | translate }}"> delete_forever diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 5ad48ea50..5c6ec695c 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -91,6 +91,7 @@ "COPY": "Copy", "MOVE": "Move", "DELETE": "Delete", + "DELETE_PERMANENT": "Permanently delete", "MORE": "More actions", "UNDO": "Undo", "RESTORE": "Restore", From 39c579631759d66821d4fc3ab30208850e05de30 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 3 Nov 2017 11:13:08 +0200 Subject: [PATCH 05/27] tab title translation (#33) --- src/app/app.component.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 3328004b0..1fedb4b5d 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -49,9 +49,10 @@ export class AppComponent implements OnInit { const data: any = snapshot.data || {}; if (data.i18nTitle) { - translateService.get(data.i18nTitle).subscribe(title => { - pageTitle.setTitle(title); - }); + this.translateService.translate + .stream(data.i18nTitle) + .subscribe((title) => pageTitle.setTitle(title)); + } else { pageTitle.setTitle(data.title || ''); } From 3bf1af209d9b38b267fe134fa46890abd89f64db Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 3 Nov 2017 13:41:14 +0000 Subject: [PATCH 06/27] fix logo image reference --- src/app/components/header/header.component.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/header/header.component.scss b/src/app/components/header/header.component.scss index 5a35e5378..547f328c7 100644 --- a/src/app/components/header/header.component.scss +++ b/src/app/components/header/header.component.scss @@ -38,7 +38,7 @@ color: inherit; - background: url('../../../assets/images/alfresco-logo-white.svg') no-repeat 0 50%; + background: url('/assets/images/alfresco-logo-white.svg') no-repeat 0 50%; background-size: 100% auto; display: block; From 75f6cd3de1a859912c539900670b116576a8f951 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 3 Nov 2017 14:04:50 +0000 Subject: [PATCH 07/27] minor code formatting --- src/app/app.routes.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 57829dd67..bad9a9f40 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -112,8 +112,7 @@ export const APP_ROUTES: Routes = [ data: { i18nTitle: 'APP.BROWSE.TRASHCAN.TITLE' } - } - , + }, { path: '**', component: GenericErrorComponent From 59d4a4a8ed07de0b8f594a0682788ccd7f00346d Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Fri, 3 Nov 2017 16:54:27 +0200 Subject: [PATCH 08/27] add favorites api --- .../apis/favorites/favorites-api.ts | 66 +++++++++++++++++++ e2e/utilities/repo-client/repo-client.ts | 3 +- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 e2e/utilities/repo-client/apis/favorites/favorites-api.ts diff --git a/e2e/utilities/repo-client/apis/favorites/favorites-api.ts b/e2e/utilities/repo-client/apis/favorites/favorites-api.ts new file mode 100644 index 000000000..efb30a0bf --- /dev/null +++ b/e2e/utilities/repo-client/apis/favorites/favorites-api.ts @@ -0,0 +1,66 @@ +/*! + * @license + * Copyright 2017 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 { promise } from 'protractor'; +import { RepoApi } from '../repo-api'; +import { NodesApi } from '../nodes/nodes-api'; +import { RepoClient } from './../../repo-client'; + +export class FavoritesApi extends RepoApi { + + addFavorite(api: RepoClient, nodeType: string, name: string): Promise { + let data = []; + + return api.nodes.getNodeByPath(name) + .then((response: any): string => { + return response.data.entry.id; + }) + .then((id: string) => { + data = data.concat([{ + target: { + [nodeType]: { + guid: id + } + } + }]); + }) + .then(() => { + return this.post(`/people/-me-/favorites`, { data }); + }) + .catch(this.handleError); + } + + getFavorite(api: RepoClient, name: string): Promise { + return api.nodes.getNodeByPath(name) + .then((resp: any) => { + const { id } = resp.data.entry; + return this.get(`/people/-me-/favorites/${id}`); + }) + .catch((response) => Promise.resolve(response)); + } + + removeFavorite(api: RepoClient, nodeType: string, name: string): Promise { + return api.nodes.getNodeByPath(name) + .then((response: any): string => { + return response.data.entry.id; + }) + .then((id: string) => { + return this.delete(`/people/-me-/favorites/${id}`); + }) + .catch(this.handleError); + } +} diff --git a/e2e/utilities/repo-client/repo-client.ts b/e2e/utilities/repo-client/repo-client.ts index 80d37360b..889c4c1f3 100644 --- a/e2e/utilities/repo-client/repo-client.ts +++ b/e2e/utilities/repo-client/repo-client.ts @@ -20,12 +20,13 @@ import { RepoClientAuth, RepoClientConfig } from './repo-client-models'; import { PeopleApi } from './apis/people/people-api'; import { NodesApi } from './apis/nodes/nodes-api'; import { SitesApi } from './apis/sites/sites-api'; +import { FavoritesApi } from './apis/favorites/favorites-api'; export class RepoClient { public people: PeopleApi = new PeopleApi(this.auth, this.config); public nodes: NodesApi = new NodesApi(this.auth, this.config); public sites: SitesApi = new SitesApi(this.auth, this.config); - // public favorites: FavoritesApi = new FavoritesApi(this.auth, this.config); + public favorites: FavoritesApi = new FavoritesApi(this.auth, this.config); // public shared: SharedLinksApi = new SharedLinksApi(this.auth, this.config); constructor( From 04b410254e9ef13cfbf8287e684970541ebc02a1 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Fri, 3 Nov 2017 17:26:10 +0200 Subject: [PATCH 09/27] changes after review --- .../apis/favorites/favorites-api.ts | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/e2e/utilities/repo-client/apis/favorites/favorites-api.ts b/e2e/utilities/repo-client/apis/favorites/favorites-api.ts index efb30a0bf..ced51018d 100644 --- a/e2e/utilities/repo-client/apis/favorites/favorites-api.ts +++ b/e2e/utilities/repo-client/apis/favorites/favorites-api.ts @@ -23,14 +23,10 @@ import { RepoClient } from './../../repo-client'; export class FavoritesApi extends RepoApi { addFavorite(api: RepoClient, nodeType: string, name: string): Promise { - let data = []; - return api.nodes.getNodeByPath(name) - .then((response: any): string => { - return response.data.entry.id; - }) - .then((id: string) => { - data = data.concat([{ + .then((response) => { + const { id } = response.data.entry; + return ([{ target: { [nodeType]: { guid: id @@ -38,7 +34,7 @@ export class FavoritesApi extends RepoApi { } }]); }) - .then(() => { + .then((data) => { return this.post(`/people/-me-/favorites`, { data }); }) .catch(this.handleError); @@ -46,8 +42,8 @@ export class FavoritesApi extends RepoApi { getFavorite(api: RepoClient, name: string): Promise { return api.nodes.getNodeByPath(name) - .then((resp: any) => { - const { id } = resp.data.entry; + .then((response) => { + const { id } = response.data.entry; return this.get(`/people/-me-/favorites/${id}`); }) .catch((response) => Promise.resolve(response)); @@ -55,10 +51,8 @@ export class FavoritesApi extends RepoApi { removeFavorite(api: RepoClient, nodeType: string, name: string): Promise { return api.nodes.getNodeByPath(name) - .then((response: any): string => { - return response.data.entry.id; - }) - .then((id: string) => { + .then((response) => { + const { id } = response.data.entry; return this.delete(`/people/-me-/favorites/${id}`); }) .catch(this.handleError); From 10649fb6a5367af7e8f1bf9d1e0b5dd7739fbf23 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 3 Nov 2017 16:56:59 +0000 Subject: [PATCH 10/27] upgrade to ADF 1.10.0-beta6 --- package.json | 18 +++--- yarn.lock | 169 +++++++++++++++++++++++++++------------------------ 2 files changed, 100 insertions(+), 87 deletions(-) diff --git a/package.json b/package.json index 5349356db..503d04dac 100644 --- a/package.json +++ b/package.json @@ -24,17 +24,17 @@ "@angular/platform-browser": "4.4.5", "@angular/platform-browser-dynamic": "4.4.5", "@angular/router": "4.4.5", - "@ngx-translate/core": "7.0.0", - "alfresco-js-api": "1.10.0-beta5", + "@ngx-translate/core": "8.0.0", + "alfresco-js-api": "1.10.0-beta6", "core-js": "^2.4.1", "hammerjs": "2.0.8", - "ng2-alfresco-core": "1.10.0-beta5", - "ng2-alfresco-datatable": "1.10.0-beta5", - "ng2-alfresco-documentlist": "1.10.0-beta5", - "ng2-alfresco-login": "1.10.0-beta5", - "ng2-alfresco-search": "1.10.0-beta5", - "ng2-alfresco-upload": "1.10.0-beta5", - "ng2-alfresco-viewer": "1.10.0-beta5", + "ng2-alfresco-core": "1.10.0-beta6", + "ng2-alfresco-datatable": "1.10.0-beta6", + "ng2-alfresco-documentlist": "1.10.0-beta6", + "ng2-alfresco-login": "1.10.0-beta6", + "ng2-alfresco-search": "1.10.0-beta6", + "ng2-alfresco-upload": "1.10.0-beta6", + "ng2-alfresco-viewer": "1.10.0-beta6", "pdfjs-dist": "1.8.557", "rxjs": "5.1.0", "wsrv": "0.2.2", diff --git a/yarn.lock b/yarn.lock index d6911b754..7164cf2fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,8 +3,8 @@ "@angular-devkit/build-optimizer@~0.0.23": - version "0.0.31" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.0.31.tgz#511bc00e18c787a6cd4efe37b8cdb9f1bc6d4472" + version "0.0.32" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.0.32.tgz#1bf32332d8a7c84043059e3d265a52f9d11726fd" dependencies: loader-utils "^1.1.0" source-map "^0.5.6" @@ -18,13 +18,13 @@ source-map "^0.5.6" "@angular-devkit/schematics@~0.0.25": - version "0.0.34" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-0.0.34.tgz#c3ef61b0e49e585d9982f2828e9a67b3879a6b1b" + version "0.0.35" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-0.0.35.tgz#23dbe2c8dd430114a903a7995d6eefcf1f0f648d" dependencies: "@angular-devkit/core" "0.0.20" "@ngtools/json-schema" "^1.1.0" minimist "^1.2.0" - rxjs "^5.4.2" + rxjs "^5.5.2" "@angular/animations@4.4.5": version "4.4.5" @@ -189,9 +189,9 @@ magic-string "^0.22.3" source-map "^0.5.6" -"@ngx-translate/core@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@ngx-translate/core/-/core-7.0.0.tgz#5b6f63bd4042164d44cd85f68703af96e9392e7d" +"@ngx-translate/core@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@ngx-translate/core/-/core-8.0.0.tgz#751fd6b512d80f3a748d2de8dfc96dfefa29afe0" "@schematics/angular@~0.0.38": version "0.0.49" @@ -303,9 +303,9 @@ ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -alfresco-js-api@1.10.0-beta5: - version "1.10.0-beta5" - resolved "https://registry.yarnpkg.com/alfresco-js-api/-/alfresco-js-api-1.10.0-beta5.tgz#6b3b111b1774b6b81a51f0ad0e5f7c24e5e234da" +alfresco-js-api@1.10.0-beta6: + version "1.10.0-beta6" + resolved "https://registry.yarnpkg.com/alfresco-js-api/-/alfresco-js-api-1.10.0-beta6.tgz#c988a46f81ce17c70edd053d03b95d61ce5447f5" dependencies: event-emitter "0.3.4" superagent "3.7.0" @@ -887,8 +887,8 @@ caniuse-api@^1.5.2: lodash.uniq "^4.5.0" caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: - version "1.0.30000756" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000756.tgz#e938a6b991630f30d2263dd3458beb65d362268b" + version "1.0.30000758" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000758.tgz#a235627b1922e878b63164942c991b84de92c810" caseless@~0.12.0: version "0.12.0" @@ -925,7 +925,7 @@ chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" dependencies: @@ -1292,8 +1292,8 @@ cryptiles@3.x.x, cryptiles@^3.1.2: boom "5.x.x" crypto-browserify@^3.11.0: - version "3.11.1" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f" + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" dependencies: browserify-cipher "^1.0.0" browserify-sign "^4.0.0" @@ -1305,6 +1305,7 @@ crypto-browserify@^3.11.0: pbkdf2 "^3.0.3" public-encrypt "^4.0.0" randombytes "^2.0.0" + randomfill "^1.0.3" css-color-names@0.0.4: version "0.0.4" @@ -1542,6 +1543,10 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" +detect-libc@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.2.tgz#71ad5d204bf17a6a6ca8f450c61454066ef461e1" + detect-node@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" @@ -3669,9 +3674,9 @@ negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" -ng2-alfresco-core@1.10.0-beta5: - version "1.10.0-beta5" - resolved "https://registry.yarnpkg.com/ng2-alfresco-core/-/ng2-alfresco-core-1.10.0-beta5.tgz#d641754b9440014a5b747811b82520c449f2694e" +ng2-alfresco-core@1.10.0-beta6: + version "1.10.0-beta6" + resolved "https://registry.yarnpkg.com/ng2-alfresco-core/-/ng2-alfresco-core-1.10.0-beta6.tgz#d1ed5028f3bb4e9c063e338290dfba9a9cb44992" dependencies: "@angular/animations" "4.4.5" "@angular/cdk" "2.0.0-beta.12" @@ -3685,8 +3690,8 @@ ng2-alfresco-core@1.10.0-beta5: "@angular/platform-browser" "4.4.5" "@angular/platform-browser-dynamic" "4.4.5" "@angular/router" "4.4.5" - "@ngx-translate/core" "7.0.0" - alfresco-js-api "1.10.0-beta5" + "@ngx-translate/core" "8.0.0" + alfresco-js-api "1.10.0-beta6" core-js "2.4.1" hammerjs "2.0.8" moment "2.15.2" @@ -3695,9 +3700,9 @@ ng2-alfresco-core@1.10.0-beta5: systemjs "0.19.27" zone.js "0.8.12" -ng2-alfresco-datatable@1.10.0-beta5: - version "1.10.0-beta5" - resolved "https://registry.yarnpkg.com/ng2-alfresco-datatable/-/ng2-alfresco-datatable-1.10.0-beta5.tgz#a63feac548ee5aac5ec677a923c84fbaecb3ba3c" +ng2-alfresco-datatable@1.10.0-beta6: + version "1.10.0-beta6" + resolved "https://registry.yarnpkg.com/ng2-alfresco-datatable/-/ng2-alfresco-datatable-1.10.0-beta6.tgz#37312c3be022b7eb893e4fa278c0177c77b9130f" dependencies: "@angular/animations" "4.4.5" "@angular/cdk" "2.0.0-beta.12" @@ -3710,19 +3715,19 @@ ng2-alfresco-datatable@1.10.0-beta5: "@angular/platform-browser" "4.4.5" "@angular/platform-browser-dynamic" "4.4.5" "@angular/router" "4.4.5" - "@ngx-translate/core" "7.0.0" - alfresco-js-api "1.10.0-beta5" + "@ngx-translate/core" "8.0.0" + alfresco-js-api "1.10.0-beta6" core-js "2.4.1" hammerjs "2.0.8" - ng2-alfresco-core "1.10.0-beta5" + ng2-alfresco-core "1.10.0-beta6" reflect-metadata "0.1.10" rxjs "5.1.0" systemjs "0.19.27" zone.js "0.8.12" -ng2-alfresco-documentlist@1.10.0-beta5: - version "1.10.0-beta5" - resolved "https://registry.yarnpkg.com/ng2-alfresco-documentlist/-/ng2-alfresco-documentlist-1.10.0-beta5.tgz#c63d5cb769c4ed5995179b883acf460c7bfb13a5" +ng2-alfresco-documentlist@1.10.0-beta6: + version "1.10.0-beta6" + resolved "https://registry.yarnpkg.com/ng2-alfresco-documentlist/-/ng2-alfresco-documentlist-1.10.0-beta6.tgz#512dd75fbef9df43949fa74665ccb831c3346b23" dependencies: "@angular/animations" "4.4.5" "@angular/cdk" "2.0.0-beta.12" @@ -3736,21 +3741,21 @@ ng2-alfresco-documentlist@1.10.0-beta5: "@angular/platform-browser" "4.4.5" "@angular/platform-browser-dynamic" "4.4.5" "@angular/router" "4.4.5" - "@ngx-translate/core" "7.0.0" - alfresco-js-api "1.10.0-beta5" + "@ngx-translate/core" "8.0.0" + alfresco-js-api "1.10.0-beta6" core-js "2.4.1" hammerjs "2.0.8" - ng2-alfresco-core "1.10.0-beta5" - ng2-alfresco-datatable "1.10.0-beta5" - ng2-alfresco-upload "1.10.0-beta5" + ng2-alfresco-core "1.10.0-beta6" + ng2-alfresco-datatable "1.10.0-beta6" + ng2-alfresco-upload "1.10.0-beta6" reflect-metadata "0.1.10" rxjs "5.1.0" systemjs "0.19.27" zone.js "0.8.12" -ng2-alfresco-login@1.10.0-beta5: - version "1.10.0-beta5" - resolved "https://registry.yarnpkg.com/ng2-alfresco-login/-/ng2-alfresco-login-1.10.0-beta5.tgz#fc54c6e6eb32774bb47e29654432209413993fe0" +ng2-alfresco-login@1.10.0-beta6: + version "1.10.0-beta6" + resolved "https://registry.yarnpkg.com/ng2-alfresco-login/-/ng2-alfresco-login-1.10.0-beta6.tgz#db18061d219362cf8533a49099b8aafa17c648d8" dependencies: "@angular/animations" "4.4.5" "@angular/cdk" "2.0.0-beta.12" @@ -3763,18 +3768,18 @@ ng2-alfresco-login@1.10.0-beta5: "@angular/platform-browser" "4.4.5" "@angular/platform-browser-dynamic" "4.4.5" "@angular/router" "4.4.5" - "@ngx-translate/core" "7.0.0" - alfresco-js-api "1.10.0-beta5" + "@ngx-translate/core" "8.0.0" + alfresco-js-api "1.10.0-beta6" hammerjs "2.0.8" - ng2-alfresco-core "1.10.0-beta5" + ng2-alfresco-core "1.10.0-beta6" reflect-metadata "0.1.10" rxjs "5.1.0" systemjs "0.19.27" zone.js "0.8.12" -ng2-alfresco-search@1.10.0-beta5: - version "1.10.0-beta5" - resolved "https://registry.yarnpkg.com/ng2-alfresco-search/-/ng2-alfresco-search-1.10.0-beta5.tgz#6a2c83c0bc9b3696908a53c3bf042cd1c7736127" +ng2-alfresco-search@1.10.0-beta6: + version "1.10.0-beta6" + resolved "https://registry.yarnpkg.com/ng2-alfresco-search/-/ng2-alfresco-search-1.10.0-beta6.tgz#6257100b8f52e5d812d4b8dae065b84124b636bb" dependencies: "@angular/animations" "4.4.5" "@angular/cdk" "2.0.0-beta.12" @@ -3787,21 +3792,21 @@ ng2-alfresco-search@1.10.0-beta5: "@angular/platform-browser" "4.4.5" "@angular/platform-browser-dynamic" "4.4.5" "@angular/router" "4.4.5" - "@ngx-translate/core" "7.0.0" - alfresco-js-api "1.10.0-beta5" + "@ngx-translate/core" "8.0.0" + alfresco-js-api "1.10.0-beta6" core-js "2.4.1" hammerjs "2.0.8" - ng2-alfresco-core "1.10.0-beta5" - ng2-alfresco-datatable "1.10.0-beta5" - ng2-alfresco-documentlist "1.10.0-beta5" + ng2-alfresco-core "1.10.0-beta6" + ng2-alfresco-datatable "1.10.0-beta6" + ng2-alfresco-documentlist "1.10.0-beta6" reflect-metadata "0.1.10" rxjs "5.1.0" systemjs "0.19.27" zone.js "0.8.12" -ng2-alfresco-upload@1.10.0-beta5: - version "1.10.0-beta5" - resolved "https://registry.yarnpkg.com/ng2-alfresco-upload/-/ng2-alfresco-upload-1.10.0-beta5.tgz#6d61b0777c6dd7703993ae04921dd44b78eb5bab" +ng2-alfresco-upload@1.10.0-beta6: + version "1.10.0-beta6" + resolved "https://registry.yarnpkg.com/ng2-alfresco-upload/-/ng2-alfresco-upload-1.10.0-beta6.tgz#7da94739cee61125dae4a4aa9c23573a414aa23e" dependencies: "@angular/animations" "4.4.5" "@angular/cdk" "2.0.0-beta.12" @@ -3814,20 +3819,20 @@ ng2-alfresco-upload@1.10.0-beta5: "@angular/platform-browser" "4.4.5" "@angular/platform-browser-dynamic" "4.4.5" "@angular/router" "4.4.5" - "@ngx-translate/core" "7.0.0" - alfresco-js-api "1.10.0-beta5" + "@ngx-translate/core" "8.0.0" + alfresco-js-api "1.10.0-beta6" core-js "2.4.1" hammerjs "2.0.8" minimatch "3.0.4" - ng2-alfresco-core "1.10.0-beta5" + ng2-alfresco-core "1.10.0-beta6" reflect-metadata "0.1.10" rxjs "5.1.0" systemjs "0.19.27" zone.js "0.8.12" -ng2-alfresco-viewer@1.10.0-beta5: - version "1.10.0-beta5" - resolved "https://registry.yarnpkg.com/ng2-alfresco-viewer/-/ng2-alfresco-viewer-1.10.0-beta5.tgz#b52a7afc89c6816ebe8def703aa8d879a38d3eb6" +ng2-alfresco-viewer@1.10.0-beta6: + version "1.10.0-beta6" + resolved "https://registry.yarnpkg.com/ng2-alfresco-viewer/-/ng2-alfresco-viewer-1.10.0-beta6.tgz#04f9c400869e9e603acc47fc88b3ab3f5db2657b" dependencies: "@angular/animations" "4.4.5" "@angular/cdk" "2.0.0-beta.12" @@ -3840,11 +3845,11 @@ ng2-alfresco-viewer@1.10.0-beta5: "@angular/platform-browser" "4.4.5" "@angular/platform-browser-dynamic" "4.4.5" "@angular/router" "4.4.5" - "@ngx-translate/core" "7.0.0" - alfresco-js-api "1.10.0-beta5" + "@ngx-translate/core" "8.0.0" + alfresco-js-api "1.10.0-beta6" core-js "2.4.1" hammerjs "2.0.8" - ng2-alfresco-core "1.10.0-beta5" + ng2-alfresco-core "1.10.0-beta6" pdfjs-dist "1.5.404" reflect-metadata "0.1.10" rxjs "5.1.0" @@ -3929,9 +3934,10 @@ node-modules-path@^1.0.0: resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" node-pre-gyp@^0.6.36: - version "0.6.38" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.38.tgz#e92a20f83416415bb4086f6d1fb78b3da73d113d" + version "0.6.39" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" dependencies: + detect-libc "^1.0.2" hawk "3.1.3" mkdirp "^0.5.1" nopt "^4.0.1" @@ -4524,8 +4530,8 @@ postcss-minify-selectors@^2.0.4: postcss-selector-parser "^2.0.0" postcss-modules-extract-imports@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz#b614c9720be6816eaee35fb3a5faa1dba6a05ddb" dependencies: postcss "^6.0.1" @@ -4652,10 +4658,10 @@ postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0. supports-color "^3.2.3" postcss@^6.0.1: - version "6.0.13" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.13.tgz#b9ecab4ee00c89db3ec931145bd9590bbf3f125f" + version "6.0.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.14.tgz#5534c72114739e75d0afcf017db853099f562885" dependencies: - chalk "^2.1.0" + chalk "^2.3.0" source-map "^0.6.1" supports-color "^4.4.0" @@ -4806,12 +4812,19 @@ randomatic@^1.1.3: is-number "^3.0.0" kind-of "^4.0.0" -randombytes@^2.0.0, randombytes@^2.0.1: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79" dependencies: safe-buffer "^5.1.0" +randomfill@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.3.tgz#b96b7df587f01dd91726c418f30553b1418e3d62" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" @@ -5064,7 +5077,7 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" -requires-port@1.0.x, requires-port@1.x.x: +requires-port@1.0.x, requires-port@1.x.x, requires-port@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -5099,7 +5112,7 @@ rxjs@5.1.0: dependencies: symbol-observable "^1.0.1" -rxjs@^5.4.2: +rxjs@^5.4.2, rxjs@^5.5.2: version "5.5.2" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.2.tgz#28d403f0071121967f18ad665563255d54236ac3" dependencies: @@ -5863,8 +5876,8 @@ tslint@~5.7.0: tsutils "^2.8.1" tsutils@^2.8.1: - version "2.12.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.12.1.tgz#f4d95ce3391c8971e46e54c4cf0edb0a21dd5b24" + version "2.12.2" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.12.2.tgz#ad58a4865d17ec3ddb6631b6ca53be14a5656ff3" dependencies: tslib "^1.7.1" @@ -5987,11 +6000,11 @@ url-parse@1.0.x: requires-port "1.0.x" url-parse@^1.1.8: - version "1.1.9" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.9.tgz#c67f1d775d51f0a18911dd7b3ffad27bb9e5bd19" + version "1.2.0" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986" dependencies: querystringify "~1.0.0" - requires-port "1.0.x" + requires-port "~1.0.0" url@^0.11.0: version "0.11.0" @@ -6169,8 +6182,8 @@ webpack-dev-server@~2.7.1: yargs "^6.0.0" webpack-merge@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.0.tgz#6ad72223b3e0b837e531e4597c199f909361511e" + version "4.1.1" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.1.tgz#f1197a0a973e69c6fbeeb6d658219aa8c0c13555" dependencies: lodash "^4.17.4" From 71c5d96cf3c6a3ee51d46af2fc9f8bd0eea28e03 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Sat, 4 Nov 2017 13:26:22 +0200 Subject: [PATCH 11/27] switch to adf component (#38) --- src/app/common/common.module.ts | 4 - .../folder-create.directive.spec.ts | 96 ------------------- .../directives/folder-create.directive.ts | 66 ------------- .../components/sidenav/sidenav.component.html | 2 +- 4 files changed, 1 insertion(+), 167 deletions(-) delete mode 100644 src/app/common/directives/folder-create.directive.spec.ts delete mode 100644 src/app/common/directives/folder-create.directive.ts diff --git a/src/app/common/common.module.ts b/src/app/common/common.module.ts index 5e008c78c..45997390f 100644 --- a/src/app/common/common.module.ts +++ b/src/app/common/common.module.ts @@ -24,8 +24,6 @@ import { AdfModule } from '../adf.module'; import { MaterialModule } from './material.module'; import { FolderDialogComponent } from './dialogs/folder-dialog.component'; - -import { FolderCreateDirective } from './directives/folder-create.directive'; import { FolderEditDirective } from './directives/folder-edit.directive'; import { NodeCopyDirective } from './directives/node-copy.directive'; import { NodeDeleteDirective } from './directives/node-delete.directive'; @@ -52,8 +50,6 @@ export function modules() { export function declarations() { return [ FolderDialogComponent, - - FolderCreateDirective, FolderEditDirective, NodeCopyDirective, NodeDeleteDirective, diff --git a/src/app/common/directives/folder-create.directive.spec.ts b/src/app/common/directives/folder-create.directive.spec.ts deleted file mode 100644 index a77ef95da..000000000 --- a/src/app/common/directives/folder-create.directive.spec.ts +++ /dev/null @@ -1,96 +0,0 @@ -/*! - * @license - * Copyright 2017 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 { TestBed, ComponentFixture } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { Component } from '@angular/core'; -import { Observable } from 'rxjs/Rx'; -import { MatDialogModule, MatDialog } from '@angular/material'; - -import { FolderCreateDirective } from './folder-create.directive'; -import { ContentManagementService } from '../services/content-management.service'; - -@Component({ - template: '
' -}) -class TestComponent { - parentNode = ''; -} - -describe('FolderCreateDirective', () => { - let fixture: ComponentFixture; - let element; - let node: any; - let dialog: MatDialog; - let contentService: ContentManagementService; - let dialogRefMock; - - const event: any = { - type: 'click', - preventDefault: () => null - }; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ MatDialogModule ], - declarations: [ - TestComponent, - FolderCreateDirective - ] - , - providers: [ - ContentManagementService - ] - }); - - fixture = TestBed.createComponent(TestComponent); - element = fixture.debugElement.query(By.directive(FolderCreateDirective)); - dialog = TestBed.get(MatDialog); - contentService = TestBed.get(ContentManagementService); - }); - - beforeEach(() => { - node = { entry: { id: 'nodeId' } }; - - dialogRefMock = { - afterClosed: val => Observable.of(val) - }; - - spyOn(dialog, 'open').and.returnValue(dialogRefMock); - }); - - it('emits createFolder event when input value is not undefined', () => { - spyOn(dialogRefMock, 'afterClosed').and.returnValue(Observable.of(node)); - - contentService.createFolder.subscribe((val) => { - expect(val).toBe(node); - }); - - element.triggerEventHandler('click', event); - fixture.detectChanges(); - }); - - it('does not emits createFolder event when input value is undefined', () => { - spyOn(dialogRefMock, 'afterClosed').and.returnValue(Observable.of(null)); - spyOn(contentService.createFolder, 'next'); - - element.triggerEventHandler('click', event); - fixture.detectChanges(); - - expect(contentService.createFolder.next).not.toHaveBeenCalled(); - }); -}); diff --git a/src/app/common/directives/folder-create.directive.ts b/src/app/common/directives/folder-create.directive.ts deleted file mode 100644 index 36d6a67f7..000000000 --- a/src/app/common/directives/folder-create.directive.ts +++ /dev/null @@ -1,66 +0,0 @@ -/*! - * @license - * Copyright 2017 Alfresco Software, Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Directive, HostListener, Input } from '@angular/core'; -import { MatDialog, MatDialogConfig } from '@angular/material'; - -import { MinimalNodeEntryEntity } from 'alfresco-js-api'; - -import { FolderDialogComponent } from '../dialogs/folder-dialog.component'; -import { ContentManagementService } from '../services/content-management.service'; - -@Directive({ - selector: '[app-create-folder]' -}) -export class FolderCreateDirective { - static DIALOG_WIDTH: number = 400; - - @Input('app-create-folder') - parentNodeId: string; - - @HostListener('click', [ '$event' ]) - onClick(event) { - event.preventDefault(); - this.openDialog(); - } - - constructor( - public dialogRef: MatDialog, - public content: ContentManagementService - ) {} - - private get dialogConfig(): MatDialogConfig { - const { DIALOG_WIDTH: width } = FolderCreateDirective; - const { parentNodeId } = this; - - return { - data: { parentNodeId }, - width: `${width}px` - }; - } - - private openDialog(): void { - const { dialogRef, dialogConfig, content } = this; - const dialogInstance = dialogRef.open(FolderDialogComponent, dialogConfig); - - dialogInstance.afterClosed().subscribe((node: MinimalNodeEntryEntity) => { - if (node) { - content.createFolder.next(node); - } - }); - } -} diff --git a/src/app/components/sidenav/sidenav.component.html b/src/app/components/sidenav/sidenav.component.html index 43fdaa621..73973dbfd 100644 --- a/src/app/components/sidenav/sidenav.component.html +++ b/src/app/components/sidenav/sidenav.component.html @@ -8,8 +8,8 @@ diff --git a/src/app/components/favorites/favorites.component.spec.ts b/src/app/components/favorites/favorites.component.spec.ts index 0728982b9..ec8e88cdb 100644 --- a/src/app/components/favorites/favorites.component.spec.ts +++ b/src/app/components/favorites/favorites.component.spec.ts @@ -20,7 +20,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { TestBed, async } from '@angular/core/testing'; import { Observable } from 'rxjs/Rx'; -import { CoreModule, NodesApiService, AlfrescoApiService } from 'ng2-alfresco-core'; +import { CoreModule, NodesApiService, AlfrescoApiService, AlfrescoContentService } from 'ng2-alfresco-core'; import { CommonModule } from '../../common/common.module'; import { ContentManagementService } from '../../common/services/content-management.service'; @@ -32,6 +32,7 @@ describe('Favorites Routed Component', () => { let component: FavoritesComponent; let nodesApi: NodesApiService; let alfrescoApi: AlfrescoApiService; + let alfrescoContentService: AlfrescoContentService; let contentService: ContentManagementService; let router: Router; let page; @@ -80,6 +81,7 @@ describe('Favorites Routed Component', () => { nodesApi = TestBed.get(NodesApiService); alfrescoApi = TestBed.get(AlfrescoApiService); + alfrescoContentService = TestBed.get(AlfrescoContentService); contentService = TestBed.get(ContentManagementService); router = TestBed.get(Router); }); @@ -94,7 +96,7 @@ describe('Favorites Routed Component', () => { spyOn(component, 'refresh'); fixture.detectChanges(); - contentService.editFolder.next(null); + alfrescoContentService.folderEdit.next(null); expect(component.refresh).toHaveBeenCalled(); }); diff --git a/src/app/components/favorites/favorites.component.ts b/src/app/components/favorites/favorites.component.ts index cdb5daffd..92ebfdbe8 100644 --- a/src/app/components/favorites/favorites.component.ts +++ b/src/app/components/favorites/favorites.component.ts @@ -20,7 +20,7 @@ import { Router } from '@angular/router'; import { Subscription } from 'rxjs/Rx'; import { MinimalNodeEntryEntity, PathElementEntity, PathInfo } from 'alfresco-js-api'; -import { NodesApiService } from 'ng2-alfresco-core'; +import { AlfrescoContentService, NodesApiService } from 'ng2-alfresco-core'; import { DocumentListComponent } from 'ng2-alfresco-documentlist'; import { ContentManagementService } from '../../common/services/content-management.service'; @@ -41,12 +41,13 @@ export class FavoritesComponent extends PageComponent implements OnInit, OnDestr constructor( private router: Router, private nodesApi: NodesApiService, + private contentService: AlfrescoContentService, private content: ContentManagementService) { super(); } ngOnInit() { - this.onEditFolder = this.content.editFolder.subscribe(() => this.refresh()); + this.onEditFolder = this.contentService.folderEdit.subscribe(() => this.refresh()); this.onMoveNode = this.content.moveNode.subscribe(() => this.refresh()); this.onToggleFavorite = this.content.toggleFavorite .debounceTime(300).subscribe(() => this.refresh()); diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index 4fdd83895..2341d840a 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -27,7 +27,7 @@ mat-icon-button *ngIf="canEditFolder(documentList.selection)" title="{{ 'APP.ACTIONS.EDIT' | translate }}" - [app-edit-folder]="documentList.selection[0]?.entry"> + [adf-edit-folder]="documentList.selection[0]?.entry"> create diff --git a/src/app/components/files/files.component.spec.ts b/src/app/components/files/files.component.spec.ts index 63e87fe0d..622e3352e 100644 --- a/src/app/components/files/files.component.spec.ts +++ b/src/app/components/files/files.component.spec.ts @@ -170,13 +170,13 @@ describe('FilesComponent', () => { }); it('calls refresh onCreateFolder event', () => { - contentManagementService.createFolder.next(); + alfrescoContentService.folderCreate.next(); expect(component.load).toHaveBeenCalled(); }); it('calls refresh editFolder event', () => { - contentManagementService.editFolder.next(); + alfrescoContentService.folderEdit.next(); expect(component.load).toHaveBeenCalled(); }); diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index 45c2557f6..0a48e3794 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -16,7 +16,7 @@ */ import { Observable, Subscription } from 'rxjs/Rx'; -import { Component, ViewChild, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core'; import { Router, ActivatedRoute, Params } from '@angular/router'; import { MinimalNodeEntity, MinimalNodeEntryEntity, PathElementEntity, NodePaging, PathElement } from 'alfresco-js-api'; import { UploadService, FileUploadEvent, NodesApiService, AlfrescoContentService, AlfrescoApiService } from 'ng2-alfresco-core'; @@ -60,7 +60,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { } ngOnInit() { - const { route, contentManagementService, nodeActionsService, uploadService } = this; + const { route, contentManagementService, contentService, nodeActionsService, uploadService } = this; const { data } = route.snapshot; this.routeData = data; @@ -87,8 +87,8 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { this.onCopyNode = nodeActionsService.contentCopied .subscribe((nodes) => this.onContentCopied(nodes)); - this.onCreateFolder = contentManagementService.createFolder.subscribe(() => this.load()); - this.onEditFolder = contentManagementService.editFolder.subscribe(() => this.load()); + this.onCreateFolder = contentService.folderCreate.subscribe(() => this.load()); + this.onEditFolder = contentService.folderEdit.subscribe(() => this.load()); this.onDeleteNode = contentManagementService.deleteNode.subscribe(() => this.load()); this.onMoveNode = contentManagementService.moveNode.subscribe(() => this.load()); this.onRestoreNode = contentManagementService.restoreNode.subscribe(() => this.load()); From d10255b8438238a12f21566e0ceab9943faa933b Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 6 Nov 2017 14:11:04 +0000 Subject: [PATCH 13/27] production build setup --- Dockerfile | 7 +++++++ docker-compose.yml | 8 ++++++++ nginx.conf | 27 +++++++++++++++++++++++++++ package.json | 3 ++- postbuild-dev.js | 26 ++++++++++++++++++++++++++ src/app/app.module.ts | 1 - 6 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 nginx.conf create mode 100644 postbuild-dev.js diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..1c3cdbc27 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM nginx + +COPY nginx.conf /etc/nginx/nginx.conf + +WORKDIR /usr/share/nginx/html +COPY dist/ . + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..3ecf2b560 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,8 @@ +version: '3.1' + +services: + app: + image: 'alfresco/content-app' + build: '.' + ports: + - 3000:80 diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 000000000..e898ca067 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,27 @@ +worker_processes 1; + +events { + worker_connections 1024; +} + +http { + server { + listen 80; + server_name localhost; + + root /usr/share/nginx/html; + index index.html index.htm; + include /etc/nginx/mime.types; + + gzip on; + gzip_min_length 1000; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; + + location / { + # If you want to enable html5Mode(true) in your angularjs app for pretty URL + # then all request for your angularJS app will be through index.html + try_files $uri /index.html; + } + } +} diff --git a/package.json b/package.json index 503d04dac..125142c12 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "scripts": { "ng": "ng", "start": "ng serve --open", - "build": "ng build", + "build": "ng build --prod", + "build:dev": "ng build && node postbuild-dev.js", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e", diff --git a/postbuild-dev.js b/postbuild-dev.js new file mode 100644 index 000000000..02544050d --- /dev/null +++ b/postbuild-dev.js @@ -0,0 +1,26 @@ +/*! + * @license + * Copyright 2017 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. + */ + +var fs = require('fs'); +var config = require('./dist/app.config.json'); + +config.ecmHost = 'http://localhost:8080'; + +fs.writeFileSync( + './dist/app.config.json', + JSON.stringify(config, null, 4) +); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 36072abef..9be78dbd3 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -46,7 +46,6 @@ import { SidenavComponent } from './components/sidenav/sidenav.component'; imports: [ BrowserModule, RouterModule.forRoot(APP_ROUTES, { - useHash: true, enableTracing: false // enable for debug only }), AdfModule, From d2cd302a66fbb0bf45c5795fc6a66df8bdf76fe9 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 6 Nov 2017 16:55:15 +0000 Subject: [PATCH 14/27] fix base path --- src/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.html b/src/index.html index 6be430da6..73d53f5cc 100644 --- a/src/index.html +++ b/src/index.html @@ -3,7 +3,7 @@ Alfresco Content App - + From e8106801f9f58896387828813125bf5b6f79451e Mon Sep 17 00:00:00 2001 From: suzana_dirla Date: Tue, 7 Nov 2017 13:42:31 +0200 Subject: [PATCH 15/27] [ACA-980] Clean up code: remove folder-dialog.component from ACA this is now available on ADF side, no need to have it here anymore --- src/app/common/common.module.ts | 6 +- .../dialogs/folder-dialog.component.html | 62 ----- .../dialogs/folder-dialog.component.spec.ts | 260 ------------------ .../common/dialogs/folder-dialog.component.ts | 138 ---------- .../common/dialogs/folder-name.validators.ts | 45 --- 5 files changed, 1 insertion(+), 510 deletions(-) delete mode 100644 src/app/common/dialogs/folder-dialog.component.html delete mode 100644 src/app/common/dialogs/folder-dialog.component.spec.ts delete mode 100644 src/app/common/dialogs/folder-dialog.component.ts delete mode 100644 src/app/common/dialogs/folder-name.validators.ts diff --git a/src/app/common/common.module.ts b/src/app/common/common.module.ts index 85ba72e63..a31010d56 100644 --- a/src/app/common/common.module.ts +++ b/src/app/common/common.module.ts @@ -23,7 +23,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { AdfModule } from '../adf.module'; import { MaterialModule } from './material.module'; -import { FolderDialogComponent } from './dialogs/folder-dialog.component'; import { NodeCopyDirective } from './directives/node-copy.directive'; import { NodeDeleteDirective } from './directives/node-delete.directive'; import { NodeMoveDirective } from './directives/node-move.directive'; @@ -48,7 +47,6 @@ export function modules() { export function declarations() { return [ - FolderDialogComponent, NodeCopyDirective, NodeDeleteDirective, NodeMoveDirective, @@ -71,9 +69,7 @@ export function providers() { @NgModule({ imports: modules(), declarations: declarations(), - entryComponents: [ - FolderDialogComponent - ], + entryComponents: [], providers: providers(), exports: [ ...modules(), diff --git a/src/app/common/dialogs/folder-dialog.component.html b/src/app/common/dialogs/folder-dialog.component.html deleted file mode 100644 index b392bea9d..000000000 --- a/src/app/common/dialogs/folder-dialog.component.html +++ /dev/null @@ -1,62 +0,0 @@ -

- {{ - (editing - ? 'APP.FOLDER_DIALOG.EDIT_FOLDER_TITLE' - : 'APP.FOLDER_DIALOG.CREATE_FOLDER_TITLE' - ) | translate - }} -

- - -
- - - - - - {{ 'APP.FOLDER_DIALOG.FOLDER_NAME.ERRORS.REQUIRED' | translate }} - - - - {{ form.controls['name'].errors?.message | translate }} - - - - -
-
- - - - -
-
- - - - - - diff --git a/src/app/common/dialogs/folder-dialog.component.spec.ts b/src/app/common/dialogs/folder-dialog.component.spec.ts deleted file mode 100644 index ef118baa6..000000000 --- a/src/app/common/dialogs/folder-dialog.component.spec.ts +++ /dev/null @@ -1,260 +0,0 @@ -/*! - * @license - * Copyright 2017 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 { TestBed, async } from '@angular/core/testing'; -import { Observable } from 'rxjs/Rx'; -import { MatDialogModule, MatDialogRef } from '@angular/material'; -import { CoreModule, NodesApiService, TranslationService, NotificationService } from 'ng2-alfresco-core'; - -import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/testing'; -import { FolderDialogComponent } from './folder-dialog.component'; -import { ComponentFixture } from '@angular/core/testing'; - -describe('FolderDialogComponent', () => { - - let fixture: ComponentFixture; - let component: FolderDialogComponent; - let translationService: TranslationService; - let nodesApi: NodesApiService; - let notificationService: NotificationService; - let dialogRef; - - beforeEach(async(() => { - dialogRef = { - close: jasmine.createSpy('close') - }; - - TestBed.configureTestingModule({ - imports: [ - CoreModule, - MatDialogModule - ], - declarations: [ - FolderDialogComponent - ], - providers: [ - { provide: MatDialogRef, useValue: dialogRef } - ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(FolderDialogComponent); - component = fixture.componentInstance; - - nodesApi = TestBed.get(NodesApiService); - notificationService = TestBed.get(NotificationService); - - translationService = TestBed.get(TranslationService); - spyOn(translationService, 'get').and.returnValue(Observable.of('message')); - }); - - describe('Edit', () => { - - beforeEach(() => { - component.data = { - folder: { - id: 'node-id', - name: 'folder-name', - properties: { - ['cm:description']: 'folder-description' - } - } - }; - component.ngOnInit(); - }); - - it('should init form with folder name and description', () => { - expect(component.name).toBe('folder-name'); - expect(component.description).toBe('folder-description'); - }); - - it('should update form input', () => { - component.form.controls['name'].setValue('folder-name-update'); - component.form.controls['description'].setValue('folder-description-update'); - - expect(component.name).toBe('folder-name-update'); - expect(component.description).toBe('folder-description-update'); - }); - - it('should submit updated values if form is valid', () => { - spyOn(nodesApi, 'updateNode').and.returnValue(Observable.of({})); - - component.form.controls['name'].setValue('folder-name-update'); - component.form.controls['description'].setValue('folder-description-update'); - - component.submit(); - - expect(nodesApi.updateNode).toHaveBeenCalledWith( - 'node-id', - { - name: 'folder-name-update', - properties: { - 'cm:title': 'folder-name-update', - 'cm:description': 'folder-description-update' - } - } - ); - }); - - it('should call dialog to close with form data when submit is succesfluly', () => { - const folder = { - data: 'folder-data' - }; - - spyOn(nodesApi, 'updateNode').and.returnValue(Observable.of(folder)); - - component.submit(); - - expect(dialogRef.close).toHaveBeenCalledWith(folder); - }); - - it('should not submit if form is invalid', () => { - spyOn(nodesApi, 'updateNode'); - - component.form.controls['name'].setValue(''); - component.form.controls['description'].setValue(''); - - component.submit(); - - expect(component.form.valid).toBe(false); - expect(nodesApi.updateNode).not.toHaveBeenCalled(); - }); - - it('should not call dialog to close if submit fails', () => { - spyOn(nodesApi, 'updateNode').and.returnValue(Observable.throw('error')); - spyOn(component, 'handleError').and.callFake(val => val); - - component.submit(); - - expect(component.handleError).toHaveBeenCalled(); - expect(dialogRef.close).not.toHaveBeenCalled(); - }); - }); - - describe('Create', () => { - beforeEach(() => { - component.data = { - parentNodeId: 'parentNodeId', - folder: null - }; - component.ngOnInit(); - }); - - it('should init form with empty inputs', () => { - expect(component.name).toBe(''); - expect(component.description).toBe(''); - }); - - it('should update form input', () => { - component.form.controls['name'].setValue('folder-name-update'); - component.form.controls['description'].setValue('folder-description-update'); - - expect(component.name).toBe('folder-name-update'); - expect(component.description).toBe('folder-description-update'); - }); - - it('should submit updated values if form is valid', () => { - spyOn(nodesApi, 'createFolder').and.returnValue(Observable.of({})); - - component.form.controls['name'].setValue('folder-name-update'); - component.form.controls['description'].setValue('folder-description-update'); - - component.submit(); - - expect(nodesApi.createFolder).toHaveBeenCalledWith( - 'parentNodeId', - { - name: 'folder-name-update', - properties: { - 'cm:title': 'folder-name-update', - 'cm:description': 'folder-description-update' - } - } - ); - }); - - it('should call dialog to close with form data when submit is succesfluly', () => { - const folder = { - data: 'folder-data' - }; - - component.form.controls['name'].setValue('name'); - component.form.controls['description'].setValue('description'); - - spyOn(nodesApi, 'createFolder').and.returnValue(Observable.of(folder)); - - component.submit(); - - expect(dialogRef.close).toHaveBeenCalledWith(folder); - }); - - it('should not submit if form is invalid', () => { - spyOn(nodesApi, 'createFolder'); - - component.form.controls['name'].setValue(''); - component.form.controls['description'].setValue(''); - - component.submit(); - - expect(component.form.valid).toBe(false); - expect(nodesApi.createFolder).not.toHaveBeenCalled(); - }); - - it('should not call dialog to close if submit fails', () => { - spyOn(nodesApi, 'createFolder').and.returnValue(Observable.throw('error')); - spyOn(component, 'handleError').and.callFake(val => val); - - component.form.controls['name'].setValue('name'); - component.form.controls['description'].setValue('description'); - - component.submit(); - - expect(component.handleError).toHaveBeenCalled(); - expect(dialogRef.close).not.toHaveBeenCalled(); - }); - }); - - describe('handleError()', () => { - it('should raise error for 409', () => { - spyOn(notificationService, 'openSnackMessage').and.stub(); - - const error = { - message: '{ "error": { "statusCode" : 409 } }' - }; - - component.handleError(error); - - expect(notificationService.openSnackMessage).toHaveBeenCalled(); - expect(translationService.get).toHaveBeenCalledWith('APP.MESSAGES.ERRORS.EXISTENT_FOLDER'); - }); - - it('should raise generic error', () => { - spyOn(notificationService, 'openSnackMessage').and.stub(); - - const error = { - message: '{ "error": { "statusCode" : 123 } }' - }; - - component.handleError(error); - - expect(notificationService.openSnackMessage).toHaveBeenCalled(); - expect(translationService.get).toHaveBeenCalledWith('APP.MESSAGES.ERRORS.GENERIC'); - }); - }); -}); diff --git a/src/app/common/dialogs/folder-dialog.component.ts b/src/app/common/dialogs/folder-dialog.component.ts deleted file mode 100644 index e8a395511..000000000 --- a/src/app/common/dialogs/folder-dialog.component.ts +++ /dev/null @@ -1,138 +0,0 @@ -/*! - * @license - * Copyright 2017 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 { Observable } from 'rxjs/Rx'; - -import { Component, Inject, Optional, OnInit } from '@angular/core'; -import { FormGroup, FormBuilder, Validators } from '@angular/forms'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; - -import { TranslationService, NodesApiService, NotificationService } from 'ng2-alfresco-core'; -import { MinimalNodeEntryEntity } from 'alfresco-js-api'; - -import { forbidSpecialCharacters, forbidEndingDot, forbidOnlySpaces } from './folder-name.validators'; - -@Component({ - selector: 'app-folder-dialog', - templateUrl: './folder-dialog.component.html' -}) -export class FolderDialogComponent implements OnInit { - form: FormGroup; - folder: MinimalNodeEntryEntity = null; - - constructor( - private formBuilder: FormBuilder, - private dialog: MatDialogRef, - private nodesApi: NodesApiService, - private translation: TranslationService, - private notification: NotificationService, - @Optional() - @Inject(MAT_DIALOG_DATA) - public data: any - ) {} - - get editing(): boolean { - return !!this.data.folder; - } - - ngOnInit() { - const { folder } = this.data; - let name = '', description = ''; - - if (folder) { - const { properties } = folder; - - name = folder.name || ''; - description = properties ? properties['cm:description'] : ''; - } - - const validators = { - name: [ - Validators.required, - forbidSpecialCharacters, - forbidEndingDot, - forbidOnlySpaces - ] - }; - - this.form = this.formBuilder.group({ - name: [ name, validators.name ], - description: [ description ] - }); - } - - get name(): string { - const { name } = this.form.value; - - return (name || '').trim(); - } - - get description(): string { - const { description } = this.form.value; - - return (description || '').trim(); - } - - private get properties(): any { - const { name: title, description } = this; - - return { - 'cm:title': title, - 'cm:description': description - }; - } - - private create(): Observable { - const { name, properties, nodesApi, data: { parentNodeId} } = this; - return nodesApi.createFolder(parentNodeId, { name, properties }); - } - - private edit(): Observable { - const { name, properties, nodesApi, data: { folder: { id: nodeId }} } = this; - return nodesApi.updateNode(nodeId, { name, properties }); - } - - submit() { - const { form, dialog, editing } = this; - - if (!form.valid) { return; } - - (editing ? this.edit() : this.create()) - .subscribe( - (folder: MinimalNodeEntryEntity) => dialog.close(folder), - (error) => this.handleError(error) - ); - } - - handleError(error: any): any { - let i18nMessageString = 'APP.MESSAGES.ERRORS.GENERIC'; - - try { - const { error: { statusCode } } = JSON.parse(error.message); - - if (statusCode === 409) { - i18nMessageString = 'APP.MESSAGES.ERRORS.EXISTENT_FOLDER'; - } - } catch (err) { /* Do nothing, keep the original message */ } - - this.translation.get(i18nMessageString).subscribe(message => { - this.notification.openSnackMessage(message, 3000); - }); - - return error; - } -} diff --git a/src/app/common/dialogs/folder-name.validators.ts b/src/app/common/dialogs/folder-name.validators.ts deleted file mode 100644 index 714ac127f..000000000 --- a/src/app/common/dialogs/folder-name.validators.ts +++ /dev/null @@ -1,45 +0,0 @@ -/*! - * @license - * Copyright 2017 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 { FormControl } from '@angular/forms'; - -const I18N_ERRORS_PATH = 'APP.FOLDER_DIALOG.FOLDER_NAME.ERRORS'; - -export function forbidSpecialCharacters({ value }: FormControl) { - const specialCharacters: RegExp = /([\*\"\<\>\\\/\?\:\|])/; - const isValid: boolean = !specialCharacters.test(value); - - return (isValid) ? null : { - message: `${I18N_ERRORS_PATH}.SPECIAL_CHARACTERS` - }; -} - -export function forbidEndingDot({ value }: FormControl) { - const isValid: boolean = ((value || '').split('').pop() !== '.'); - - return isValid ? null : { - message: `${I18N_ERRORS_PATH}.ENDING_DOT` - }; -} - -export function forbidOnlySpaces({ value }: FormControl) { - const isValid: boolean = !!((value || '')).trim(); - - return isValid ? null : { - message: `${I18N_ERRORS_PATH}.ONLY_SPACES` - }; -} From d0226f3f293acac15ee9711e9fa0816e7d13480a Mon Sep 17 00:00:00 2001 From: Bogdan Cilibiu Date: Wed, 8 Nov 2017 12:07:54 +0200 Subject: [PATCH 16/27] temporary no tree shaking --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 125142c12..375742605 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "ng": "ng", "start": "ng serve --open", "build": "ng build --prod", + "build:nts": "ng build", "build:dev": "ng build && node postbuild-dev.js", "test": "ng test", "lint": "ng lint", From 08179772e3fb749b72e18da18b6aaf27bd2e24d9 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Wed, 8 Nov 2017 16:12:53 +0200 Subject: [PATCH 17/27] fix login page selector --- e2e/components/login/login.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/components/login/login.ts b/e2e/components/login/login.ts index 742f08635..ceb89a61c 100644 --- a/e2e/components/login/login.ts +++ b/e2e/components/login/login.ts @@ -19,7 +19,7 @@ import { by, ElementFinder, promise } from 'protractor'; import { Component } from '../component'; export class LoginComponent extends Component { - static selector = 'alfresco-login'; + static selector = 'adf-login'; private locators = { usernameInput: by.css('input#username'), From f1fc4d2ffedc71a404ec927015bcef16689a763e Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Wed, 8 Nov 2017 16:14:11 +0200 Subject: [PATCH 18/27] set hash strategy to false as per latest changes --- e2e/pages/page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/pages/page.ts b/e2e/pages/page.ts index 0ee4009cb..7ec381401 100644 --- a/e2e/pages/page.ts +++ b/e2e/pages/page.ts @@ -18,7 +18,7 @@ import { browser, element, by, ElementFinder, promise } from 'protractor'; export abstract class Page { - private static USE_HASH_STRATEGY = true; + private static USE_HASH_STRATEGY = false; private locators = { app: by.css('app-root'), From 5a28a7fcab222d5768043d708e803845bf66cc42 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Wed, 8 Nov 2017 16:15:06 +0200 Subject: [PATCH 19/27] some changes to create-folder and edit-folder tests --- e2e/suites/actions/create-folder.test.ts | 27 +++++++++++++++--------- e2e/suites/actions/edit-folder.test.ts | 4 ++-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/e2e/suites/actions/create-folder.test.ts b/e2e/suites/actions/create-folder.test.ts index 27d5f37de..3bb9176bb 100644 --- a/e2e/suites/actions/create-folder.test.ts +++ b/e2e/suites/actions/create-folder.test.ts @@ -17,7 +17,7 @@ import { protractor, browser, by, ElementFinder } from 'protractor'; -import { APP_ROUTES, BROWSER_WAIT_TIMEOUT } from '../../configs'; +import { APP_ROUTES, BROWSER_WAIT_TIMEOUT, SITE_VISIBILITY, SITE_ROLES } from '../../configs'; import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; import { CreateOrEditFolderDialog } from '../../components/dialog/create-edit-folder-dialog'; import { LocalStorageUtility } from '../../utilities/local-storage'; @@ -31,7 +31,9 @@ describe('Create folder', () => { const folderName2 = 'my-folder2'; const folderDescription = 'description of my folder'; const duplicateFolderName = 'duplicate-folder-name'; - const nameWithSpaces = ' folder name '; + const nameWithSpaces = ' folder-name '; + + const siteName = 'site-private'; const apis = { admin: new RepoClient(), @@ -55,6 +57,9 @@ describe('Create folder', () => { beforeAll(done => { apis.admin.people.createUser(username, password) + .then(() => apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PRIVATE)) + .then(() => apis.admin.nodes.createFolders([ folderName1 ], `Sites/${siteName}/documentLibrary`)) + .then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_CONSUMER)) .then(() => apis.user.nodes.createFolders([ duplicateFolderName ])) .then(() => loginPage.load()) .then(() => loginPage.loginWith(username, password)) @@ -143,11 +148,12 @@ describe('Create folder', () => { }); it('option is disabled when not enough permissions', () => { - // refactor after implementing Breadcrumb automation component - const breadcrumbRoot: ElementFinder = protractor.element(by.css('.adf-breadcrumb-item[title="User Homes"]')); + const fileLibrariesPage = new BrowsingPage(APP_ROUTES.FILE_LIBRARIES); - browser.actions().mouseMove(breadcrumbRoot).click().perform() - .then(() => personalFilesPage.sidenav.openNewMenu()) + fileLibrariesPage.sidenav.navigateToLinkByLabel('File Libraries') + .then(() => fileLibrariesPage.dataTable.doubleClickOnRowByContainingText(siteName)) + .then(() => fileLibrariesPage.dataTable.doubleClickOnRowByContainingText(folderName1)) + .then(() => fileLibrariesPage.sidenav.openNewMenu()) .then(menu => { const isEnabled = menu.getItemByLabel('Create folder').getWebElement().isEnabled(); expect(isEnabled).toBe(false, 'Create folder is not disabled'); @@ -155,11 +161,12 @@ describe('Create folder', () => { }); it('disabled option tooltip', () => { - // refactor after implementing Breadcrumb automation component - const breadcrumbRoot: ElementFinder = protractor.element(by.css('.adf-breadcrumb-item[title="User Homes"]')); + const fileLibrariesPage = new BrowsingPage(APP_ROUTES.FILE_LIBRARIES); - browser.actions().mouseMove(breadcrumbRoot).click().perform() - .then(() => personalFilesPage.sidenav.openNewMenu()) + fileLibrariesPage.sidenav.navigateToLinkByLabel('File Libraries') + .then(() => fileLibrariesPage.dataTable.doubleClickOnRowByContainingText(siteName)) + .then(() => fileLibrariesPage.dataTable.doubleClickOnRowByContainingText(folderName1)) + .then(() => fileLibrariesPage.sidenav.openNewMenu()) .then(menu => { const action = browser.actions().mouseMove(menu.getItemByLabel('Create folder')); action.perform() diff --git a/e2e/suites/actions/edit-folder.test.ts b/e2e/suites/actions/edit-folder.test.ts index 47bf0b749..c39de96ff 100644 --- a/e2e/suites/actions/edit-folder.test.ts +++ b/e2e/suites/actions/edit-folder.test.ts @@ -44,7 +44,7 @@ describe('Edit folder', () => { const loginPage = new LoginPage(); const logoutPage = new LogoutPage(); - const personalFilesPage = new BrowsingPage(); + const personalFilesPage = new BrowsingPage(APP_ROUTES.PERSONAL_FILES); const editDialog = new CreateOrEditFolderDialog(); const dataTable = personalFilesPage.dataTable; const editButton = personalFilesPage.toolbar.actions.getButtonByTitleAttribute('Edit'); @@ -130,7 +130,7 @@ describe('Edit folder', () => { }); it('button is not displayed when not enough permissions', () => { - const fileLibrariesPage = new BrowsingPage(); + const fileLibrariesPage = new BrowsingPage(APP_ROUTES.FILE_LIBRARIES); fileLibrariesPage.sidenav.navigateToLinkByLabel('File Libraries') .then(() => fileLibrariesPage.dataTable.doubleClickOnRowByContainingText(siteName)) From 9632f57e5e8fb16c7504da2f8d2e7de5d16b8645 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Wed, 8 Nov 2017 16:16:18 +0200 Subject: [PATCH 20/27] provide the list of specs to enforce their execution order proper formatting --- protractor.conf.js | 91 ++++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/protractor.conf.js b/protractor.conf.js index 9db00659f..9141ac324 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -8,49 +8,54 @@ const jasmineReporters = require('jasmine-reporters'); const projectRoot = path.resolve(__dirname); exports.config = { - allScriptsTimeout: 11000, - specs: [ - './e2e/**/*.test.ts' - ], - capabilities: { - 'browserName': 'chrome', - chromeOptions: { - prefs: { - 'credentials_enable_service': false + allScriptsTimeout: 11000, + specs: [ + './e2e/suites/authentication/*.test.ts', + './e2e/suites/list-views/*.test.ts', + './e2e/suites/application/page-titles.test.ts', + './e2e/suites/navigation/side-navigation.test.ts', + './e2e/suites/pagination/pagination.test.ts', + './e2e/suites/actions/*.test.ts' + ], + capabilities: { + 'browserName': 'chrome', + chromeOptions: { + prefs: { + 'credentials_enable_service': false + } } - } - }, - directConnect: true, - baseUrl: 'http://localhost:3000', - framework: 'jasmine', - jasmineNodeOpts: { - showColors: true, - defaultTimeoutInterval: 30000, - print: function() {} - }, - plugins: [{ - package: 'jasmine2-protractor-utils', - disableHTMLReport: false, - disableScreenshot: false, - screenshotOnExpectFailure: true, - screenshotOnSpecFailure: false, - clearFoldersBeforeTest: true, - htmlReportDir: `${projectRoot}/e2e-output/html-report/`, - screenshotPath: `${projectRoot}/e2e-output/screenshots/` - }], - onPrepare() { - require('ts-node').register({ - project: 'e2e/tsconfig.e2e.json' - }); - jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + }, + directConnect: true, + baseUrl: 'http://localhost:3000', + framework: 'jasmine2', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + plugins: [{ + package: 'jasmine2-protractor-utils', + disableHTMLReport: false, + disableScreenshot: false, + screenshotOnExpectFailure: true, + screenshotOnSpecFailure: false, + clearFoldersBeforeTest: true, + htmlReportDir: `${projectRoot}/e2e-output/html-report/`, + screenshotPath: `${projectRoot}/e2e-output/screenshots/` + }], + onPrepare() { + require('ts-node').register({ + project: 'e2e/tsconfig.e2e.json' + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); - jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({ - consolidateAll: true, - savePath: `${projectRoot}/e2e-output/junit-report`, - filePrefix: 'results.xml', - useDotNotation: false, - useFullTestName: false, - reportFailedUrl: true - })); - } + jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({ + consolidateAll: true, + savePath: `${projectRoot}/e2e-output/junit-report`, + filePrefix: 'results.xml', + useDotNotation: false, + useFullTestName: false, + reportFailedUrl: true + })); + } }; From 9058febfd17b898db4621a9fbc09c1f7b85b5084 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Wed, 8 Nov 2017 19:05:01 +0200 Subject: [PATCH 21/27] update package.json to use latest version of protractor and jasmine --- package.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 375742605..4a455c541 100644 --- a/package.json +++ b/package.json @@ -46,14 +46,14 @@ "@angular/cli": "1.4.7", "@angular/compiler-cli": "4.4.5", "@angular/language-service": "4.4.5", - "@types/jasmine": "~2.5.53", - "@types/jasminewd2": "~2.0.2", + "@types/jasmine": "^2.5.53", + "@types/jasminewd2": "^2.0.2", "@types/node": "~6.0.60", "codelyzer": "~3.2.0", - "jasmine-core": "~2.6.2", - "jasmine-reporters": "2.2.1", - "jasmine-spec-reporter": "~4.1.0", - "jasmine2-protractor-utils": "1.3.0", + "jasmine-core": "^2.6.2", + "jasmine-reporters": "^2.2.1", + "jasmine-spec-reporter": "^4.1.0", + "jasmine2-protractor-utils": "^1.3.0", "karma": "~1.7.0", "karma-chrome-launcher": "~2.1.1", "karma-cli": "~1.0.1", @@ -61,7 +61,7 @@ "karma-jasmine": "~1.1.0", "karma-jasmine-html-reporter": "^0.2.2", "node-rest-client": "^3.1.0", - "protractor": "~5.1.2", + "protractor": "^5.1.2", "ts-node": "~3.2.0", "tslint": "~5.7.0", "typescript": "~2.3.3" From 609163d1366e42df8124bf538846c38c84361c21 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Wed, 8 Nov 2017 23:38:20 +0200 Subject: [PATCH 22/27] rename utils file to allow future more utils to be added --- e2e/suites/actions/create-folder.test.ts | 4 ++-- e2e/suites/actions/edit-folder.test.ts | 4 ++-- e2e/suites/application/page-titles.test.ts | 4 ++-- e2e/suites/authentication/login.test.ts | 4 ++-- e2e/suites/authentication/logout.test.ts | 4 ++-- e2e/suites/list-views/personal-files.test.ts | 6 +++--- e2e/suites/navigation/side-navigation.test.ts | 4 ++-- e2e/suites/pagination/pagination.test.ts | 4 ++-- e2e/utilities/{local-storage.ts => utils.ts} | 18 +++++++----------- 9 files changed, 24 insertions(+), 28 deletions(-) rename e2e/utilities/{local-storage.ts => utils.ts} (64%) diff --git a/e2e/suites/actions/create-folder.test.ts b/e2e/suites/actions/create-folder.test.ts index 3bb9176bb..b5ea9a296 100644 --- a/e2e/suites/actions/create-folder.test.ts +++ b/e2e/suites/actions/create-folder.test.ts @@ -20,7 +20,7 @@ import { protractor, browser, by, ElementFinder } from 'protractor'; import { APP_ROUTES, BROWSER_WAIT_TIMEOUT, SITE_VISIBILITY, SITE_ROLES } from '../../configs'; import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; import { CreateOrEditFolderDialog } from '../../components/dialog/create-edit-folder-dialog'; -import { LocalStorageUtility } from '../../utilities/local-storage'; +import { Utils } from '../../utilities/utils'; import { RepoClient, NodeContentTree } from '../../utilities/repo-client/repo-client'; describe('Create folder', () => { @@ -86,7 +86,7 @@ describe('Create folder', () => { nameWithSpaces.trim() ]), logoutPage.load() - .then(() => LocalStorageUtility.clear()) + .then(() => Utils.clearLocalStorage()) ]) .then(done); }); diff --git a/e2e/suites/actions/edit-folder.test.ts b/e2e/suites/actions/edit-folder.test.ts index c39de96ff..497fd00df 100644 --- a/e2e/suites/actions/edit-folder.test.ts +++ b/e2e/suites/actions/edit-folder.test.ts @@ -20,7 +20,7 @@ import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; import { APP_ROUTES, SITE_VISIBILITY, SITE_ROLES } from '../../configs'; import { RepoClient } from '../../utilities/repo-client/repo-client'; import { CreateOrEditFolderDialog } from '../../components/dialog/create-edit-folder-dialog'; -import { LocalStorageUtility } from '../../utilities/local-storage'; +import { Utils } from '../../utilities/utils'; describe('Edit folder', () => { const username = 'jane.doe'; @@ -82,7 +82,7 @@ describe('Edit folder', () => { apis.admin.sites.deleteSite(siteName, true), apis.user.nodes.deleteNodes([ folderName, folderNameEdited, duplicateFolderName ]), logoutPage.load() - .then(() => LocalStorageUtility.clear()) + .then(() => Utils.clearLocalStorage()) ]) .then(done); }); diff --git a/e2e/suites/application/page-titles.test.ts b/e2e/suites/application/page-titles.test.ts index b9085a6f7..6906435af 100644 --- a/e2e/suites/application/page-titles.test.ts +++ b/e2e/suites/application/page-titles.test.ts @@ -19,7 +19,7 @@ import { browser } from 'protractor'; import { SIDEBAR_LABELS } from '../../configs'; import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; -import { LocalStorageUtility } from '../../utilities/local-storage'; +import { Utils } from '../../utilities/utils'; describe('Page titles', () => { const loginPage = new LoginPage(); @@ -65,7 +65,7 @@ describe('Page titles', () => { afterAll(done => { logoutPage.load() - .then(() => LocalStorageUtility.clear()) + .then(() => Utils.clearLocalStorage()) .then(done); }); diff --git a/e2e/suites/authentication/login.test.ts b/e2e/suites/authentication/login.test.ts index 922386dad..56d804805 100644 --- a/e2e/suites/authentication/login.test.ts +++ b/e2e/suites/authentication/login.test.ts @@ -19,7 +19,7 @@ import { browser } from 'protractor'; import { APP_ROUTES } from '../../configs'; import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; -import { LocalStorageUtility } from '../../utilities/local-storage'; +import { Utils } from '../../utilities/utils'; import { RepoClient } from '../../utilities/repo-client/repo-client'; describe('Login', () => { @@ -63,7 +63,7 @@ describe('Login', () => { afterEach(done => { logoutPage.load() - .then(() => LocalStorageUtility.clear()) + .then(() => Utils.clearLocalStorage()) .then(done); }); diff --git a/e2e/suites/authentication/logout.test.ts b/e2e/suites/authentication/logout.test.ts index 050e2913a..6a48edc25 100644 --- a/e2e/suites/authentication/logout.test.ts +++ b/e2e/suites/authentication/logout.test.ts @@ -19,7 +19,7 @@ import { browser } from 'protractor'; import { APP_ROUTES, BROWSER_WAIT_TIMEOUT } from '../../configs'; import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; -import { LocalStorageUtility } from '../../utilities/local-storage'; +import { Utils } from '../../utilities/utils'; import { RepoClient } from '../../utilities/repo-client/repo-client'; describe('Logout', () => { @@ -48,7 +48,7 @@ describe('Logout', () => { afterEach((done) => { logoutPage.load() - .then(() => LocalStorageUtility.clear()) + .then(() => Utils.clearLocalStorage()) .then(done); }); diff --git a/e2e/suites/list-views/personal-files.test.ts b/e2e/suites/list-views/personal-files.test.ts index 891e729a6..efe263793 100644 --- a/e2e/suites/list-views/personal-files.test.ts +++ b/e2e/suites/list-views/personal-files.test.ts @@ -19,7 +19,7 @@ import { browser } from 'protractor'; import { APP_ROUTES } from '../../configs'; import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; -import { LocalStorageUtility } from '../../utilities/local-storage'; +import { Utils } from '../../utilities/utils'; import { RepoClient, NodeContentTree } from '../../utilities/repo-client/repo-client'; describe('Personal Files', () => { @@ -81,7 +81,7 @@ describe('Personal Files', () => { afterAll(done => { logoutPage.load() - .then(() => LocalStorageUtility.clear()) + .then(() => Utils.clearLocalStorage()) .then(done); }); @@ -109,7 +109,7 @@ describe('Personal Files', () => { afterAll(done => { logoutPage.load() - .then(() => LocalStorageUtility.clear()) + .then(() => Utils.clearLocalStorage()) .then(done); }); diff --git a/e2e/suites/navigation/side-navigation.test.ts b/e2e/suites/navigation/side-navigation.test.ts index 93e6219fe..bf6c8541d 100644 --- a/e2e/suites/navigation/side-navigation.test.ts +++ b/e2e/suites/navigation/side-navigation.test.ts @@ -19,7 +19,7 @@ import { browser } from 'protractor'; import { APP_ROUTES, SIDEBAR_LABELS } from '../../configs'; import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; -import { LocalStorageUtility } from '../../utilities/local-storage'; +import { Utils } from '../../utilities/utils'; describe('Side navigation', () => { const loginPage = new LoginPage(); @@ -38,7 +38,7 @@ describe('Side navigation', () => { afterAll(done => { logoutPage.load() - .then(() => LocalStorageUtility.clear()) + .then(() => Utils.clearLocalStorage()) .then(done); }); diff --git a/e2e/suites/pagination/pagination.test.ts b/e2e/suites/pagination/pagination.test.ts index f0298ff51..7fb40c359 100644 --- a/e2e/suites/pagination/pagination.test.ts +++ b/e2e/suites/pagination/pagination.test.ts @@ -19,7 +19,7 @@ import { browser } from 'protractor'; import { APP_ROUTES } from '../../configs'; import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; -import { LocalStorageUtility } from '../../utilities/local-storage'; +import { Utils } from '../../utilities/utils'; import { RepoClient, NodeContentTree } from '../../utilities/repo-client/repo-client'; describe('Pagination', () => { @@ -75,7 +75,7 @@ describe('Pagination', () => { afterAll(done => { logoutPage .load() - .then(() => LocalStorageUtility.clear()) + .then(() => Utils.clearLocalStorage()) .then(() => nodesApi.deleteNodes([ content.name ])) .then(done); }); diff --git a/e2e/utilities/local-storage.ts b/e2e/utilities/utils.ts similarity index 64% rename from e2e/utilities/local-storage.ts rename to e2e/utilities/utils.ts index 46d7d7926..0a6072f68 100644 --- a/e2e/utilities/local-storage.ts +++ b/e2e/utilities/utils.ts @@ -17,18 +17,14 @@ import { browser, promise } from 'protractor'; -declare var window; - -export class LocalStorageUtility { - static clear(): promise.Promise { - return browser.executeScript(() => { - return window.localStorage.clear(); - }); +export class Utils { + // generate a random value + static random(): string { + return Math.random().toString(36).substring(3, 10); } - static getTicket(): promise.Promise { - return browser.executeScript(() => { - return window.localStorage.getItem('ticket-ECM'); - }); + // local storage + static clearLocalStorage(): promise.Promise { + return browser.executeScript('window.localStorage.clear();'); } } From e41550c4f08bfcf80cc417fef588390f3e82bbdb Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Wed, 8 Nov 2017 23:38:49 +0200 Subject: [PATCH 23/27] small fix for the logout method --- e2e/pages/logout-page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/pages/logout-page.ts b/e2e/pages/logout-page.ts index f1c0b65ce..5a8f6082a 100644 --- a/e2e/pages/logout-page.ts +++ b/e2e/pages/logout-page.ts @@ -22,7 +22,7 @@ import { APP_ROUTES } from '../configs'; export class LogoutPage extends Page { /** @override */ constructor() { - super(APP_ROUTES.LOGOUT); + super(APP_ROUTES.LOGIN); } /** @override */ From 1f7b09af836cff9d4da3df9f66eb7cc1264f84e1 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Thu, 9 Nov 2017 00:24:11 +0200 Subject: [PATCH 24/27] few more changes trying to fix randomly failing tests --- e2e/suites/actions/create-folder.test.ts | 264 ++++++++++++----------- e2e/suites/actions/edit-folder.test.ts | 195 +++++++++-------- 2 files changed, 250 insertions(+), 209 deletions(-) diff --git a/e2e/suites/actions/create-folder.test.ts b/e2e/suites/actions/create-folder.test.ts index b5ea9a296..c608562cf 100644 --- a/e2e/suites/actions/create-folder.test.ts +++ b/e2e/suites/actions/create-folder.test.ts @@ -27,6 +27,7 @@ describe('Create folder', () => { const username = 'jane.doe'; const password = 'jane.doe'; + const parent = 'parent-folder'; const folderName1 = 'my-folder1'; const folderName2 = 'my-folder2'; const folderDescription = 'description of my folder'; @@ -60,7 +61,7 @@ describe('Create folder', () => { .then(() => apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PRIVATE)) .then(() => apis.admin.nodes.createFolders([ folderName1 ], `Sites/${siteName}/documentLibrary`)) .then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_CONSUMER)) - .then(() => apis.user.nodes.createFolders([ duplicateFolderName ])) + .then(() => apis.user.nodes.createFolders([ duplicateFolderName ], parent)) .then(() => loginPage.load()) .then(() => loginPage.loginWith(username, password)) .then(done); @@ -79,12 +80,7 @@ describe('Create folder', () => { afterAll(done => { Promise .all([ - apis.user.nodes.deleteNodes([ - folderName1, - folderName2, - duplicateFolderName, - nameWithSpaces.trim() - ]), + apis.user.nodes.deleteNodes([ parent ]), logoutPage.load() .then(() => Utils.clearLocalStorage()) ]) @@ -92,59 +88,67 @@ describe('Create folder', () => { }); it('option is enabled when having enough permissions', () => { - personalFilesPage.sidenav.openNewMenu() - .then((menu) => { - const isEnabled = menu.getItemByLabel('Create folder').getWebElement().isEnabled(); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => personalFilesPage.sidenav.openNewMenu() + .then((menu) => { + const isEnabled = menu.getItemByLabel('Create folder').getWebElement().isEnabled(); - expect(isEnabled).toBe(true, 'Create folder is not enabled'); - }); + expect(isEnabled).toBe(true, 'Create folder is not enabled'); + }) + ); }); it('creates new folder with name', () => { - openCreateDialog() - .then(() => createDialog.enterName(folderName1).clickCreate()) - .then(() => createDialog.waitForDialogToClose()) - .then(() => dataTable.waitForHeader()) - .then(() => { - const isPresent = dataTable.getRowByContainingText(folderName1).isPresent(); - expect(isPresent).toBe(true, 'Folder not displayed in list view'); - }); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => openCreateDialog() + .then(() => createDialog.enterName(folderName1).clickCreate()) + .then(() => createDialog.waitForDialogToClose()) + .then(() => dataTable.waitForHeader()) + .then(() => { + const isPresent = dataTable.getRowByContainingText(folderName1).isPresent(); + expect(isPresent).toBe(true, 'Folder not displayed in list view'); + }) + ); }); it('creates new folder with name and description', () => { - openCreateDialog() - .then(() => { - createDialog - .enterName(folderName2) - .enterDescription(folderDescription) - .clickCreate(); - }) - .then(() => createDialog.waitForDialogToClose()) - .then(() => dataTable.waitForHeader()) - .then(() => { - const isPresent = dataTable.getRowByContainingText(folderName2).isPresent(); - expect(isPresent).toBe(true, 'Folder not displayed in list view'); - }) - .then(() => { - apis.user.nodes.getNodeDescription(folderName2) - .then((description) => { - expect(description).toEqual(folderDescription, 'Description is not correct'); - }); - }); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => openCreateDialog() + .then(() => { + createDialog + .enterName(folderName2) + .enterDescription(folderDescription) + .clickCreate(); + }) + .then(() => createDialog.waitForDialogToClose()) + .then(() => dataTable.waitForHeader()) + .then(() => { + const isPresent = dataTable.getRowByContainingText(folderName2).isPresent(); + expect(isPresent).toBe(true, 'Folder not displayed in list view'); + }) + .then(() => { + apis.user.nodes.getNodeDescription(folderName2) + .then((description) => { + expect(description).toEqual(folderDescription, 'Description is not correct'); + }); + }) + ); }); it('enabled option tooltip', () => { - personalFilesPage.sidenav.openNewMenu() - .then(menu => { - const action = browser.actions().mouseMove(menu.getItemByLabel('Create folder')); - action.perform(); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => personalFilesPage.sidenav.openNewMenu() + .then(menu => { + const action = browser.actions().mouseMove(menu.getItemByLabel('Create folder')); + action.perform(); - return menu; - }) - .then((menu) => { - const tooltip = menu.getItemTooltip('Create folder'); - expect(tooltip).toContain('Create new folder'); - }); + return menu; + }) + .then((menu) => { + const tooltip = menu.getItemTooltip('Create folder'); + expect(tooltip).toContain('Create new folder'); + }) + ); }); it('option is disabled when not enough permissions', () => { @@ -178,107 +182,123 @@ describe('Create folder', () => { }); it('dialog UI elements', () => { - openCreateDialog().then(() => { - const dialogTitle = createDialog.getTitle(); - const isFolderNameDisplayed = createDialog.nameInput.getWebElement().isDisplayed(); - const isDescriptionDisplayed = createDialog.descriptionTextArea.getWebElement().isDisplayed(); - const isCreateEnabled = createDialog.createButton.getWebElement().isEnabled(); - const isCancelEnabled = createDialog.cancelButton.getWebElement().isEnabled(); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => openCreateDialog().then(() => { + const dialogTitle = createDialog.getTitle(); + const isFolderNameDisplayed = createDialog.nameInput.getWebElement().isDisplayed(); + const isDescriptionDisplayed = createDialog.descriptionTextArea.getWebElement().isDisplayed(); + const isCreateEnabled = createDialog.createButton.getWebElement().isEnabled(); + const isCancelEnabled = createDialog.cancelButton.getWebElement().isEnabled(); - expect(dialogTitle).toBe('Create new folder'); - expect(isFolderNameDisplayed).toBe(true, 'Name input is not displayed'); - expect(isDescriptionDisplayed).toBe(true, 'Description field is not displayed'); - expect(isCreateEnabled).toBe(false, 'Create button is not disabled'); - expect(isCancelEnabled).toBe(true, 'Cancel button is not enabled'); - }); + expect(dialogTitle).toBe('Create new folder'); + expect(isFolderNameDisplayed).toBe(true, 'Name input is not displayed'); + expect(isDescriptionDisplayed).toBe(true, 'Description field is not displayed'); + expect(isCreateEnabled).toBe(false, 'Create button is not disabled'); + expect(isCancelEnabled).toBe(true, 'Cancel button is not enabled'); + }) + ); }); it('with empty folder name', () => { - openCreateDialog() - .then(() => { - createDialog.deleteNameWithBackspace(); - }) - .then(() => { - const isCreateEnabled = createDialog.createButton.getWebElement().isEnabled(); - const validationMessage = createDialog.getValidationMessage(); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => openCreateDialog() + .then(() => { + createDialog.deleteNameWithBackspace(); + }) + .then(() => { + const isCreateEnabled = createDialog.createButton.getWebElement().isEnabled(); + const validationMessage = createDialog.getValidationMessage(); - expect(isCreateEnabled).toBe(false, 'Create button is enabled'); - expect(validationMessage).toMatch('Folder name is required'); - }); + expect(isCreateEnabled).toBe(false, 'Create button is enabled'); + expect(validationMessage).toMatch('Folder name is required'); + }) + ); }); it('with folder name ending with a dot "."', () => { - openCreateDialog() - .then(() => createDialog.enterName('folder-name.')) - .then((dialog) => { - const isCreateEnabled = dialog.createButton.getWebElement().isEnabled(); - const validationMessage = dialog.getValidationMessage(); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => openCreateDialog() + .then(() => createDialog.enterName('folder-name.')) + .then((dialog) => { + const isCreateEnabled = dialog.createButton.getWebElement().isEnabled(); + const validationMessage = dialog.getValidationMessage(); - expect(isCreateEnabled).toBe(false, 'Create button is not disabled'); - expect(validationMessage).toMatch(`Folder name can't end with a period .`); - }); + expect(isCreateEnabled).toBe(false, 'Create button is not disabled'); + expect(validationMessage).toMatch(`Folder name can't end with a period .`); + }) + ); }); it('with folder name containing special characters', () => { const namesWithSpecialChars = [ 'a*a', 'a"a', 'aa', `a\\a`, 'a/a', 'a?a', 'a:a', 'a|a' ]; - openCreateDialog() - .then(() => { - namesWithSpecialChars.forEach(name => { - createDialog.enterName(name); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => openCreateDialog() + .then(() => { + namesWithSpecialChars.forEach(name => { + createDialog.enterName(name); - const isCreateEnabled = createDialog.createButton.getWebElement().isEnabled(); - const validationMessage = createDialog.getValidationMessage(); + const isCreateEnabled = createDialog.createButton.getWebElement().isEnabled(); + const validationMessage = createDialog.getValidationMessage(); - expect(isCreateEnabled).toBe(false, 'Create button is not disabled'); - expect(validationMessage).toContain(`Folder name can't contain these characters`); - }); - }); + expect(isCreateEnabled).toBe(false, 'Create button is not disabled'); + expect(validationMessage).toContain(`Folder name can't contain these characters`); + }); + }) + ); }); it('with folder name containing only spaces', () => { - openCreateDialog() - .then(() => createDialog.enterName(' ')) - .then((dialog) => { - const isCreateEnabled = dialog.createButton.getWebElement().isEnabled(); - const validationMessage = dialog.getValidationMessage(); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => openCreateDialog() + .then(() => createDialog.enterName(' ')) + .then((dialog) => { + const isCreateEnabled = dialog.createButton.getWebElement().isEnabled(); + const validationMessage = dialog.getValidationMessage(); - expect(isCreateEnabled).toBe(false, 'Create button is not disabled'); - expect(validationMessage).toMatch(`Folder name can't contain only spaces`); - }); + expect(isCreateEnabled).toBe(false, 'Create button is not disabled'); + expect(validationMessage).toMatch(`Folder name can't contain only spaces`); + }) + ); }); it('cancel folder creation', () => { - openCreateDialog() - .then(() => { - createDialog - .enterName('test') - .enterDescription('test description') - .clickCancel(); - }) - .then(() => expect(createDialog.component.isPresent()).not.toBe(true, 'dialog is not closed')); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => openCreateDialog() + .then(() => { + createDialog + .enterName('test') + .enterDescription('test description') + .clickCancel(); + }) + .then(() => expect(createDialog.component.isPresent()).not.toBe(true, 'dialog is not closed')) + ); }); it('duplicate folder name', () => { - openCreateDialog() - .then(() => createDialog.enterName(duplicateFolderName).clickCreate()) - .then(() => { - personalFilesPage.getSnackBarMessage() - .then(message => { - expect(message).toEqual(`There's already a folder with this name. Try a different name.`); - expect(createDialog.component.isPresent()).toBe(true, 'dialog is not present'); - }); - }); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => openCreateDialog() + .then(() => createDialog.enterName(duplicateFolderName).clickCreate()) + .then(() => { + personalFilesPage.getSnackBarMessage() + .then(message => { + expect(message).toEqual(`There's already a folder with this name. Try a different name.`); + expect(createDialog.component.isPresent()).toBe(true, 'dialog is not present'); + }); + }) + ); }); it('trim ending spaces from folder name', () => { - openCreateDialog() - .then(() => createDialog.enterName(nameWithSpaces).clickCreate()) - .then(() => createDialog.waitForDialogToClose()) - .then(() => dataTable.waitForHeader()) - .then(() => { - const isPresent = dataTable.getRowByContainingText(nameWithSpaces.trim()).isPresent(); - expect(isPresent).toBe(true, 'Folder not displayed in list view'); - }); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => openCreateDialog() + .then(() => createDialog.enterName(nameWithSpaces).clickCreate()) + .then(() => createDialog.waitForDialogToClose()) + .then(() => dataTable.waitForHeader()) + .then(() => { + const isPresent = dataTable.getRowByContainingText(nameWithSpaces.trim()).isPresent(); + expect(isPresent).toBe(true, 'Folder not displayed in list view'); + }) + ); }); }); diff --git a/e2e/suites/actions/edit-folder.test.ts b/e2e/suites/actions/edit-folder.test.ts index 497fd00df..441ba60fa 100644 --- a/e2e/suites/actions/edit-folder.test.ts +++ b/e2e/suites/actions/edit-folder.test.ts @@ -23,9 +23,10 @@ import { CreateOrEditFolderDialog } from '../../components/dialog/create-edit-fo import { Utils } from '../../utilities/utils'; describe('Edit folder', () => { - const username = 'jane.doe'; - const password = 'jane.doe'; + const username = 'john.doe'; + const password = 'john.doe'; + const parent = 'parent-folder'; const folderName = 'my-folder'; const folderDescription = 'my folder description'; @@ -58,11 +59,11 @@ describe('Edit folder', () => { ]) .then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_CONSUMER)) .then(() => Promise.all([ - apis.user.nodes.createNodeWithProperties( folderName, '', folderDescription ), - apis.user.nodes.createFolders([ folderNameToEdit, duplicateFolderName ]), + apis.user.nodes.createNodeWithProperties( folderName, '', folderDescription, parent ), + apis.user.nodes.createFolders([ folderNameToEdit, duplicateFolderName ], parent), loginPage.load() ])) - .then(() => { loginPage.loginWith(username, password); }) + .then(() => loginPage.loginWith(username, password)) .then(done); }); @@ -80,7 +81,7 @@ describe('Edit folder', () => { Promise .all([ apis.admin.sites.deleteSite(siteName, true), - apis.user.nodes.deleteNodes([ folderName, folderNameEdited, duplicateFolderName ]), + apis.user.nodes.deleteNodes([ parent ]), logoutPage.load() .then(() => Utils.clearLocalStorage()) ]) @@ -88,45 +89,51 @@ describe('Edit folder', () => { }); it('button is enabled when having permissions', () => { - dataTable.clickOnRowByContainingText(folderName) - .then(() => { - expect(editButton.isEnabled()).toBe(true); - }); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => dataTable.clickOnRowByContainingText(folderName) + .then(() => { + expect(editButton.isEnabled()).toBe(true); + }) + ); }); it('dialog UI defaults', () => { - dataTable.clickOnRowByContainingText(folderName) - .then(() => editButton.click()) - .then(() => { - expect(editDialog.getTitle()).toBe('Edit folder'); - expect(editDialog.nameInput.getWebElement().getAttribute('value')).toBe(folderName); - expect(editDialog.descriptionTextArea.getWebElement().getAttribute('value')).toBe(folderDescription); - expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(true, 'upload button is not enabled'); - expect(editDialog.cancelButton.getWebElement().isEnabled()).toBe(true, 'cancel button is not enabled'); - }); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => dataTable.clickOnRowByContainingText(folderName) + .then(() => editButton.click()) + .then(() => { + expect(editDialog.getTitle()).toBe('Edit folder'); + expect(editDialog.nameInput.getWebElement().getAttribute('value')).toBe(folderName); + expect(editDialog.descriptionTextArea.getWebElement().getAttribute('value')).toBe(folderDescription); + expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(true, 'upload button is not enabled'); + expect(editDialog.cancelButton.getWebElement().isEnabled()).toBe(true, 'cancel button is not enabled'); + }) + ); }); it('folder properties are modified when pressing OK', () => { - dataTable.clickOnRowByContainingText(folderNameToEdit) - .then(() => editButton.click()) - .then(() => { - editDialog - .enterName(folderNameEdited) - .enterDescription(folderDescriptionEdited) - .clickUpdate(); - }) - .then(() => editDialog.waitForDialogToClose()) - .then(() => dataTable.waitForHeader()) - .then(() => { - const isPresent = dataTable.getRowByContainingText(folderNameEdited).isPresent(); - expect(isPresent).toBe(true, 'Folder not displayed in list view'); - }) - .then(() => { - apis.user.nodes.getNodeDescription(folderNameEdited) - .then((description) => { - expect(description).toEqual(folderDescriptionEdited); - }); - }); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => dataTable.clickOnRowByContainingText(folderNameToEdit) + .then(() => editButton.click()) + .then(() => { + editDialog + .enterName(folderNameEdited) + .enterDescription(folderDescriptionEdited) + .clickUpdate(); + }) + .then(() => editDialog.waitForDialogToClose()) + .then(() => dataTable.waitForHeader()) + .then(() => { + const isPresent = dataTable.getRowByContainingText(folderNameEdited).isPresent(); + expect(isPresent).toBe(true, 'Folder not displayed in list view'); + }) + .then(() => { + apis.user.nodes.getNodeDescription(folderNameEdited) + .then((description) => { + expect(description).toEqual(folderDescriptionEdited); + }); + }) + ); }); it('button is not displayed when not enough permissions', () => { @@ -141,71 +148,85 @@ describe('Edit folder', () => { }); it('with empty folder name', () => { - dataTable.clickOnRowByContainingText(folderName) - .then(() => editButton.click()) - .then(() => { - editDialog.deleteNameWithBackspace(); - }) - .then(() => { - expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(false, 'upload button is not enabled'); - expect(editDialog.getValidationMessage()).toMatch('Folder name is required'); - }); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => dataTable.clickOnRowByContainingText(folderName) + .then(() => editButton.click()) + .then(() => { + editDialog.deleteNameWithBackspace(); + }) + .then(() => { + expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(false, 'upload button is not enabled'); + expect(editDialog.getValidationMessage()).toMatch('Folder name is required'); + }) + ); }); it('with name with special characters', () => { const namesWithSpecialChars = [ 'a*a', 'a"a', 'aa', `a\\a`, 'a/a', 'a?a', 'a:a', 'a|a' ]; - dataTable.clickOnRowByContainingText(folderName) - .then(() => editButton.click()) - .then(() => { - namesWithSpecialChars.forEach(name => { - editDialog.enterName(name); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => dataTable.clickOnRowByContainingText(folderName) + .then(() => editButton.click()) + .then(() => { + namesWithSpecialChars.forEach(name => { + editDialog.enterName(name); - expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(false, 'upload button is not disabled'); - expect(editDialog.getValidationMessage()).toContain(`Folder name can't contain these characters`); - }); - }); + expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(false, 'upload button is not disabled'); + expect(editDialog.getValidationMessage()).toContain(`Folder name can't contain these characters`); + }); + }) + ); }); it('with name ending with a dot', () => { - dataTable.clickOnRowByContainingText(folderName) - .then(() => editButton.click()) - .then(() => editDialog.nameInput.sendKeys('.')) - .then(() => { - expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(false, 'upload button is not enabled'); - expect(editDialog.getValidationMessage()).toMatch(`Folder name can't end with a period .`); - }); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => dataTable.clickOnRowByContainingText(folderName) + .then(() => editButton.click()) + .then(() => editDialog.nameInput.sendKeys('.')) + .then(() => { + expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(false, 'upload button is not enabled'); + expect(editDialog.getValidationMessage()).toMatch(`Folder name can't end with a period .`); + }) + ); }); it('Cancel button', () => { - dataTable.clickOnRowByContainingText(folderName) - .then(() => editButton.click()) - .then(() => editDialog.clickCancel()) - .then(() => { expect(editDialog.component.isPresent()).not.toBe(true, 'dialog is not closed'); }); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => dataTable.clickOnRowByContainingText(folderName) + .then(() => editButton.click()) + .then(() => editDialog.clickCancel()) + .then(() => { + expect(editDialog.component.isPresent()).not.toBe(true, 'dialog is not closed'); + }) + ); }); it('with duplicate folder name', () => { - dataTable.clickOnRowByContainingText(folderName) - .then(() => editButton.click()) - .then(() => editDialog.enterName(duplicateFolderName).clickUpdate()) - .then(() => { - personalFilesPage.getSnackBarMessage() - .then(message => { - expect(message).toEqual(`There's already a folder with this name. Try a different name.`); - expect(editDialog.component.isPresent()).toBe(true, 'dialog is not present'); - }); - }); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => dataTable.clickOnRowByContainingText(folderName) + .then(() => editButton.click()) + .then(() => editDialog.enterName(duplicateFolderName).clickUpdate()) + .then(() => { + personalFilesPage.getSnackBarMessage() + .then(message => { + expect(message).toEqual(`There's already a folder with this name. Try a different name.`); + expect(editDialog.component.isPresent()).toBe(true, 'dialog is not present'); + }); + }) + ); }); it('trim ending spaces', () => { - dataTable.clickOnRowByContainingText(folderName) - .then(() => editButton.click()) - .then(() => editDialog.nameInput.sendKeys(' ')) - .then(() => editDialog.clickUpdate()) - .then(() => editDialog.waitForDialogToClose()) - .then(() => { - expect(personalFilesPage.snackBar.isPresent()).not.toBe(true, 'notification appears'); - expect(dataTable.getRowByContainingText(folderName).isPresent()).toBe(true, 'Folder not displayed in list view'); - }); + personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent) + .then(() => dataTable.clickOnRowByContainingText(folderName) + .then(() => editButton.click()) + .then(() => editDialog.nameInput.sendKeys(' ')) + .then(() => editDialog.clickUpdate()) + .then(() => editDialog.waitForDialogToClose()) + .then(() => { + expect(personalFilesPage.snackBar.isPresent()).not.toBe(true, 'notification appears'); + expect(dataTable.getRowByContainingText(folderName).isPresent()).toBe(true, 'Folder not displayed in list view'); + }) + ); }); }); From 128c6b72844ced4f1a15e1ff0c60ac1aea939300 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Thu, 9 Nov 2017 00:51:54 +0200 Subject: [PATCH 25/27] clear storage and cookies before each login --- e2e/pages/login-page.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/e2e/pages/login-page.ts b/e2e/pages/login-page.ts index 2a6f90f33..d5ca2dc98 100644 --- a/e2e/pages/login-page.ts +++ b/e2e/pages/login-page.ts @@ -40,7 +40,10 @@ export class LoginPage extends Page { const { submitButton } = this.login; const hasSumbitButton = EC.presenceOf(submitButton); - return browser.wait(hasSumbitButton, BROWSER_WAIT_TIMEOUT); + return browser.wait(hasSumbitButton, BROWSER_WAIT_TIMEOUT) + .then(() => browser.executeScript('window.localStorage.clear();')) + .then(() => browser.executeScript('window.sessionStorage.clear();')) + .then(() => browser.driver.manage().deleteAllCookies()); }); } From 91fb346f31f56826cdc4dfc0f34c4fe92e7122f2 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 9 Nov 2017 09:39:32 +0000 Subject: [PATCH 26/27] update nginx settings --- nginx.conf | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nginx.conf b/nginx.conf index e898ca067..ea9434b3d 100644 --- a/nginx.conf +++ b/nginx.conf @@ -19,9 +19,7 @@ http { gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; location / { - # If you want to enable html5Mode(true) in your angularjs app for pretty URL - # then all request for your angularJS app will be through index.html - try_files $uri /index.html; + try_files $uri $uri/ /index.html; } } } From 96ac54bb2b045df6a30082c85dd4acae9bf68c4c Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 10 Nov 2017 09:57:16 +0000 Subject: [PATCH 27/27] split build scripts into dev and prod --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4a455c541..7319ef40a 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "scripts": { "ng": "ng", "start": "ng serve --open", - "build": "ng build --prod", - "build:nts": "ng build", + "build": "ng build", + "build:prod": "ng build --prod", "build:dev": "ng build && node postbuild-dev.js", "test": "ng test", "lint": "ng lint",