From 195284c13aa2028f400f2cdd53862e0b5415a7ab Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 14 Nov 2019 08:15:34 +0200 Subject: [PATCH 01/96] trap focus on drawer when active --- src/app/components/info-drawer/info-drawer.component.html | 6 +++++- src/app/components/info-drawer/info.drawer.module.ts | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/app/components/info-drawer/info-drawer.component.html b/src/app/components/info-drawer/info-drawer.component.html index 8cf1471d7..9a57ca301 100644 --- a/src/app/components/info-drawer/info-drawer.component.html +++ b/src/app/components/info-drawer/info-drawer.component.html @@ -2,7 +2,11 @@ - + Date: Thu, 14 Nov 2019 08:16:24 +0200 Subject: [PATCH 02/96] close panel on Esc keyboard event --- .../info-drawer/info-drawer.component.ts | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/app/components/info-drawer/info-drawer.component.ts b/src/app/components/info-drawer/info-drawer.component.ts index 55c3b80d2..aa22749f2 100644 --- a/src/app/components/info-drawer/info-drawer.component.ts +++ b/src/app/components/info-drawer/info-drawer.component.ts @@ -23,7 +23,14 @@ * along with Alfresco. If not, see . */ -import { Component, Input, OnChanges, OnInit, OnDestroy } from '@angular/core'; +import { + Component, + HostListener, + Input, + OnChanges, + OnInit, + OnDestroy +} from '@angular/core'; import { MinimalNodeEntity, MinimalNodeEntryEntity, @@ -33,7 +40,10 @@ import { ContentApiService } from '@alfresco/aca-shared'; import { AppExtensionService } from '../../extensions/extension.service'; import { SidebarTabRef } from '@alfresco/adf-extensions'; import { Store } from '@ngrx/store'; -import { SetInfoDrawerStateAction } from '@alfresco/aca-shared/store'; +import { + SetInfoDrawerStateAction, + ToggleInfoDrawerAction +} from '@alfresco/aca-shared/store'; @Component({ selector: 'aca-info-drawer', @@ -49,6 +59,10 @@ export class InfoDrawerComponent implements OnChanges, OnInit, OnDestroy { displayNode: MinimalNodeEntryEntity | SiteEntry; tabs: Array = []; + @HostListener('keydown.escape') onEscapeKeyboardEvent() { + this.close(); + } + constructor( private store: Store, private contentApi: ContentApiService, @@ -80,6 +94,10 @@ export class InfoDrawerComponent implements OnChanges, OnInit, OnDestroy { } } + private close() { + this.store.dispatch(new ToggleInfoDrawerAction()); + } + private loadNodeInfo(nodeId: string) { if (nodeId) { this.isLoading = true; From cdcc770e241a2c49e068ad2aa93e13a77c6397d3 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 14 Nov 2019 08:16:40 +0200 Subject: [PATCH 03/96] tests --- .../info-drawer/info-drawer.component.spec.ts | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/app/components/info-drawer/info-drawer.component.spec.ts b/src/app/components/info-drawer/info-drawer.component.spec.ts index 57a442605..09ec936db 100644 --- a/src/app/components/info-drawer/info-drawer.component.spec.ts +++ b/src/app/components/info-drawer/info-drawer.component.spec.ts @@ -26,7 +26,10 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { InfoDrawerComponent } from './info-drawer.component'; import { TestBed, ComponentFixture, async } from '@angular/core/testing'; import { Store } from '@ngrx/store'; -import { SetInfoDrawerStateAction } from '@alfresco/aca-shared/store'; +import { + SetInfoDrawerStateAction, + ToggleInfoDrawerAction +} from '@alfresco/aca-shared/store'; import { AppTestingModule } from '../../testing/app-testing.module'; import { AppExtensionService } from '../../extensions/extension.service'; import { ContentApiService } from '@alfresco/aca-shared'; @@ -159,4 +162,23 @@ describe('InfoDrawerComponent', () => { expect(component.displayNode).toBe(response); expect(contentApiService.getNodeInfo).toHaveBeenCalled(); })); + + it('should dispatch close panel on Esc keyboard event', () => { + const nodeMock = { entry: { id: 'nodeId', aspectNames: [] } }; + component.node = nodeMock; + const event = new KeyboardEvent('keydown', { + code: 'Escape', + key: 'Escape', + keyCode: 27 + } as KeyboardEventInit); + + fixture.detectChanges(); + component.ngOnChanges(); + + fixture.debugElement.nativeElement.dispatchEvent(event); + + expect(storeMock.dispatch).toHaveBeenCalledWith( + new ToggleInfoDrawerAction() + ); + }); }); From 741bca5795967352c12fed596edca870b4f0ff0b Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 14 Nov 2019 10:40:40 +0200 Subject: [PATCH 04/96] trigger event when not input --- src/app/components/info-drawer/info-drawer.component.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app/components/info-drawer/info-drawer.component.ts b/src/app/components/info-drawer/info-drawer.component.ts index aa22749f2..531797b0c 100644 --- a/src/app/components/info-drawer/info-drawer.component.ts +++ b/src/app/components/info-drawer/info-drawer.component.ts @@ -59,8 +59,11 @@ export class InfoDrawerComponent implements OnChanges, OnInit, OnDestroy { displayNode: MinimalNodeEntryEntity | SiteEntry; tabs: Array = []; - @HostListener('keydown.escape') onEscapeKeyboardEvent() { - this.close(); + @HostListener('keydown.escape', ['$event']) + onEscapeKeyboardEvent(event: KeyboardEvent): void { + if ((event.target as HTMLElement).tagName !== 'INPUT') { + this.close(); + } } constructor( From 725073c753c9b465b0d2c50dae34099bff95f2ab Mon Sep 17 00:00:00 2001 From: Martin Muller Date: Tue, 3 Dec 2019 14:39:41 +0100 Subject: [PATCH 05/96] allow other base urls like localhost:8080/workspace (#1273) --- e2e/suites/actions/share-file.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/suites/actions/share-file.test.ts b/e2e/suites/actions/share-file.test.ts index 4f3522d55..cca27189d 100755 --- a/e2e/suites/actions/share-file.test.ts +++ b/e2e/suites/actions/share-file.test.ts @@ -48,7 +48,7 @@ describe('Share a file', () => { const viewer = new Viewer(); const page = new BrowsingPage(); const { dataTable, toolbar } = page; - const shareLinkPreUrl = "/#/preview/s/"; + const shareLinkPreUrl = `${browser.baseUrl}/#/preview/s/`; const apis = { admin: new RepoClient(), From 3221caea870c09145148765b77e09f67896b405f Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 5 Dec 2019 12:02:04 +0200 Subject: [PATCH 06/96] adf update 3.7.0-5c1aff (#1274) * adf dep update * fix ACA-2175 TODO * remove workarounds --- .../files-folders/test-data-files-folders.ts | 7 +- .../other-permissions.test.ts | 9 +- .../test-data-permissions.ts | 6 +- e2e/suites/actions/share-file.test.ts | 6 +- e2e/suites/actions/unshare-file.test.ts | 20 +-- package-lock.json | 164 +++++++++--------- package.json | 8 +- 7 files changed, 101 insertions(+), 119 deletions(-) diff --git a/e2e/suites/actions-available/files-folders/test-data-files-folders.ts b/e2e/suites/actions-available/files-folders/test-data-files-folders.ts index c2c24971e..be7bf471a 100644 --- a/e2e/suites/actions-available/files-folders/test-data-files-folders.ts +++ b/e2e/suites/actions-available/files-folders/test-data-files-folders.ts @@ -65,11 +65,9 @@ const viewerLockedToolbarMore = ['Cancel Editing', 'Upload New Version', 'Favori // ---- FAVORITES workarounds ---- // TODO: add Edit Offline when ACA-2174 is fixed -// TODO: change 'Share' into 'Shared Link Settings' when ACA-2175 is done // TODO: investigate why 'Edit in Microsoft Office™' and 'Permissions' are not displayed and raise issue -// TODO: change 'Share' into 'Shared Link Settings' when ACA-2175 is done -const favoritesSharedToolbarPrimary = ['Share', 'Download', 'View', 'View Details', 'More Actions']; +const favoritesSharedToolbarPrimary = ['Shared Link Settings', 'Download', 'View', 'View Details', 'More Actions']; // TODO: add Edit Offline when ACA-2174 is fixed // TODO: investigate why 'Edit in Microsoft Office™' and 'Permissions' are not displayed and raise issue const favoritesContextMenu = ['Share', 'Download', 'View', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; @@ -78,8 +76,7 @@ const favoritesContextMenu = ['Share', 'Download', 'View', 'Upload New Version', const favoritesToolbarMore = ['Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; // TODO: add Edit Offline when ACA-2174 is fixed // TODO: investigate why 'Edit in Microsoft Office™' and 'Permissions' are not displayed and raise issue -// TODO: change 'Share' into 'Shared Link Settings' when ACA-2175 is done -const favoritesSharedContextMenu = ['Share', 'Download', 'View', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; +const favoritesSharedContextMenu = ['Shared Link Settings', 'Download', 'View', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; // ---- SEARCH workarounds ---- diff --git a/e2e/suites/actions-available/special-permissions/other-permissions.test.ts b/e2e/suites/actions-available/special-permissions/other-permissions.test.ts index 7a7af0e99..b7b63f6fa 100755 --- a/e2e/suites/actions-available/special-permissions/other-permissions.test.ts +++ b/e2e/suites/actions-available/special-permissions/other-permissions.test.ts @@ -183,8 +183,7 @@ describe('', () => { expect(await toolbar.isDownloadPresent()).toBe(true, `Download is not displayed for ${file1}`); expect(await toolbar.isViewDetailsPresent()).toBe(true, `View details is not displayed for ${file1}`); expect(await toolbar.isEditFolderPresent()).toBe(false, `Edit folder is displayed for ${file1}`); - // TODO: replace with isSharedLinkSettingsPresent when ACA-2175 is done - expect(await toolbar.isSharePresent()).toBe(true, `Share is not displayed`); + expect(await toolbar.isSharedLinkSettingsPresent()).toBe(true, `Shared Link Settings is not displayed`); await toolbar.openMoreMenu(); @@ -422,8 +421,7 @@ describe('', () => { expect(await toolbar.isDownloadPresent()).toBe(true, `Download is not displayed for ${fileLocked}`); expect(await toolbar.isViewDetailsPresent()).toBe(true, `View details is not displayed for ${fileLocked}`); expect(await toolbar.isEditFolderPresent()).toBe(false, `Edit folder is displayed for ${fileLocked}`); - // TODO: replace with isSharedLinkSettingsPresent when ACA-2175 is done - expect(await toolbar.isSharePresent()).toBe(true, `Share is not displayed`); + expect(await toolbar.isSharedLinkSettingsPresent()).toBe(true, `Shared Link Settings is not displayed`); await toolbar.openMoreMenu(); @@ -663,8 +661,7 @@ describe('', () => { expect(await toolbar.isDownloadPresent()).toBe(true, `Download is not displayed for ${fileLocked}`); expect(await toolbar.isViewDetailsPresent()).toBe(true, `View details is not displayed for ${fileLocked}`); expect(await toolbar.isEditFolderPresent()).toBe(false, `Edit folder is displayed for ${fileLocked}`); - // TODO: replace with isSharedLinkSettingsPresent when ACA-2175 is done - expect(await toolbar.isSharePresent()).toBe(true, `Share is not displayed`); + expect(await toolbar.isSharedLinkSettingsPresent()).toBe(true, `Shared Link Settings is not displayed`); await toolbar.openMoreMenu(); diff --git a/e2e/suites/actions-available/special-permissions/test-data-permissions.ts b/e2e/suites/actions-available/special-permissions/test-data-permissions.ts index 58c8cb8e7..881229767 100644 --- a/e2e/suites/actions-available/special-permissions/test-data-permissions.ts +++ b/e2e/suites/actions-available/special-permissions/test-data-permissions.ts @@ -59,10 +59,8 @@ const favoritesConsumerToolbarMore = ['Upload New Version', 'Remove Favorite', ' const favoritesConsumerContextMenu = ['Share', 'Download', 'View', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; // TODO: remove 'Move' and 'Delete' when ACA-1737 is done // TODO: remove 'Upload New Version' when ACA-2175 is done -// TODO: change 'Share' into 'Shared Link Settings' when ACA-2175 is done -const favoritesConsumerSharedContextMenu = ['Share', 'Download', 'View', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; -// TODO: change 'Share' into 'Shared Link Settings' when ACA-2175 is done -const favoritesConsumerSharedToolbarPrimary = ['Share', 'Download', 'View', 'View Details', 'More Actions']; +const favoritesConsumerSharedContextMenu = ['Shared Link Settings', 'Download', 'View', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; +const favoritesConsumerSharedToolbarPrimary = ['Shared Link Settings', 'Download', 'View', 'View Details', 'More Actions']; // ---- SHARED FILES workaround ---- diff --git a/e2e/suites/actions/share-file.test.ts b/e2e/suites/actions/share-file.test.ts index cca27189d..918dc095b 100755 --- a/e2e/suites/actions/share-file.test.ts +++ b/e2e/suites/actions/share-file.test.ts @@ -924,7 +924,7 @@ describe('Share a file', () => { it('Expire date is displayed correctly - [C286671]', async () => { await dataTable.selectItem(file6); - await toolbar.clickShare(); + await toolbar.clickSharedLinkSettings(); await shareDialog.waitForDialogToOpen(); const expireProperty = await apis.user.nodes.getSharedExpiryDate(file6Id); @@ -935,7 +935,7 @@ describe('Share a file', () => { it('Disable the share link expiration - [C286672]', async () => { await dataTable.selectItem(file7); - await toolbar.clickShare(); + await toolbar.clickSharedLinkSettings(); await shareDialog.waitForDialogToOpen(); expect(await shareDialog.isExpireToggleEnabled()).toBe(true, 'Expiration is not checked'); @@ -959,7 +959,7 @@ describe('Share a file', () => { await page.dataTable.clearSelection(); await dataTable.selectItem(file8); - await toolbar.clickShare(); + await toolbar.clickSharedLinkSettings(); await shareDialog.waitForDialogToOpen(); const url2 = await shareDialog.getLinkUrl(); diff --git a/e2e/suites/actions/unshare-file.test.ts b/e2e/suites/actions/unshare-file.test.ts index e3b802962..34d21349e 100755 --- a/e2e/suites/actions/unshare-file.test.ts +++ b/e2e/suites/actions/unshare-file.test.ts @@ -579,9 +579,7 @@ describe('Unshare a file', () => { it('Unshare dialog UI - [C286694]', async () => { await dataTable.selectItem(file1); - // TODO: remove workaround for favorites - // await toolbar.clickSharedLinkSettings(); - await toolbar.clickShare(); + await toolbar.clickSharedLinkSettings(); await shareDialog.waitForDialogToOpen(); expect(await shareDialog.isShareToggleChecked()).toBe(true, 'Share toggle not checked'); @@ -596,9 +594,7 @@ describe('Unshare a file', () => { it('Unshare a file - [C286695]', async () => { await dataTable.selectItem(file2); - // TODO: remove workaround for favorites - // await toolbar.clickSharedLinkSettings(); - await toolbar.clickShare(); + await toolbar.clickSharedLinkSettings(); await shareDialog.waitForDialogToOpen(); const url = await shareDialog.getLinkUrl(); await shareDialog.clickShareToggle(); @@ -618,9 +614,7 @@ describe('Unshare a file', () => { it('Cancel the Unshare action - [C286696]', async () => { await dataTable.selectItem(file3); - // TODO: remove workaround for favorites - // await toolbar.clickSharedLinkSettings(); - await toolbar.clickShare(); + await toolbar.clickSharedLinkSettings(); await shareDialog.waitForDialogToOpen(); const urlBefore = await shareDialog.getLinkUrl(); @@ -780,9 +774,7 @@ describe('Unshare a file', () => { it('on Favorites - file shared by other user - [C286697]', async () => { await page.clickFavoritesAndWait(); await dataTable.selectItem(file1Fav); - // TODO: remove workaround for favorites - // await toolbar.clickSharedLinkSettings(); - await toolbar.clickShare(); + await toolbar.clickSharedLinkSettings(); await shareDialog.waitForDialogToOpen(); expect(await shareDialog.isShareToggleDisabled()).toBe(false, 'Share toggle disabled for consumer'); @@ -797,9 +789,7 @@ describe('Unshare a file', () => { it('on Favorites - file shared by the user - [C286703]', async () => { await page.clickFavoritesAndWait(); await dataTable.selectItem(file2Fav); - // TODO: remove workaround for favorites - // await toolbar.clickSharedLinkSettings(); - await toolbar.clickShare(); + await toolbar.clickSharedLinkSettings(); await shareDialog.waitForDialogToOpen(); expect(await shareDialog.isShareToggleDisabled()).toBe(false, 'Share toggle disabled for consumer'); diff --git a/package-lock.json b/package-lock.json index 8340f2ff3..16444dc6d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,33 +5,33 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-3.6.0.tgz", - "integrity": "sha512-npEPJ4eAIalIWd4lmTltYiS3XyLdagzfqDUfC9oHwFz8QfX7y8mUtaSDBVYqTGRm3lZ7vElczfsbuKlknLaxog==", + "version": "3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57.tgz", + "integrity": "sha512-F1ccqy3tz5G4n54EzEWo6DA2CrZU/hrqmS21QfkyHq3ytChJCqQjAf99L8MG6sIdmHKoLwoofREkS8p8q0K3PA==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/adf-core": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-3.6.0.tgz", - "integrity": "sha512-WlYvxuBpJ6sug5iPfJprdWDZcDtJ7Y6/SFzEchEhan30O4Efb/MgWY+3s1nCsIwX0eYhyv8pj9NHQjHNjPotLw==", + "version": "3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57.tgz", + "integrity": "sha512-HT1bdNflN3QF/toRnHxpg/4ioGvPfdApFc9ov4odER5Tu8Jx9BJVUBExUnkyKQKMP/KPew/ct9z+qFgHDctVRg==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/adf-extensions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-3.6.0.tgz", - "integrity": "sha512-/B2+TKrjQswXsTkkuU7qgK9Ud8Wn02bZRgRuKZiPwUxIo8s4wSMZpgWkfrIw58WDNDiL/MDgDeNiCrpxxrzdow==", + "version": "3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57", + "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57.tgz", + "integrity": "sha512-4t0laDE57FnPXgwaR82AAuScxsjBCNSUHCQL2LA9JLQ5LdlxaIQTGr/7ZaMmA1D67UD+frL1GkSThu815jvoFA==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/js-api": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-3.6.0.tgz", - "integrity": "sha512-aXc4twC3jDTZqyyhrlQX5DvyuSAnsfmZ7LT03itm/II9EqFEHcpXGWzyOA2VyZSyfuYz5e13KuM6v1VqBZxCwQ==", + "version": "3.7.0-c48ced828e07de899beecb005cd7c4dc1668f64c", + "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-3.7.0-c48ced828e07de899beecb005cd7c4dc1668f64c.tgz", + "integrity": "sha512-DGNjyhCexaIkyTMZKqKTCRZpdOHcANuo8Qins0XVxoSD7BGP35cp0FXCM7BiCrxFRShoZ1LKG94+CJl6rTxoGg==", "requires": { "event-emitter": "^0.3.5", "minimatch": "3.0.4", @@ -262,7 +262,7 @@ "dependencies": { "source-map": { "version": "0.5.6", - "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", "dev": true } @@ -592,7 +592,7 @@ }, "load-json-file": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { @@ -639,7 +639,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, @@ -1263,7 +1263,7 @@ }, "@types/q": { "version": "0.0.32", - "resolved": "http://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", "dev": true }, @@ -1876,7 +1876,7 @@ }, "util": { "version": "0.10.3", - "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -1980,7 +1980,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -2417,7 +2417,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -2454,7 +2454,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { @@ -2583,7 +2583,7 @@ }, "cacache": { "version": "10.0.4", - "resolved": "http://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", "dev": true, "requires": { @@ -2657,7 +2657,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { @@ -2966,7 +2966,7 @@ }, "colors": { "version": "1.1.2", - "resolved": "http://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", "dev": true }, @@ -3323,7 +3323,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -3336,7 +3336,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -3854,7 +3854,7 @@ "dependencies": { "globby": { "version": "6.1.0", - "resolved": "http://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { @@ -3867,7 +3867,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -3943,7 +3943,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { @@ -4136,7 +4136,7 @@ }, "engine.io-client": { "version": "3.2.1", - "resolved": "http://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", "dev": true, "requires": { @@ -4252,7 +4252,7 @@ }, "es6-promisify": { "version": "5.0.0", - "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "dev": true, "requires": { @@ -4514,7 +4514,7 @@ }, "array-flatten": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", "dev": true }, @@ -4655,9 +4655,9 @@ } }, "ext": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.2.1.tgz", - "integrity": "sha512-x+OKKC57tNiLhDW26UmWtvQBpvO+2wxdC/A0jP7RkmjAc4gze9/U98hQyIYJUzo9A+o9ntMHpC+LH3pWMSbrVQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", "requires": { "type": "^2.0.0" }, @@ -5122,7 +5122,7 @@ }, "fs-access": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", "dev": true, "requires": { @@ -5795,7 +5795,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, @@ -5891,7 +5891,7 @@ }, "got": { "version": "6.7.1", - "resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "dev": true, "requires": { @@ -6168,7 +6168,7 @@ }, "http-proxy-middleware": { "version": "0.18.0", - "resolved": "http://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz", "integrity": "sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==", "dev": true, "requires": { @@ -6791,7 +6791,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -6850,7 +6850,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -6976,7 +6976,7 @@ }, "is-obj": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, @@ -7217,7 +7217,7 @@ }, "fast-deep-equal": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", "dev": true }, @@ -7470,7 +7470,7 @@ }, "jsesc": { "version": "1.3.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", "dev": true }, @@ -7661,7 +7661,7 @@ }, "karma-cli": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/karma-cli/-/karma-cli-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/karma-cli/-/karma-cli-1.0.1.tgz", "integrity": "sha1-rmw8WKMTodALRRZMRVubhs4X+WA=", "dev": true, "requires": { @@ -7686,7 +7686,7 @@ }, "karma-jasmine-html-reporter": { "version": "0.2.2", - "resolved": "http://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-0.2.2.tgz", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-0.2.2.tgz", "integrity": "sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw=", "dev": true, "requires": { @@ -7790,7 +7790,7 @@ "dependencies": { "promise": { "version": "7.0.4", - "resolved": "http://registry.npmjs.org/promise/-/promise-7.0.4.tgz", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.0.4.tgz", "integrity": "sha1-Nj6EpMNsg1a4kP7WLJHOhdAu1Tk=", "dev": true, "requires": { @@ -8014,7 +8014,7 @@ }, "supports-color": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } @@ -8034,7 +8034,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -8047,7 +8047,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -8393,7 +8393,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, @@ -8428,7 +8428,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { @@ -8653,7 +8653,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -8945,7 +8945,7 @@ "dependencies": { "semver": { "version": "5.3.0", - "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", "dev": true } @@ -9032,7 +9032,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -9391,13 +9391,13 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, "os-locale": { "version": "1.4.0", - "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { @@ -9406,7 +9406,7 @@ }, "os-tmpdir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, @@ -9711,7 +9711,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, @@ -10055,7 +10055,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -10369,7 +10369,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -10399,7 +10399,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -10438,7 +10438,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -10510,7 +10510,7 @@ }, "regexpu-core": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", "dev": true, "requires": { @@ -10540,13 +10540,13 @@ }, "regjsgen": { "version": "0.2.0", - "resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", "dev": true }, "regjsparser": { "version": "0.1.5", - "resolved": "http://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", "dev": true, "requires": { @@ -10555,7 +10555,7 @@ "dependencies": { "jsesc": { "version": "0.5.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true } @@ -10914,7 +10914,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { @@ -10964,7 +10964,7 @@ }, "sax": { "version": "0.5.8", - "resolved": "http://registry.npmjs.org/sax/-/sax-0.5.8.tgz", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=", "dev": true }, @@ -10995,7 +10995,7 @@ "dependencies": { "source-map": { "version": "0.4.4", - "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { @@ -11253,7 +11253,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -11340,7 +11340,7 @@ }, "slice-ansi": { "version": "0.0.4", - "resolved": "http://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", "dev": true }, @@ -11556,7 +11556,7 @@ }, "socket.io-parser": { "version": "3.2.0", - "resolved": "http://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", "dev": true, "requires": { @@ -11820,7 +11820,7 @@ }, "sprintf-js": { "version": "1.0.3", - "resolved": "http://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, @@ -11961,7 +11961,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -11972,7 +11972,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -11991,7 +11991,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -12009,7 +12009,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, @@ -12081,7 +12081,7 @@ }, "source-map": { "version": "0.1.43", - "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", "dev": true, "requires": { @@ -12408,7 +12408,7 @@ }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -12672,7 +12672,7 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, @@ -13232,7 +13232,7 @@ }, "source-map": { "version": "0.4.4", - "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { @@ -13714,7 +13714,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { diff --git a/package.json b/package.json index 78c457248..ddfff6a33 100644 --- a/package.json +++ b/package.json @@ -36,10 +36,10 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "3.6.0", - "@alfresco/adf-core": "3.6.0", - "@alfresco/adf-extensions": "3.6.0", - "@alfresco/js-api": "3.6.0", + "@alfresco/adf-content-services": "3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57", + "@alfresco/adf-core": "3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57", + "@alfresco/adf-extensions": "3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57", + "@alfresco/js-api": "3.7.0-c48ced828e07de899beecb005cd7c4dc1668f64c", "@angular/animations": "7.2.15", "@angular/cdk": "^7.3.7", "@angular/common": "7.2.15", From 4c840036beb554022770f8ff9f2634cfcd0446d0 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 5 Dec 2019 13:35:24 +0200 Subject: [PATCH 07/96] remove tag name check --- src/app/components/info-drawer/info-drawer.component.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app/components/info-drawer/info-drawer.component.ts b/src/app/components/info-drawer/info-drawer.component.ts index 5d409e1c2..9d514a943 100644 --- a/src/app/components/info-drawer/info-drawer.component.ts +++ b/src/app/components/info-drawer/info-drawer.component.ts @@ -61,9 +61,7 @@ export class InfoDrawerComponent implements OnChanges, OnInit, OnDestroy { @HostListener('keydown.escape', ['$event']) onEscapeKeyboardEvent(event: KeyboardEvent): void { - if ((event.target as HTMLElement).tagName !== 'INPUT') { - this.close(); - } + this.close(); } constructor( From ab527d7f231a7237846af6047b1c9821b5b10f25 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 5 Dec 2019 14:14:12 +0200 Subject: [PATCH 08/96] fix test --- src/app/components/info-drawer/info-drawer.component.spec.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/app/components/info-drawer/info-drawer.component.spec.ts b/src/app/components/info-drawer/info-drawer.component.spec.ts index 2ec81d549..702e0b768 100644 --- a/src/app/components/info-drawer/info-drawer.component.spec.ts +++ b/src/app/components/info-drawer/info-drawer.component.spec.ts @@ -152,8 +152,6 @@ describe('InfoDrawerComponent', () => { })); it('should dispatch close panel on Esc keyboard event', () => { - const nodeMock = { entry: { id: 'nodeId', aspectNames: [] } }; - component.node = nodeMock; const event = new KeyboardEvent('keydown', { code: 'Escape', key: 'Escape', @@ -161,7 +159,6 @@ describe('InfoDrawerComponent', () => { } as KeyboardEventInit); fixture.detectChanges(); - component.ngOnChanges(); fixture.debugElement.nativeElement.dispatchEvent(event); From 744b14bbd9fdc67aa41389980d6216051a29cc8d Mon Sep 17 00:00:00 2001 From: pionnegru Date: Fri, 6 Dec 2019 08:39:51 +0200 Subject: [PATCH 09/96] add ajv-cli --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index ddfff6a33..e8e2fc205 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "@types/jasminewd2": "^2.0.2", "@types/node": "9.3.0", "@types/selenium-webdriver": "^3.0.8", + "ajv-cli": "^3.0.0", "adf-tslint-rules": "0.0.7", "chrome-remote-interface": "^0.26.1", "codelyzer": "^4.5.0", From d75ca3b41e5a845288a160be0ecdd6b30daf2a4e Mon Sep 17 00:00:00 2001 From: pionnegru Date: Fri, 6 Dec 2019 08:40:22 +0200 Subject: [PATCH 10/96] add validation script --- package.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e8e2fc205..bbeea35af 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,13 @@ "license": "LGPL-3.0", "scripts": { "ng": "ng", - "start": "npm run build.shared && npm run build.extensions && ng serve --open", - "start:prod": "node --max-old-space-size=8192 node_modules/@angular/cli/bin/ng serve --prod --open", + "start": "npm run validate-config && npm run build.shared && npm run build.extensions && ng serve --open", + "start:prod": "npm run validate-config && node --max-old-space-size=8192 node_modules/@angular/cli/bin/ng serve --prod --open", "build:aos-extension": "npx rimraf dist/@alfresco/adf-office-services-ext && ng build adf-office-services-ext && cpr projects/adf-office-services-ext/ngi.json dist/@alfresco/adf-office-services-ext/ngi.json && cpr projects/adf-office-services-ext/assets dist/@alfresco/adf-office-services-ext/assets", "build.shared": "ng build aca-shared", "build.extensions": "npm run build:aos-extension", "build.app": "node --max-old-space-size=8192 node_modules/@angular/cli/bin/ng build app", - "build": "npm run build.shared && npm run build.extensions && npm run build.app -- --prod", + "build": "npm run validate-config && npm run build.shared && npm run build.extensions && npm run build.app -- --prod", "build.e2e": "npm run build.shared && npm run build.extensions && npm run build.app -- --prod --configuration=e2e", "test": "ng test app --code-coverage", "test:ci": "npm run build.shared && npm run build.extensions && ng test adf-office-services-ext --watch=false && ng test app --code-coverage --watch=false", @@ -27,12 +27,13 @@ "inspect.bundle": "ng build app --prod --stats-json && npx webpack-bundle-analyzer dist/app/stats.json", "format:check": "prettier --check \"src/{app,environments}/**/*.{ts,js,css,scss,html}\"", "format:fix": "prettier --write \"src/{app,environments}/**/*.{ts,js,css,scss,html}\"", - "build.tomcat": "npm run build.shared && npm run build.extensions && npm run build.app -- --prod --base-href ./ && jar -cvf docker/tomcat/artifacts/content-app.war -C dist/app/ .", + "build.tomcat": "npm run validate-config && npm run build.shared && npm run build.extensions && npm run build.app -- --prod --base-href ./ && jar -cvf docker/tomcat/artifacts/content-app.war -C dist/app/ .", "build.tomcat.e2e": "./build-tomcat-e2e.sh", "e2e.tomcat": "npm run wd:update && protractor --baseUrl=http://localhost:8080/content-app/ $SUITE", "docker.tomcat.start": "cd docker/tomcat && docker-compose up -d --build && npm run wait:app", "docker.tomcat.stop": "cd docker/tomcat && docker-compose stop", - "docker.tomcat.e2e": "npm run docker.tomcat.start && npm run e2e.tomcat" + "docker.tomcat.e2e": "npm run docker.tomcat.start && npm run e2e.tomcat", + "validate-config": "ajv validate -s ./node_modules/@alfresco/adf-core/app.config.schema.json -d ./src/app.config.json --errors=text --verbose" }, "private": true, "dependencies": { From 9d787669a9a63babe70c1015fe6b8923a25f79ee Mon Sep 17 00:00:00 2001 From: pionnegru Date: Fri, 6 Dec 2019 08:40:49 +0200 Subject: [PATCH 11/96] add schema reference and fixes --- src/app.config.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/app.config.json b/src/app.config.json index 2b0259620..e3a799564 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -1,4 +1,5 @@ { + "$schema": "../node_modules/@alfresco/adf-core/app.config.schema.json", "ecmHost": "{protocol}//{hostname}{:port}", "aosHost": "{protocol}//{hostname}{:port}/alfresco/aos", "baseShareUrl": "{protocol}//{hostname}{:port}/#/preview/s", @@ -279,18 +280,22 @@ "expanded": true, "fields": [ { + "mincount": 1, "field": "content.mimetype", "label": "SEARCH.FACET_FIELDS.FILE_TYPE" }, { + "mincount": 1, "field": "creator", "label": "SEARCH.FACET_FIELDS.CREATOR" }, { + "mincount": 1, "field": "modifier", "label": "SEARCH.FACET_FIELDS.MODIFIER" }, { + "mincount": 1, "field": "SITE", "label": "SEARCH.FACET_FIELDS.LOCATION" } From b26794f52be8e667b3d7de5a9d1e0955ccbd220e Mon Sep 17 00:00:00 2001 From: pionnegru Date: Fri, 6 Dec 2019 09:00:40 +0200 Subject: [PATCH 12/96] add package-lock --- package-lock.json | 140 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/package-lock.json b/package-lock.json index 16444dc6d..25c4ce73e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1615,6 +1615,20 @@ "uri-js": "^4.2.2" } }, + "ajv-cli": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ajv-cli/-/ajv-cli-3.0.0.tgz", + "integrity": "sha1-WCMjH2TigzBUEwaQsYCZYJ6YDyk=", + "dev": true, + "requires": { + "ajv": "^6.0.0", + "ajv-pack": "^0.3.0", + "fast-json-patch": "^0.5.6", + "glob": "^7.0.3", + "json-schema-migrate": "^0.2.0", + "minimist": "^1.2.0" + } + }, "ajv-errors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", @@ -1626,6 +1640,24 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.3.0.tgz", "integrity": "sha512-CMzN9S62ZOO4sA/mJZIO4S++ZM7KFWzH3PPWkveLhy4OZ9i1/VatgwWMD46w/XbGCBy7Ye0gCk+Za6mmyfKK7g==" }, + "ajv-pack": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/ajv-pack/-/ajv-pack-0.3.1.tgz", + "integrity": "sha1-tyxNQhnjko5ihC10Le2Tv1B5ZWA=", + "dev": true, + "requires": { + "js-beautify": "^1.6.4", + "require-from-string": "^1.2.0" + }, + "dependencies": { + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", + "dev": true + } + } + }, "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", @@ -3088,6 +3120,16 @@ "typedarray": "^0.0.6" } }, + "config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "configstore": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz", @@ -4041,6 +4083,26 @@ "safer-buffer": "^2.1.0" } }, + "editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4822,6 +4884,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, + "fast-json-patch": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-0.5.7.tgz", + "integrity": "sha1-taj0nSWWJFlu+YuHLz/aiVtNhmU=", + "dev": true + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -7432,6 +7500,31 @@ "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==", "dev": true }, + "js-beautify": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.10.2.tgz", + "integrity": "sha512-ZtBYyNUYJIsBWERnQP0rPN9KjkrDfJcMjuVGcvXOUJrD1zmOGwhRwQ4msG+HJ+Ni/FA7+sRQEMYVzdTQDvnzvQ==", + "dev": true, + "requires": { + "config-chain": "^1.1.12", + "editorconfig": "^0.15.3", + "glob": "^7.1.3", + "mkdirp": "~0.5.1", + "nopt": "~4.0.1" + }, + "dependencies": { + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + } + } + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -7495,6 +7588,41 @@ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "dev": true }, + "json-schema-migrate": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json-schema-migrate/-/json-schema-migrate-0.2.0.tgz", + "integrity": "sha1-ukelsAcvxyOWRg4b1gtE1SF4u8Y=", + "dev": true, + "requires": { + "ajv": "^5.0.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + } + } + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -10015,6 +10143,12 @@ "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==", "dev": true }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, "protoduck": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", @@ -11306,6 +11440,12 @@ "rechoir": "^0.6.2" } }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", From 55fe3f8399bfbf906a3400b2486eafb2bddc2dcb Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 12 Dec 2019 10:11:18 +0200 Subject: [PATCH 13/96] templates actions --- .../store/src/actions/template.actions.ts | 36 +++++++++++++++++++ projects/aca-shared/store/src/public_api.ts | 1 + 2 files changed, 37 insertions(+) create mode 100644 projects/aca-shared/store/src/actions/template.actions.ts diff --git a/projects/aca-shared/store/src/actions/template.actions.ts b/projects/aca-shared/store/src/actions/template.actions.ts new file mode 100644 index 000000000..ba6f9d172 --- /dev/null +++ b/projects/aca-shared/store/src/actions/template.actions.ts @@ -0,0 +1,36 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Action } from '@ngrx/store'; + +export enum TemplateActionTypes { + CreateFileFromTemplate = 'CREATE_FILE_FROM_TEMPLATE' +} + +export class CreateFileFromTemplate implements Action { + readonly type = TemplateActionTypes.CreateFileFromTemplate; + + constructor() {} +} diff --git a/projects/aca-shared/store/src/public_api.ts b/projects/aca-shared/store/src/public_api.ts index c7695c5b9..c35d08eab 100644 --- a/projects/aca-shared/store/src/public_api.ts +++ b/projects/aca-shared/store/src/public_api.ts @@ -32,6 +32,7 @@ export * from './actions/snackbar.actions'; export * from './actions/upload.actions'; export * from './actions/viewer.actions'; export * from './actions/metadata-aspect.actions'; +export * from './actions/template.actions'; export * from './effects/dialog.effects'; export * from './effects/router.effects'; From 2e2f015a418adce2d83f8d5dfbbb48b233b64f77 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 12 Dec 2019 10:11:38 +0200 Subject: [PATCH 14/96] update docs --- docs/extending/application-actions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/extending/application-actions.md b/docs/extending/application-actions.md index cd48959b2..77083e036 100644 --- a/docs/extending/application-actions.md +++ b/docs/extending/application-actions.md @@ -124,3 +124,4 @@ Below is the list of public actions types you can use in the plugin definitions | 1.8.0 | VIEW_NODE | NodeId<`string`> , [ViewNodeExtras](../features/file-viewer.md#details)<`any`> | Lightweight preview of a node by id. Can be invoked from extensions. For details also see [File Viewer](../features/file-viewer.md#details) | | 1.8.0 | CLOSE_PREVIEW | n/a | Closes the viewer ( preview of the item ) | | 1.9.0 | RESET_SELECTION | n/a | Resets active document list selection | +| 2.0.0 | CREATE_FILE_FROM_TEMPLATE | n/a | Invoke a dialog listing `Node Templates` folder. Selected template can be copied in the current folder from where tha action was invoked | From dd6a61e9f149b807aacf5a54e539743fdc04f3d7 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 12 Dec 2019 10:12:47 +0200 Subject: [PATCH 15/96] file from template effect --- src/app/store/app-store.module.ts | 6 +- src/app/store/effects.ts | 1 + src/app/store/effects/template.effects.ts | 87 +++++++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/app/store/effects/template.effects.ts diff --git a/src/app/store/app-store.module.ts b/src/app/store/app-store.module.ts index 4ea9aae32..bd71d2f60 100644 --- a/src/app/store/app-store.module.ts +++ b/src/app/store/app-store.module.ts @@ -39,7 +39,8 @@ import { SearchEffects, LibraryEffects, UploadEffects, - FavoriteEffects + FavoriteEffects, + TemplateEffects } from './effects'; import { INITIAL_STATE } from './initial-state'; @@ -56,7 +57,8 @@ import { INITIAL_STATE } from './initial-state'; SearchEffects, LibraryEffects, UploadEffects, - FavoriteEffects + FavoriteEffects, + TemplateEffects ]), !environment.production ? StoreDevtoolsModule.instrument({ maxAge: 25 }) diff --git a/src/app/store/effects.ts b/src/app/store/effects.ts index 29bee5773..4a7b28ca2 100644 --- a/src/app/store/effects.ts +++ b/src/app/store/effects.ts @@ -32,3 +32,4 @@ export * from './effects/search.effects'; export * from './effects/library.effects'; export * from './effects/upload.effects'; export * from './effects/upload.effects'; +export * from './effects/template.effects'; diff --git a/src/app/store/effects/template.effects.ts b/src/app/store/effects/template.effects.ts new file mode 100644 index 000000000..9ae79a2e1 --- /dev/null +++ b/src/app/store/effects/template.effects.ts @@ -0,0 +1,87 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Effect, Actions, ofType } from '@ngrx/effects'; +import { Injectable } from '@angular/core'; +import { map, withLatestFrom, switchMap, catchError } from 'rxjs/operators'; +import { Store } from '@ngrx/store'; +import { + CreateFileFromTemplate, + TemplateActionTypes, + getCurrentFolder, + AppStore, + SnackbarErrorAction +} from '@alfresco/aca-shared/store'; +import { CreateFileFromTemplateService } from '../../services/create-file-from-template.service'; +import { AlfrescoApiService } from '@alfresco/adf-core'; +import { ContentManagementService } from '../../services/content-management.service'; +import { from, of } from 'rxjs'; +import { NodeEntry } from '@alfresco/js-api'; + +@Injectable() +export class TemplateEffects { + constructor( + private content: ContentManagementService, + private store: Store, + private apiService: AlfrescoApiService, + private actions$: Actions, + private createFileFromTemplateService: CreateFileFromTemplateService + ) {} + + @Effect({ dispatch: false }) + fileFromTemplate$ = this.actions$.pipe( + ofType(TemplateActionTypes.CreateFileFromTemplate), + map(() => { + this.createFileFromTemplateService + .openTemplatesDialog() + .pipe( + withLatestFrom(this.store.select(getCurrentFolder)), + switchMap(([[template], parentNode]) => { + return from( + this.apiService + .getInstance() + .nodes.copyNode(template.id, { targetParentId: parentNode.id }) + ); + }), + catchError(error => { + const { statusCode } = JSON.parse(error.message).error; + + if (statusCode !== 409) { + this.store.dispatch( + new SnackbarErrorAction('APP.MESSAGES.ERRORS.GENERIC') + ); + } + + return of(null); + }) + ) + .subscribe((node: NodeEntry | null) => { + if (node) { + this.content.reload.next(); + } + }); + }) + ); +} From b7f29990c23362756640389ad7967987a5569e60 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 12 Dec 2019 10:13:24 +0200 Subject: [PATCH 16/96] file from template dialog --- .../create-file-from-template.service.ts | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 src/app/services/create-file-from-template.service.ts diff --git a/src/app/services/create-file-from-template.service.ts b/src/app/services/create-file-from-template.service.ts new file mode 100644 index 000000000..9848b22c0 --- /dev/null +++ b/src/app/services/create-file-from-template.service.ts @@ -0,0 +1,121 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Injectable } from '@angular/core'; +import { MatDialog, MatDialogConfig } from '@angular/material'; +import { + ContentNodeSelectorComponentData, + ContentNodeSelectorComponent +} from '@alfresco/adf-content-services'; +import { Subject, from, of } from 'rxjs'; +import { Node } from '@alfresco/js-api'; +import { AlfrescoApiService } from '@alfresco/adf-core'; +import { switchMap, catchError } from 'rxjs/operators'; +import { Store } from '@ngrx/store'; +import { AppStore, SnackbarErrorAction } from '@alfresco/aca-shared/store'; + +@Injectable({ + providedIn: 'root' +}) +export class CreateFileFromTemplateService { + constructor( + private store: Store, + private alfrescoApiService: AlfrescoApiService, + public dialog: MatDialog + ) {} + + openTemplatesDialog(): Subject { + const select = new Subject(); + select.subscribe({ + complete: this.close.bind(this) + }); + + const data: ContentNodeSelectorComponentData = { + title: null, + dropdownHideMyFiles: true, + currentFolderId: null, + dropdownSiteList: null, + breadcrumbTransform: this.transformNode.bind(this), + select, + isSelectionValid: this.isSelectionValid.bind(this) + }; + + data.select.subscribe({ + complete: this.close.bind(this) + }); + + from( + this.alfrescoApiService.getInstance().nodes.getNodeInfo('-root-', { + relativePath: 'Data Dictionary/Node Templates' + }) + ) + .pipe( + switchMap(node => { + data.currentFolderId = node.id; + return this.dialog + .open(ContentNodeSelectorComponent, { + data, + panelClass: [ + 'adf-content-node-selector-dialog', + 'aca-template-node-selector-dialog' + ], + width: '630px' + }) + .afterClosed(); + }), + catchError(error => { + this.store.dispatch( + new SnackbarErrorAction('APP.MESSAGES.ERRORS.GENERIC') + ); + return of(error); + }) + ) + .subscribe({ next: () => select.complete() }); + + return select; + } + + private transformNode(node: Node): Node { + if (node && node.path && node.path && node.path.elements instanceof Array) { + let { + path: { elements: elementsPath = [] } + } = node; + elementsPath = elementsPath.filter( + path => path.name !== 'Company Home' && path.name !== 'Data Dictionary' + ); + node.path.elements = elementsPath; + } + + return node; + } + + private isSelectionValid(node: Node): boolean { + return node.isFile; + } + + private close() { + this.dialog.closeAll(); + } +} From fa448f4d4b1e0fb687317d9659b9248e4db5e46b Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 12 Dec 2019 10:14:13 +0200 Subject: [PATCH 17/96] menu entry --- src/assets/app.extensions.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/assets/app.extensions.json b/src/assets/app.extensions.json index 8a8c989b9..44a2fcd3b 100644 --- a/src/assets/app.extensions.json +++ b/src/assets/app.extensions.json @@ -102,6 +102,24 @@ "actions": { "click": "CREATE_LIBRARY" } + }, + { + "id": "app.create.separator.2", + "type": "separator", + "order": 650 + }, + { + "id": "app.create.fileFromTemplate", + "order": 700, + "icon": "description", + "title": "APP.NEW_MENU.MENU_ITEMS.FILE_TEMPLATE", + "description": "APP.NEW_MENU.MENU_ITEMS.FILE_TEMPLATE", + "actions": { + "click": "CREATE_FILE_FROM_TEMPLATE" + }, + "rules": { + "enabled": "app.navigation.folder.canUpload" + } } ], "navbar": [ From 1264218cd16a6aa7990c2c3231286ec0a44239fd Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 12 Dec 2019 10:14:33 +0200 Subject: [PATCH 18/96] i18n --- src/assets/i18n/en.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index ec473ac55..7813a920c 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -57,7 +57,8 @@ "CREATE_FOLDER": "Create Folder", "UPLOAD_FILE": "Upload File", "UPLOAD_FOLDER": "Upload Folder", - "CREATE_LIBRARY": "Create Library" + "CREATE_LIBRARY": "Create Library", + "FILE_TEMPLATE": "Create file from template" }, "TOOLTIPS": { "CREATE_FOLDER": "Create new folder", From dc511bd430e60210962b2040e52b7b9ec2fb21c2 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 12 Dec 2019 10:14:55 +0200 Subject: [PATCH 19/96] tests --- .../create-file-from-template.service.spec.ts | 156 ++++++++++++++++++ .../store/effects/template.effects.spec.ts | 93 +++++++++++ 2 files changed, 249 insertions(+) create mode 100644 src/app/services/create-file-from-template.service.spec.ts create mode 100644 src/app/store/effects/template.effects.spec.ts diff --git a/src/app/services/create-file-from-template.service.spec.ts b/src/app/services/create-file-from-template.service.spec.ts new file mode 100644 index 000000000..70e7c89be --- /dev/null +++ b/src/app/services/create-file-from-template.service.spec.ts @@ -0,0 +1,156 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { EffectsModule } from '@ngrx/effects'; +import { AppStore, SnackbarErrorAction } from '@alfresco/aca-shared/store'; +import { TemplateEffects } from '../store/effects/template.effects'; +import { AppTestingModule } from '../testing/app-testing.module'; +import { Store } from '@ngrx/store'; +import { MatDialog } from '@angular/material/dialog'; +import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-core'; +import { CreateFileFromTemplateService } from './create-file-from-template.service'; +import { of } from 'rxjs'; + +describe('CreateFileFromTemplateService', () => { + let dialog: MatDialog; + let store: Store; + let alfrescoApiService: AlfrescoApiService; + let createFileFromTemplateService: CreateFileFromTemplateService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [AppTestingModule, EffectsModule.forRoot([TemplateEffects])], + providers: [ + CreateFileFromTemplateService, + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock } + ] + }); + + store = TestBed.get(Store); + alfrescoApiService = TestBed.get(AlfrescoApiService); + dialog = TestBed.get(MatDialog); + createFileFromTemplateService = TestBed.get(CreateFileFromTemplateService); + }); + + it('should open dialog with `Node Templates` folder id as data property', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(dialog, 'open'); + + createFileFromTemplateService.openTemplatesDialog(); + + expect(dialog.open['calls'].argsFor(0)[1].data).toEqual( + jasmine.objectContaining({ currentFolderId: 'templates-folder-id' }) + ); + }); + + it('should remove parents for templates node breadcrumb path', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue( + of({ + id: 'templates-folder-id', + path: { + elements: [], + name: '/Company Home/Data Dictionary' + } + }) + ); + spyOn(dialog, 'open'); + + createFileFromTemplateService.openTemplatesDialog(); + + const breadcrumb = dialog.open['calls'] + .argsFor(0)[1] + .data.breadcrumbTransform({ + name: 'Node Templates', + path: { + elements: [{ name: 'Company Home' }, { name: 'Data Dictionary' }], + name: '/Company Home/Data Dictionary' + } + }); + + expect(breadcrumb.path.elements).toEqual([]); + }); + + it('should return false if selected node is not a template file', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(dialog, 'open'); + + createFileFromTemplateService.openTemplatesDialog(); + + const isSelectionValid = dialog.open['calls'] + .argsFor(0)[1] + .data.isSelectionValid({ + isFile: false + }); + + expect(isSelectionValid).toBe(false); + }); + + it('should return true if selected node is a template file', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(dialog, 'open'); + + createFileFromTemplateService.openTemplatesDialog(); + + const isSelectionValid = dialog.open['calls'] + .argsFor(0)[1] + .data.isSelectionValid({ + isFile: true + }); + + expect(isSelectionValid).toBe(true); + }); + + it('should raise an error when getNodeInfo fails', fakeAsync(() => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue( + Promise.reject({ + message: `{ "error": { "statusCode": 404 } } ` + }) + ); + spyOn(store, 'dispatch'); + + createFileFromTemplateService.openTemplatesDialog(); + tick(); + + expect(store.dispatch).toHaveBeenCalledWith( + new SnackbarErrorAction('APP.MESSAGES.ERRORS.GENERIC') + ); + })); +}); diff --git a/src/app/store/effects/template.effects.spec.ts b/src/app/store/effects/template.effects.spec.ts new file mode 100644 index 000000000..51e976b27 --- /dev/null +++ b/src/app/store/effects/template.effects.spec.ts @@ -0,0 +1,93 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { AppTestingModule } from '../../testing/app-testing.module'; +import { TemplateEffects } from './template.effects'; +import { EffectsModule } from '@ngrx/effects'; +import { Store } from '@ngrx/store'; +import { + CreateFileFromTemplate, + SnackbarErrorAction +} from '@alfresco/aca-shared/store'; +import { CreateFileFromTemplateService } from '../../services/create-file-from-template.service'; +import { of } from 'rxjs'; +import { AlfrescoApiServiceMock, AlfrescoApiService } from '@alfresco/adf-core'; +import { ContentManagementService } from '../../services/content-management.service'; + +describe('TemplateEffects', () => { + let store: Store; + let createFileFromTemplateService: CreateFileFromTemplateService; + let alfrescoApiService: AlfrescoApiService; + let contentManagementService: ContentManagementService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [AppTestingModule, EffectsModule.forRoot([TemplateEffects])], + providers: [ + CreateFileFromTemplateService, + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock } + ] + }); + + store = TestBed.get(Store); + createFileFromTemplateService = TestBed.get(CreateFileFromTemplateService); + alfrescoApiService = TestBed.get(AlfrescoApiService); + contentManagementService = TestBed.get(ContentManagementService); + + spyOn(contentManagementService.reload, 'next'); + spyOn(store, 'select').and.returnValue(of({ id: 'parent-id' })); + spyOn(createFileFromTemplateService, 'openTemplatesDialog').and.returnValue( + of([{ id: 'template-id' }]) + ); + }); + + it('should reload content on template copy', fakeAsync(() => { + spyOn(alfrescoApiService.getInstance().nodes, 'copyNode').and.returnValue( + of({}) + ); + store.dispatch(new CreateFileFromTemplate()); + tick(); + + expect(contentManagementService.reload.next).toHaveBeenCalled(); + })); + + it('should raise error when copy template fails', fakeAsync(() => { + spyOn(store, 'dispatch').and.callThrough(); + spyOn(alfrescoApiService.getInstance().nodes, 'copyNode').and.returnValue( + Promise.reject({ + message: `{ "error": { "statusCode": 404 } } ` + }) + ); + + store.dispatch(new CreateFileFromTemplate()); + tick(); + + expect(contentManagementService.reload.next).not.toHaveBeenCalled(); + expect(store.dispatch['calls'].argsFor(1)[0]).toEqual( + new SnackbarErrorAction('APP.MESSAGES.ERRORS.GENERIC') + ); + })); +}); From 5e0f1870877eff2611bb596f8619dbf9dfa8842b Mon Sep 17 00:00:00 2001 From: pionnegru Date: Thu, 12 Dec 2019 10:15:13 +0200 Subject: [PATCH 20/96] hide node selector inputs --- src/app/ui/overrides/adf-style-fixes.theme.scss | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/app/ui/overrides/adf-style-fixes.theme.scss b/src/app/ui/overrides/adf-style-fixes.theme.scss index 52383281a..b5279f1c8 100644 --- a/src/app/ui/overrides/adf-style-fixes.theme.scss +++ b/src/app/ui/overrides/adf-style-fixes.theme.scss @@ -13,4 +13,15 @@ display: none; } } + + .aca-template-node-selector-dialog { + adf-content-node-selector-panel { + .adf-content-node-selector-content-input { + display: none; + } + .adf-sites-dropdown { + display: none; + } + } + } } From db2a6a7ef70f3e34c9e9624e4b9054e517f39ca1 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Mon, 16 Dec 2019 16:26:56 +0200 Subject: [PATCH 21/96] [ACA-2835] Favorites list - incorrect viewer actions when opened via link (#1279) * stop event propagation * tests --- .../name-column/name-column.component.html | 2 +- .../name-column/name-column.component.spec.ts | 17 +++++++++++++++++ .../name-column/name-column.component.ts | 5 +++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/app/components/dl-custom-components/name-column/name-column.component.html b/src/app/components/dl-custom-components/name-column/name-column.component.html index 6d9a13f8d..0211f5288 100644 --- a/src/app/components/dl-custom-components/name-column/name-column.component.html +++ b/src/app/components/dl-custom-components/name-column/name-column.component.html @@ -17,7 +17,7 @@ " class="adf-datatable-cell-value" title="{{ node | adfNodeNameTooltip }}" - (click)="onClick()" + (click)="onLinkClick($event)" > {{ displayText$ | async }} diff --git a/src/app/components/dl-custom-components/name-column/name-column.component.spec.ts b/src/app/components/dl-custom-components/name-column/name-column.component.spec.ts index 166831681..597d14b2d 100644 --- a/src/app/components/dl-custom-components/name-column/name-column.component.spec.ts +++ b/src/app/components/dl-custom-components/name-column/name-column.component.spec.ts @@ -105,4 +105,21 @@ describe('CustomNameColumnComponent', () => { fixture.debugElement.nativeElement.querySelector('aca-locked-by') ).not.toBe(null); }); + + it('should call parent component onClick method', () => { + const event = new MouseEvent('click'); + spyOn(component, 'onClick'); + + component.onLinkClick(event); + + expect(component.onClick).toHaveBeenCalled(); + }); + + it('should prevent event propagation', () => { + const event = new MouseEvent('click'); + spyOn(event, 'stopPropagation'); + + component.onLinkClick(event); + expect(event.stopPropagation).toHaveBeenCalled(); + }); }); diff --git a/src/app/components/dl-custom-components/name-column/name-column.component.ts b/src/app/components/dl-custom-components/name-column/name-column.component.ts index 3a34def4d..d8efe9659 100644 --- a/src/app/components/dl-custom-components/name-column/name-column.component.ts +++ b/src/app/components/dl-custom-components/name-column/name-column.component.ts @@ -94,6 +94,11 @@ export class CustomNameColumnComponent extends NameColumnComponent }); } + onLinkClick(event: Event) { + event.stopPropagation(); + this.onClick(); + } + ngOnDestroy() { super.ngOnDestroy(); From 84dc1480745e4802a5fe51625ad42314174f9a08 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Fri, 20 Dec 2019 12:30:22 +0200 Subject: [PATCH 22/96] try upgrade again (#1281) --- package-lock.json | 38 ++++++++++++++++++++++++++++++++++---- package.json | 2 +- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 25c4ce73e..e3d920dda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10344,14 +10344,14 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "puppeteer": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.20.0.tgz", - "integrity": "sha512-bt48RDBy2eIwZPrkgbcwHtb51mj2nKvHOPMaSH2IsWiv7lOG9k9zhaRzpDZafrk05ajMc3cu+lSQYYOfH2DkVQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-2.0.0.tgz", + "integrity": "sha512-t3MmTWzQxPRP71teU6l0jX47PHXlc4Z52sQv4LJQSZLq1ttkKS2yGM3gaI57uQwZkNaoGd0+HPPMELZkcyhlqA==", "dev": true, "requires": { "debug": "^4.1.0", "extract-zip": "^1.6.6", - "https-proxy-agent": "^2.2.1", + "https-proxy-agent": "^3.0.0", "mime": "^2.0.3", "progress": "^2.0.1", "proxy-from-env": "^1.0.0", @@ -10359,6 +10359,15 @@ "ws": "^6.1.0" }, "dependencies": { + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -10368,6 +10377,27 @@ "ms": "^2.1.1" } }, + "https-proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", + "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, "mime": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", diff --git a/package.json b/package.json index bbeea35af..ad138615e 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "prettier": "^1.17.1", "protractor": "5.4.2", "protractor-screenshoter-plugin": "0.10.3", - "puppeteer": "^1.20.0", + "puppeteer": "^2.0.0", "rxjs-tslint-rules": "^4.19.0", "selenium-webdriver": "4.0.0-alpha.1", "ts-node": "^8.0.3", From b3a7c63b45560253cb39ce618d7874117ade193c Mon Sep 17 00:00:00 2001 From: pionnegru Date: Mon, 23 Dec 2019 10:56:48 +0200 Subject: [PATCH 23/96] create from template dialog --- .../create-from-template.dialog.html | 59 ++++++++ .../create-from-template.dialog.scss | 64 +++++++++ .../create-from-template.dialog.ts | 128 ++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 src/app/dialogs/node-templates/create-from-template.dialog.html create mode 100644 src/app/dialogs/node-templates/create-from-template.dialog.scss create mode 100644 src/app/dialogs/node-templates/create-from-template.dialog.ts diff --git a/src/app/dialogs/node-templates/create-from-template.dialog.html b/src/app/dialogs/node-templates/create-from-template.dialog.html new file mode 100644 index 000000000..a542bebd2 --- /dev/null +++ b/src/app/dialogs/node-templates/create-from-template.dialog.html @@ -0,0 +1,59 @@ +

+
+
+ + + + + {{ form.controls['name'].errors?.message | translate }} + + + + + + + + {{ 'FILE_FROM_TEMPLATE.FORM.ERRORS.TITLE_TOO_LONG' | translate }} + + + + + + + + {{ 'FILE_FROM_TEMPLATE.FORM.ERRORS.DESCRIPTION_TOO_LONG' | translate }} + + +
+
+
+ + +
diff --git a/src/app/dialogs/node-templates/create-from-template.dialog.scss b/src/app/dialogs/node-templates/create-from-template.dialog.scss new file mode 100644 index 000000000..b88024c6e --- /dev/null +++ b/src/app/dialogs/node-templates/create-from-template.dialog.scss @@ -0,0 +1,64 @@ +@mixin app-create-file-from-template-theme($theme) { + $primary: map-get($theme, primary); + $accent: map-get($theme, accent); + $foreground: map-get($theme, foreground); + $background: map-get($theme, background); + + .aca-file-from-template-dialog { + ng-component { + overflow: visible; + } + + .mat-dialog-title { + margin-left: 24px; + margin-right: 24px; + font-size: 20px; + font-style: normal; + font-stretch: normal; + line-height: 1.6; + letter-spacing: -0.5px; + color: mat-color($foreground, text, 0.87); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + .bold { + font-weight: 600; + } + } + + .mat-form-field { + margin-bottom: 20px; + } + + .mat-dialog-container { + padding-left: 0; + padding-right: 0; + } + + .mat-dialog-content { + margin: 0 2px; + overflow: hidden; + } + + .mat-dialog-actions { + padding: 8px 22px; + display: flex; + justify-content: flex-end; + color: mat-color($foreground, secondary-text); + + button { + text-transform: uppercase; + font-weight: normal; + } + + .create:disabled { + color: mat-color($primary); + } + + .create { + color: mat-color($accent); + } + } + } +} diff --git a/src/app/dialogs/node-templates/create-from-template.dialog.ts b/src/app/dialogs/node-templates/create-from-template.dialog.ts new file mode 100644 index 000000000..9e7562d57 --- /dev/null +++ b/src/app/dialogs/node-templates/create-from-template.dialog.ts @@ -0,0 +1,128 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Component, ViewEncapsulation, Inject, OnInit } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; +import { Node } from '@alfresco/js-api'; +import { + FormBuilder, + FormGroup, + Validators, + FormControl, + ValidationErrors +} from '@angular/forms'; + +@Component({ + templateUrl: './create-from-template.dialog.html', + encapsulation: ViewEncapsulation.None, + styleUrls: ['./create-from-template.dialog.scss'] +}) +export class CreateFileFromTemplateDialogComponent implements OnInit { + public form: FormGroup; + + constructor( + private formBuilder: FormBuilder, + private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any + ) {} + + ngOnInit() { + this.form = this.formBuilder.group({ + name: [ + this.data.name, + [ + Validators.required, + this.forbidEndingDot, + this.forbidOnlySpaces, + this.forbidSpecialCharacters + ] + ], + title: [this.data.properties['cm:title'], Validators.maxLength(256)], + description: [ + this.data.properties['cm:description'], + Validators.maxLength(512) + ] + }); + } + + onSubmit() { + const update = { + name: this.form.value.name, + properties: { + 'cm:title': this.form.value.title, + 'cm:description': this.form.value.description + } + }; + const data: Node = Object.assign({}, this.data, update); + this.dialogRef.close(data); + } + + close() { + this.dialogRef.close(); + } + + private forbidSpecialCharacters({ + value + }: FormControl): ValidationErrors | null { + const specialCharacters: RegExp = /([\*\"\<\>\\\/\?\:\|])/; + const isValid: boolean = !specialCharacters.test(value); + + return isValid + ? null + : { + message: `FILE_FROM_TEMPLATE.FORM.ERRORS.SPECIAL_CHARACTERS` + }; + } + + private forbidEndingDot({ value }: FormControl): ValidationErrors | null { + const isValid: boolean = + (value || '') + .trim() + .split('') + .pop() !== '.'; + + return isValid + ? null + : { + message: `FILE_FROM_TEMPLATE.FORM.ERRORS.ENDING_DOT` + }; + } + + private forbidOnlySpaces({ value }: FormControl): ValidationErrors | null { + if (value.length) { + const isValid: boolean = !!(value || '').trim(); + + return isValid + ? null + : { + message: `FILE_FROM_TEMPLATE.FORM.ERRORS.ONLY_SPACES` + }; + } else { + return { + message: `FILE_FROM_TEMPLATE.FORM.ERRORS.REQUIRED` + }; + } + } +} From 42cdbc293172847c1f9154ee8ea1136dd48ce49e Mon Sep 17 00:00:00 2001 From: pionnegru Date: Mon, 23 Dec 2019 10:59:01 +0200 Subject: [PATCH 24/96] add open create from template --- src/app/app.module.ts | 8 ++-- .../create-file-from-template.service.ts | 39 ++++++++++++------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ec362240d..111bad187 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -76,7 +76,7 @@ import { AppNodeVersionModule } from './components/node-version/node-version.mod import { FavoritesComponent } from './components/favorites/favorites.component'; import { RecentFilesComponent } from './components/recent-files/recent-files.component'; import { SharedFilesComponent } from './components/shared-files/shared-files.component'; - +import { CreateFileFromTemplateDialogComponent } from './dialogs/node-templates/create-from-template.dialog'; import { environment } from '../environments/environment'; import { registerLocaleData } from '@angular/common'; @@ -158,7 +158,8 @@ registerLocaleData(localeSv); NodeVersionsDialogComponent, FavoritesComponent, RecentFilesComponent, - SharedFilesComponent + SharedFilesComponent, + CreateFileFromTemplateDialogComponent ], providers: [ { provide: RouteReuseStrategy, useClass: AppRouteReuseStrategy }, @@ -175,7 +176,8 @@ registerLocaleData(localeSv); entryComponents: [ NodeVersionsDialogComponent, NodeVersionUploadDialogComponent, - LibraryDialogComponent + LibraryDialogComponent, + CreateFileFromTemplateDialogComponent ], bootstrap: [AppComponent] }) diff --git a/src/app/services/create-file-from-template.service.ts b/src/app/services/create-file-from-template.service.ts index 9848b22c0..f9a8d8790 100644 --- a/src/app/services/create-file-from-template.service.ts +++ b/src/app/services/create-file-from-template.service.ts @@ -24,17 +24,18 @@ */ import { Injectable } from '@angular/core'; -import { MatDialog, MatDialogConfig } from '@angular/material'; -import { - ContentNodeSelectorComponentData, - ContentNodeSelectorComponent -} from '@alfresco/adf-content-services'; +import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material'; +import { CreateFileFromTemplateDialogComponent } from '../dialogs/node-templates/create-from-template.dialog'; import { Subject, from, of } from 'rxjs'; -import { Node } from '@alfresco/js-api'; -import { AlfrescoApiService } from '@alfresco/adf-core'; +import { Node, MinimalNode } from '@alfresco/js-api'; +import { AlfrescoApiService, TranslationService } from '@alfresco/adf-core'; import { switchMap, catchError } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { AppStore, SnackbarErrorAction } from '@alfresco/aca-shared/store'; +import { + ContentNodeSelectorComponent, + ContentNodeSelectorComponentData +} from '@alfresco/adf-content-services'; @Injectable({ providedIn: 'root' @@ -43,6 +44,7 @@ export class CreateFileFromTemplateService { constructor( private store: Store, private alfrescoApiService: AlfrescoApiService, + private translation: TranslationService, public dialog: MatDialog ) {} @@ -53,7 +55,8 @@ export class CreateFileFromTemplateService { }); const data: ContentNodeSelectorComponentData = { - title: null, + title: this.title, + actionName: 'NEXT', dropdownHideMyFiles: true, currentFolderId: null, dropdownSiteList: null, @@ -62,10 +65,6 @@ export class CreateFileFromTemplateService { isSelectionValid: this.isSelectionValid.bind(this) }; - data.select.subscribe({ - complete: this.close.bind(this) - }); - from( this.alfrescoApiService.getInstance().nodes.getNodeInfo('-root-', { relativePath: 'Data Dictionary/Node Templates' @@ -97,7 +96,17 @@ export class CreateFileFromTemplateService { return select; } - private transformNode(node: Node): Node { + createTemplateDialog( + node: Node + ): MatDialogRef { + return this.dialog.open(CreateFileFromTemplateDialogComponent, { + data: node, + panelClass: 'aca-file-from-template-dialog', + width: '630px' + }); + } + + private transformNode(node: MinimalNode): MinimalNode { if (node && node.path && node.path && node.path.elements instanceof Array) { let { path: { elements: elementsPath = [] } @@ -118,4 +127,8 @@ export class CreateFileFromTemplateService { private close() { this.dialog.closeAll(); } + + private get title() { + return this.translation.instant('NODE_SELECTOR.SELECT_TEMPLATE_TITLE'); + } } From 9e93d462f76df53eb9030b948b4c320b039af84f Mon Sep 17 00:00:00 2001 From: pionnegru Date: Mon, 23 Dec 2019 11:00:02 +0200 Subject: [PATCH 25/96] open create dialog after template selection --- src/app/store/effects/template.effects.ts | 85 ++++++++++++++++++----- 1 file changed, 66 insertions(+), 19 deletions(-) diff --git a/src/app/store/effects/template.effects.ts b/src/app/store/effects/template.effects.ts index 9ae79a2e1..ec7485076 100644 --- a/src/app/store/effects/template.effects.ts +++ b/src/app/store/effects/template.effects.ts @@ -25,7 +25,15 @@ import { Effect, Actions, ofType } from '@ngrx/effects'; import { Injectable } from '@angular/core'; -import { map, withLatestFrom, switchMap, catchError } from 'rxjs/operators'; +import { + map, + withLatestFrom, + switchMap, + catchError, + debounceTime, + flatMap, + skipWhile +} from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { CreateFileFromTemplate, @@ -37,8 +45,8 @@ import { import { CreateFileFromTemplateService } from '../../services/create-file-from-template.service'; import { AlfrescoApiService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../services/content-management.service'; -import { from, of } from 'rxjs'; -import { NodeEntry } from '@alfresco/js-api'; +import { from, of, Observable } from 'rxjs'; +import { NodeEntry, NodeBodyUpdate, MinimalNode } from '@alfresco/js-api'; @Injectable() export class TemplateEffects { @@ -57,31 +65,70 @@ export class TemplateEffects { this.createFileFromTemplateService .openTemplatesDialog() .pipe( + debounceTime(300), + flatMap(([node]) => + this.createFileFromTemplateService + .createTemplateDialog(node) + .afterClosed() + ), + skipWhile(node => !node), withLatestFrom(this.store.select(getCurrentFolder)), - switchMap(([[template], parentNode]) => { - return from( - this.apiService - .getInstance() - .nodes.copyNode(template.id, { targetParentId: parentNode.id }) - ); + switchMap(([template, parentNode]) => { + return this.copyNode(template, parentNode.id); }), catchError(error => { - const { statusCode } = JSON.parse(error.message).error; - - if (statusCode !== 409) { - this.store.dispatch( - new SnackbarErrorAction('APP.MESSAGES.ERRORS.GENERIC') - ); - } - - return of(null); + return this.handleError(error); }) ) .subscribe((node: NodeEntry | null) => { if (node) { - this.content.reload.next(); + this.content.reload.next(node); } }); }) ); + + private copyNode( + source: MinimalNode, + parentId: string + ): Observable { + return from( + this.apiService.getInstance().nodes.copyNode(source.id, { + targetParentId: parentId, + name: source.name + }) + ).pipe( + switchMap(node => + this.updateNode(node.entry.id, { + properties: { + 'cm:title': source.properties['cm:title'], + 'cm:description': source.properties['cm:description'] + } + }) + ) + ); + } + + private updateNode( + id: string, + update: NodeBodyUpdate + ): Observable { + return from(this.apiService.getInstance().nodes.updateNode(id, update)); + } + + private handleError(error: Error): Observable { + const { statusCode } = JSON.parse(error.message).error; + + if (statusCode !== 409) { + this.store.dispatch( + new SnackbarErrorAction('APP.MESSAGES.ERRORS.GENERIC') + ); + } else { + this.store.dispatch( + new SnackbarErrorAction('APP.MESSAGES.ERRORS.CONFLICT') + ); + } + + return of(null); + } } From 04fc47c08ddd2cf53973332412d4dc396494cea7 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Mon, 23 Dec 2019 11:00:35 +0200 Subject: [PATCH 26/96] add dialog theme --- src/app/ui/custom-theme.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/ui/custom-theme.scss b/src/app/ui/custom-theme.scss index db39d309c..3059f4a95 100644 --- a/src/app/ui/custom-theme.scss +++ b/src/app/ui/custom-theme.scss @@ -10,6 +10,7 @@ @import '../dialogs/node-versions/node-versions.dialog.theme'; @import '../components/create-menu/create-menu.component.scss'; @import '../components/layout/layout.theme.scss'; +@import '../dialogs/node-templates/create-from-template.dialog.scss'; @import './overrides/adf-style-fixes.theme'; @@ -67,6 +68,7 @@ $warn: map-get($custom-theme, warn); @include sidenav-component-theme($theme); @include aca-current-user-theme($theme); @include aca-context-menu-theme($theme); + @include app-create-file-from-template-theme($theme); @include app-create-menu-theme($theme); @include adf-style-fixes($theme); From bc570acca5a26752763a30e29ae52134c3357498 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Mon, 23 Dec 2019 11:00:59 +0200 Subject: [PATCH 27/96] add i18n --- src/assets/i18n/en.json | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 7813a920c..931b9ad41 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -356,7 +356,29 @@ "COPY_ITEMS": "Copy {{ number }} items to...", "MOVE_ITEM": "Move '{{ name }}' to...", "MOVE_ITEMS": "Move {{ number }} items to...", - "SEARCH": "Search" + "SEARCH": "Search", + "NEXT": "Next", + "SELECT_TEMPLATE_TITLE": "Select a document template" + }, + "FILE_FROM_TEMPLATE": { + "CANCEL": "CANCEL", + "CREATE": "Create", + "TITLE": "Create new document from '{{ template }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Name", + "TITLE": "Title", + "DESCRIPTION": "Description" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "Use 512 characters or less for description", + "TITLE_TOO_LONG": "Use 256 characters or less for title", + "REQUIRED": "File name is required", + "SPECIAL_CHARACTERS": "File name can't contain these characters * \" < > \\ / ? : |", + "ENDING_DOT": "File name can't end with a period .", + "ONLY_SPACES": "File name can't contain only spaces" + } + } }, "PERMISSIONS": { "DIALOG": { From c1dfed9e1c6880f6d49585df56ddb358b40d2aaa Mon Sep 17 00:00:00 2001 From: pionnegru Date: Mon, 23 Dec 2019 11:01:38 +0200 Subject: [PATCH 28/96] tests --- .../create-from-template.dialog.spec.ts | 140 ++++++++++++++++++ .../store/effects/template.effects.spec.ts | 76 +++++++++- 2 files changed, 212 insertions(+), 4 deletions(-) create mode 100644 src/app/dialogs/node-templates/create-from-template.dialog.spec.ts diff --git a/src/app/dialogs/node-templates/create-from-template.dialog.spec.ts b/src/app/dialogs/node-templates/create-from-template.dialog.spec.ts new file mode 100644 index 000000000..0ff8ee84f --- /dev/null +++ b/src/app/dialogs/node-templates/create-from-template.dialog.spec.ts @@ -0,0 +1,140 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { CreateFileFromTemplateDialogComponent } from './create-from-template.dialog'; +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { AppTestingModule } from '../../testing/app-testing.module'; +import { CoreModule } from '@alfresco/adf-core'; +import { + MatDialogModule, + MatDialogRef, + MAT_DIALOG_DATA +} from '@angular/material/dialog'; + +function text(length: number) { + return new Array(length) + .fill( + Math.random() + .toString() + .substring(2, 3) + ) + .join(''); +} + +describe('CreateFileFromTemplateDialogComponent', () => { + let fixture: ComponentFixture; + let component: CreateFileFromTemplateDialogComponent; + let dialogRef: MatDialogRef; + + const data = { + id: 'node-id', + name: 'node-name', + properties: { + 'cm:title': 'node-title', + 'cm:description': '' + } + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [CoreModule.forRoot(), AppTestingModule, MatDialogModule], + declarations: [CreateFileFromTemplateDialogComponent], + providers: [ + { provide: MAT_DIALOG_DATA, useValue: data }, + { + provide: MatDialogRef, + useValue: { + close: jasmine.createSpy('close') + } + } + ] + }); + + fixture = TestBed.createComponent(CreateFileFromTemplateDialogComponent); + dialogRef = TestBed.get(MatDialogRef); + component = fixture.componentInstance; + + fixture.detectChanges(); + }); + + it('should populate form with provided dialog data', () => { + expect(component.form.controls.name.value).toBe(data.name); + expect(component.form.controls.title.value).toBe( + data.properties['cm:title'] + ); + expect(component.form.controls.description.value).toBe( + data.properties['cm:description'] + ); + }); + + it('should invalidate form if required `name` field is invalid', () => { + component.form.controls.name.setValue(''); + fixture.detectChanges(); + expect(component.form.invalid).toBe(true); + }); + + it('should invalidate form if required `name` field has `only spaces`', () => { + component.form.controls.name.setValue(' '); + fixture.detectChanges(); + expect(component.form.invalid).toBe(true); + }); + + it('should invalidate form if required `name` field has `ending dot`', () => { + component.form.controls.name.setValue('something.'); + fixture.detectChanges(); + expect(component.form.invalid).toBe(true); + }); + + it('should invalidate form if `title` text length is long', () => { + component.form.controls.title.setValue(text(260)); + fixture.detectChanges(); + expect(component.form.invalid).toBe(true); + }); + + it('should invalidate form if `description` text length is long', () => { + component.form.controls.description.setValue(text(520)); + fixture.detectChanges(); + expect(component.form.invalid).toBe(true); + }); + + it('should update data with form values', () => { + component.form.controls.name.setValue('new-node-name'); + component.form.controls.title.setValue('new-node-title'); + component.form.controls.description.setValue('new-node-description'); + + fixture.detectChanges(); + + component.onSubmit(); + + expect(dialogRef.close['calls'].argsFor(0)[0]).toEqual({ + id: 'node-id', + name: 'new-node-name', + properties: { + 'cm:title': 'new-node-title', + 'cm:description': 'new-node-description' + } + }); + }); +}); diff --git a/src/app/store/effects/template.effects.spec.ts b/src/app/store/effects/template.effects.spec.ts index 51e976b27..266656a88 100644 --- a/src/app/store/effects/template.effects.spec.ts +++ b/src/app/store/effects/template.effects.spec.ts @@ -36,12 +36,28 @@ import { CreateFileFromTemplateService } from '../../services/create-file-from-t import { of } from 'rxjs'; import { AlfrescoApiServiceMock, AlfrescoApiService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../services/content-management.service'; +import { Node } from '@alfresco/js-api'; describe('TemplateEffects', () => { let store: Store; let createFileFromTemplateService: CreateFileFromTemplateService; let alfrescoApiService: AlfrescoApiService; let contentManagementService: ContentManagementService; + const node: Node = { + name: 'node-name', + id: 'node-id', + nodeType: 'cm:content', + isFolder: false, + isFile: true, + modifiedAt: null, + modifiedByUser: null, + createdAt: null, + createdByUser: null, + properties: { + 'cm:title': 'title', + 'cm:description': 'description' + } + }; beforeEach(() => { TestBed.configureTestingModule({ @@ -64,17 +80,27 @@ describe('TemplateEffects', () => { ); }); - it('should reload content on template copy', fakeAsync(() => { + it('should reload content on create file from template', fakeAsync(() => { spyOn(alfrescoApiService.getInstance().nodes, 'copyNode').and.returnValue( + of({ entry: { id: 'node-id' } }) + ); + + spyOn(alfrescoApiService.getInstance().nodes, 'updateNode').and.returnValue( of({}) ); + + spyOn( + createFileFromTemplateService, + 'createTemplateDialog' + ).and.returnValue({ afterClosed: () => of(node) }); + store.dispatch(new CreateFileFromTemplate()); - tick(); + tick(300); expect(contentManagementService.reload.next).toHaveBeenCalled(); })); - it('should raise error when copy template fails', fakeAsync(() => { + it('should raise error when copyNode api fails', fakeAsync(() => { spyOn(store, 'dispatch').and.callThrough(); spyOn(alfrescoApiService.getInstance().nodes, 'copyNode').and.returnValue( Promise.reject({ @@ -82,12 +108,54 @@ describe('TemplateEffects', () => { }) ); + spyOn( + createFileFromTemplateService, + 'createTemplateDialog' + ).and.returnValue({ afterClosed: () => of(node) }); + store.dispatch(new CreateFileFromTemplate()); - tick(); + tick(300); expect(contentManagementService.reload.next).not.toHaveBeenCalled(); expect(store.dispatch['calls'].argsFor(1)[0]).toEqual( new SnackbarErrorAction('APP.MESSAGES.ERRORS.GENERIC') ); })); + + it('should raise error when updateNode api fails', fakeAsync(() => { + spyOn(store, 'dispatch').and.callThrough(); + spyOn(alfrescoApiService.getInstance().nodes, 'copyNode').and.returnValue( + of({ entry: { id: 'node-id' } }) + ); + + spyOn(alfrescoApiService.getInstance().nodes, 'updateNode').and.returnValue( + Promise.reject({ + message: `{ "error": { "statusCode": 404 } } ` + }) + ); + + spyOn( + createFileFromTemplateService, + 'createTemplateDialog' + ).and.returnValue({ afterClosed: () => of(node) }); + + store.dispatch(new CreateFileFromTemplate()); + tick(300); + + expect(contentManagementService.reload.next).not.toHaveBeenCalled(); + expect(store.dispatch['calls'].argsFor(1)[0]).toEqual( + new SnackbarErrorAction('APP.MESSAGES.ERRORS.GENERIC') + ); + })); + + it('should update file from template with form data', () => { + spyOn(alfrescoApiService.getInstance().nodes, 'copyNode').and.returnValue( + of({ entry: { id: 'node-id' } }) + ); + + spyOn( + createFileFromTemplateService, + 'createTemplateDialog' + ).and.returnValue({ afterClosed: () => of(node) }); + }); }); From 0d0ddfcf373552b568d49f6a368c974a69ec2888 Mon Sep 17 00:00:00 2001 From: Yuuki Ebihara Date: Mon, 30 Dec 2019 20:41:13 +0900 Subject: [PATCH 29/96] README Documentation Modify. (#1271) * Fixed invalid url link. * Update docs/features/side-navigation.md Co-Authored-By: Suzana Dirla * Compatibility modify in README.md. Co-authored-by: Suzana Dirla --- docs/ja/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/ja/README.md b/docs/ja/README.md index b2806a1c2..3b64127cd 100644 --- a/docs/ja/README.md +++ b/docs/ja/README.md @@ -25,6 +25,7 @@ Alfresco Content Application は、[Alfresco Application Development Framework ( | ACA バージョン | 構築バージョン | テスト済み環境 | | ----------- | ---------- | --------- | +| ACA 1.9 | ADF 3.6.0 | ACS 6.2 | | ACA 1.8 | ADF 3.3.0 | ACS 6.1 | | ACA 1.7 | ADF 3.0.0 | ACS 6.1 | | ACA 1.6 | ADF 2.6.1 | ACS 6.1 | From 5be755ad4bda5933278e4e3055547fe215fc98e4 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 2 Jan 2020 18:31:18 +0100 Subject: [PATCH 30/96] merge docker-compose.yaml and docker-compose-keycloak.yaml to one file. Implement start.sh for starting with and without SSO. --- docker-compose-keycloak.yml | 210 ------------------------------------ docker-compose.yml | 31 ++++++ docker/proxy/nginx.conf | 6 +- package.json | 10 +- start.sh | 96 +++++++++++++++++ 5 files changed, 137 insertions(+), 216 deletions(-) delete mode 100644 docker-compose-keycloak.yml create mode 100755 start.sh diff --git a/docker-compose-keycloak.yml b/docker-compose-keycloak.yml deleted file mode 100644 index 9ef10c92c..000000000 --- a/docker-compose-keycloak.yml +++ /dev/null @@ -1,210 +0,0 @@ -version: '2' - -services: - alfresco: - image: alfresco/alfresco-content-repository-community:latest - mem_limit: 1500m - depends_on: - - auth - environment: - HOST_IP: ${HOST_IP} - JAVA_OPTS: ' - -Ddb.driver=org.postgresql.Driver - -Ddb.username=alfresco - -Ddb.password=alfresco - -Ddb.url=jdbc:postgresql://postgres:5432/alfresco - -Dsolr.host=solr6 - -Dsolr.port=8983 - -Dsolr.secureComms=none - -Dsolr.base.url=/solr - -Dindex.subsystem.name=solr6 - -Dshare.host=localhost - -Dalfresco.port=8080 - -Daos.baseUrlOverwrite=http://${HOST_IP}:8080/alfresco/aos - -Dmessaging.broker.url="failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true" - -Ddeployment.method=DOCKER_COMPOSE - -Dcsrf.filter.enabled=false - -Xms1g -Xmx1g - - -Dlocal.transform.service.enabled=true - -DlocalTransform.pdfrenderer.url=http://alfresco-pdf-renderer:8090/ - -DlocalTransform.imagemagick.url=http://imagemagick:8090/ - -DlocalTransform.libreoffice.url=http://libreoffice:8090/ - -DlocalTransform.tika.url=http://tika:8090/ - -DlocalTransform.misc.url=http://transform-misc:8090/ - - -Dlegacy.transform.service.enabled=true - -Dalfresco-pdf-renderer.url=http://alfresco-pdf-renderer:8090/ - -Djodconverter.url=http://libreoffice:8090/ - -Dimg.url=http://imagemagick:8090/ - -Dtika.url=http://tika:8090/ - -Dtransform.misc.url=http://transform-misc:8090/ - - -Dauthentication.chain=identity-service1:identity-service,alfrescoNtlm1:alfrescoNtlm - -Didentity-service.enable-basic-auth=true - -Didentity-service.authentication.validation.failure.silent=false - -Didentity-service.auth-server-url=http://${HOST_IP}:8085/auth - -Didentity-service.realm=alfresco - -Didentity-service.resource=alfresco - ' - networks: - - internal - ports: - - 8080:8080 #Browser port - - alfresco-pdf-renderer: - image: alfresco/alfresco-pdf-renderer:2.1.0-EA4 - environment: - JAVA_OPTS: ' -Xms256m -Xmx256m' - networks: - - internal - ports: - - 8090:8090 - - imagemagick: - image: alfresco/alfresco-imagemagick:2.1.0-EA4 - environment: - JAVA_OPTS: ' -Xms256m -Xmx256m' - networks: - - internal - ports: - - 8091:8090 - - libreoffice: - image: alfresco/alfresco-libreoffice:2.1.0-EA4 - environment: - JAVA_OPTS: ' -Xms256m -Xmx256m' - networks: - - internal - ports: - - 8092:8090 - - tika: - image: alfresco/alfresco-tika:2.1.0-EA4 - environment: - JAVA_OPTS: ' -Xms256m -Xmx256m' - networks: - - internal - ports: - - 8093:8090 - - transform-misc: - image: alfresco/alfresco-transform-misc:2.1.0-EA4 - environment: - JAVA_OPTS: ' -Xms256m -Xmx256m' - networks: - - internal - ports: - - 8094:8090 - - share: - image: alfresco/alfresco-share:6.1.0-RC3 - mem_limit: 1g - depends_on: - - alfresco - environment: - - REPO_HOST=alfresco - - REPO_PORT=8080 - - 'CATALINA_OPTS= -Xms500m -Xmx500m' - networks: - - internal - ports: - - 8083:8080 - - postgres: - image: postgres:10.1 - mem_limit: 1500m - environment: - - POSTGRES_PASSWORD=alfresco - - POSTGRES_USER=alfresco - - POSTGRES_DB=alfresco - command: postgres -c max_connections=300 -c log_min_messages=LOG - networks: - - internal - ports: - - 5432:5432 - - solr6: - image: alfresco/alfresco-search-services:1.3.0-RC2 - mem_limit: 2500m - depends_on: - - alfresco - environment: - #Solr needs to know how to register itself with Alfresco - - SOLR_ALFRESCO_HOST=alfresco - - SOLR_ALFRESCO_PORT=8080 - #Alfresco needs to know how to call solr - - SOLR_SOLR_HOST=solr6 - - SOLR_SOLR_PORT=8983 - #Create the default alfresco and archive cores - - SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive - - 'SOLR_JAVA_MEM=-Xms2g -Xmx2g' - networks: - - internal - ports: - - 8983:8983 #Browser port - - activemq: - image: alfresco/alfresco-activemq:5.15.6 - mem_limit: 2048m - networks: - - internal - ports: - - 8161:8161 # Web Console - - 5672:5672 # AMQP - - 61616:61616 # OpenWire - - 61613:61613 # STOMP - - content-app: - image: alfresco/alfresco-content-app:latest - build: . - environment: - # BASEPATH: ./ - APP_CONFIG_OAUTH2_HOST: ${APP_CONFIG_OAUTH2_HOST} - APP_CONFIG_AUTH_TYPE: ${APP_CONFIG_AUTH_TYPE} - APP_CONFIG_OAUTH2_CLIENTID: ${APP_CONFIG_OAUTH2_CLIENTID} - APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI: ${APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI} - APP_CONFIG_OAUTH2_REDIRECT_LOGIN: ${APP_CONFIG_OAUTH2_REDIRECT_LOGIN} - APP_CONFIG_OAUTH2_REDIRECT_LOGOUT: ${APP_CONFIG_OAUTH2_REDIRECT_LOGOUT} - networks: - - internal - depends_on: - - alfresco - ports: - - 4001:80 - # volumes: - # - ./app.config.json:/usr/share/nginx/html/app.config.json - # - ./nginx.conf:/etc/nginx/conf.d/default.conf - - proxy: - image: nginx:stable-alpine - depends_on: - - content-app - - alfresco - volumes: - - ./docker/proxy/nginx.conf:/etc/nginx/conf.d/default.conf - networks: - - internal - links: - - content-app - - alfresco - - share - ports: - - 8080:8080 - - auth: - image: jboss/keycloak:4.8.3.Final - volumes: - - ./docker/auth/alfresco-realm.json:/tmp/alfresco-realm.json - networks: - - internal - environment: - - KEYCLOAK_USER=admin - - KEYCLOAK_PASSWORD=admin - - KEYCLOAK_IMPORT=/tmp/alfresco-realm.json - - DB_VENDOR=h2 - ports: - - 8085:8080 - -networks: - internal: diff --git a/docker-compose.yml b/docker-compose.yml index a110f11ad..b2e942dca 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,8 @@ services: alfresco: image: alfresco/alfresco-content-repository-community:latest mem_limit: 1500m + depends_on: + - auth volumes: - ./docker/acs-cm:/usr/local/tomcat/shared/classes/alfresco/extension environment: @@ -37,6 +39,14 @@ services: -Dtika.url=http://tika:8090/ -Dtransform.misc.url=http://transform-misc:8090/ -Dcsrf.filter.enabled=false + + -Didentity-service.enable-basic-auth=true + -Didentity-service.authentication.validation.failure.silent=false + -Didentity-service.auth-server-url=http://${HOST_IP}:8085/auth + -Didentity-service.realm=alfresco + -Didentity-service.resource=alfresco + + ${AIMS_PROPS} -Xms1500m -Xmx1500m ' @@ -132,6 +142,15 @@ services: build: . depends_on: - alfresco + environment: + BASE_PATH: ./ + APP_CONFIG_OAUTH2_HOST: ${APP_CONFIG_OAUTH2_HOST} + APP_CONFIG_AUTH_TYPE: ${APP_CONFIG_AUTH_TYPE} + APP_CONFIG_OAUTH2_CLIENTID: ${APP_CONFIG_OAUTH2_CLIENTID} + APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI: ${APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI} + APP_CONFIG_OAUTH2_REDIRECT_LOGIN: ${APP_CONFIG_OAUTH2_REDIRECT_LOGIN} + APP_CONFIG_OAUTH2_REDIRECT_LOGOUT: ${APP_CONFIG_OAUTH2_REDIRECT_LOGOUT} + APP_BASE_SHARE_URL: '{protocol}//{hostname}{:port}/workspace/#/preview/s' ports: - 4001:8080 @@ -148,3 +167,15 @@ services: - alfresco - share - content-app + + auth: + image: jboss/keycloak:4.8.3.Final + volumes: + - ./docker/auth/alfresco-realm.json:/tmp/alfresco-realm.json + environment: + - KEYCLOAK_USER=admin + - KEYCLOAK_PASSWORD=admin + - KEYCLOAK_IMPORT=/tmp/alfresco-realm.json + - DB_VENDOR=h2 + ports: + - 8085:8080 diff --git a/docker/proxy/nginx.conf b/docker/proxy/nginx.conf index 25f275517..a98763ab3 100644 --- a/docker/proxy/nginx.conf +++ b/docker/proxy/nginx.conf @@ -26,7 +26,11 @@ http { proxy_pass_header Set-Cookie; location / { - proxy_pass http://content-app:8080; + proxy_pass http://alfresco:8080; + } + + location /content-app/ { + proxy_pass http://content-app:8080/; } location /alfresco/ { diff --git a/package.json b/package.json index ad138615e..bb73e46c7 100644 --- a/package.json +++ b/package.json @@ -17,12 +17,12 @@ "lint": "ng lint && npm run spellcheck && npm run format:check && npm run e2e.typecheck", "wd:update": "webdriver-manager update --gecko=false $VERSION_CHROME", "e2e.typecheck": "tsc -p ./e2e/tsconfig.e2e.typecheck.json", - "e2e": "npm run wd:update && protractor --baseUrl=${TEST_BASE_URL:-http://localhost:8080} $SUITE", + "e2e": "npm run wd:update && protractor --baseUrl=${TEST_BASE_URL:-http://localhost:8080/content-app} $SUITE", "e2e.local": "npm run wd:update && protractor --baseUrl=http://localhost:4200 $SUITE", - "wait:app": "wait-on http://localhost:8080/alfresco/ -t 1000000 && wait-on http://localhost:8080 -t 400000", - "start:docker": "docker-compose up -d --build && npm run wait:app", - "stop:docker": "docker-compose stop", - "e2e:docker": "npm run start:docker && npm run e2e && npm run stop:docker", + "wait:app": "wait-on http://${HOST_IP:-localhost}:${HOST_PORT:-8080}/alfresco/ -t 1000000 && wait-on http://${HOST_IP:-localhost}:${HOST_PORT:-8080}/content-app/ -t 400000", + "start:docker": "./start.sh && npm run wait:app", + "stop:docker": "./start.sh -d", + "e2e:docker": "./start.sh && npm run e2e && ./start.sh -d", "spellcheck": "cspell '{src,e2e,projects}/**/*.ts'", "inspect.bundle": "ng build app --prod --stats-json && npx webpack-bundle-analyzer dist/app/stats.json", "format:check": "prettier --check \"src/{app,environments}/**/*.{ts,js,css,scss,html}\"", diff --git a/start.sh b/start.sh new file mode 100755 index 000000000..5037a6081 --- /dev/null +++ b/start.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +show_help() { + echo "Usage: ./start.sh" + echo "" + echo "-k or --keycloak if you want to use keycloak as identity provider" + echo "-d or --down delete all container" + echo "-hi or --host-ip set the host ip" + echo "-hp or --host-port set the host port. Default 8080" + echo "-w or --wait wait for backend. Default true" + echo "-h or --help" +} + +set_keycloak(){ + KEYCLOAK="true" +} + +down(){ + docker-compose down + exit 0 +} + +set_host_ip(){ + SET_HOST_IP=$1 +} + +set_host_port(){ + HOST_PORT=$1 +} + +set_wait(){ + WAIT=$1 +} + +# Defaults +WAIT="true" +SET_HOST_IP="" +HOST_PORT="8080" +KEYCLOAK="false" +AIMS_PROPS="" + +while [[ $1 == -* ]]; do + case "$1" in + -h|--help|-\?) show_help; exit 0;; + -k|--keycloak) set_keycloak; shift;; + -d|--down) down; shift;; + -w|--wait) set_wait $2; shift 2;; + -hi|--host-ip) set_host_ip $2; shift 2;; + -hp|--host-port) set_host_port $2; shift 2;; + -*) echo "invalid option: $1" 1>&2; show_help; exit 1;; + esac +done + +if [ -n "${SET_HOST_IP}" ];then + export HOST_IP=${SET_HOST_IP} +else + echo "No HOST_IP set, try to figure out on its own ..." + export HOST_IP=$(ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1) +fi +echo "HOST_IP: ${HOST_IP}" + +URL_FRAGMENT="content-app" +export APP_URL="http://${HOST_IP}:${HOST_PORT}/${URL_FRAGMENT}" +echo "Content Workspace: ${APP_URL}" + +if [[ $KEYCLOAK == "true" ]]; then + export APP_CONFIG_AUTH_TYPE="OAUTH" + export APP_CONFIG_OAUTH2_HOST="http://${HOST_IP}:8085/auth/realms/alfresco" + echo "Realm: ${APP_CONFIG_OAUTH2_HOST}" + export APP_CONFIG_OAUTH2_CLIENTID="alfresco" + export APP_CONFIG_OAUTH2_IMPLICIT_FLOW=true + export APP_CONFIG_OAUTH2_SILENT_LOGIN=true + export APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI="${APP_URL}assets/silent-refresh.html" + export APP_CONFIG_OAUTH2_REDIRECT_LOGIN="/$URL_FRAGMENT/" + export APP_CONFIG_OAUTH2_REDIRECT_LOGOUT="/$URL_FRAGMENT/logout" + # export APP_BASE_SHARE_URL="${APP_URL}#/preview/s" + + AIMS_PROPS="-Dauthentication.chain=identity-service1:identity-service,alfrescoNtlm1:alfrescoNtlm" +fi + +echo "Start docker compose" +export REGISTRY=${REGISTRY} +export SHARE_TAG=${SHARE_TAG:-latest} +export REPO_TAG=${REPO_TAG:-latest} +export AIMS_PROPS=${AIMS_PROPS} +docker-compose up -d --build + +if [[ $WAIT == "true" ]]; then + echo "http://${HOST_IP:-localhost}:${HOST_PORT:-8080}/$URL_FRAGMENT/" + echo "Waiting for the app ..." + HOST_IP=$HOST_IP HOST_PORT=$HOST_PORT npm run wait:app + if [ $? == 1 ]; then + echo "Waiting failed -> exit 1" + exit 1 + fi +fi From a5df1b36557b952959528c3b0ccfafc8ca04f341 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 2 Jan 2020 18:35:12 +0100 Subject: [PATCH 31/96] merge docker-compose.yaml and docker-compose-keycloak.yaml to one file. Implement start.sh for starting with and without SSO. --- start.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/start.sh b/start.sh index 5037a6081..34de17fc8 100755 --- a/start.sh +++ b/start.sh @@ -79,9 +79,6 @@ if [[ $KEYCLOAK == "true" ]]; then fi echo "Start docker compose" -export REGISTRY=${REGISTRY} -export SHARE_TAG=${SHARE_TAG:-latest} -export REPO_TAG=${REPO_TAG:-latest} export AIMS_PROPS=${AIMS_PROPS} docker-compose up -d --build From 55547ed163430b7cdfa1bab9374c9fca8d76b462 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 2 Jan 2020 20:17:59 +0200 Subject: [PATCH 32/96] [ACA-2850][ACA-2849] Viewer - document properties not refreshed after changes or uploading new version (#1286) * update viewer on upload complete * prevent multiple same actions triggers * Display node again after upload was complete * Add e2e test for showing 'Editing Offline' when a new version was uploaded and the node was locked before * Add e2e test for showing 'Editing Offline' when a new version was uploaded and the node was locked before * Add e2e test for showing 'Editing Offline' when a new version was uploaded and the node was locked before * Update src/app/components/page.component.ts return type Co-Authored-By: Denys Vuika * return type Co-Authored-By: Denys Vuika * return type Co-Authored-By: Denys Vuika Co-authored-by: Martin Muller Co-authored-by: Denys Vuika --- e2e/components/menu/menu.ts | 8 +++ e2e/suites/viewer/viewer-actions.test.ts | 23 +++++++++ src/app/components/page.component.spec.ts | 49 +++++++++++++++++-- src/app/components/page.component.ts | 8 +++ src/app/components/viewer/viewer.component.ts | 5 +- 5 files changed, 89 insertions(+), 4 deletions(-) diff --git a/e2e/components/menu/menu.ts b/e2e/components/menu/menu.ts index 408eedaaf..3397e1c58 100755 --- a/e2e/components/menu/menu.ts +++ b/e2e/components/menu/menu.ts @@ -351,6 +351,14 @@ export class Menu extends Component { return this.uploadFolderAction.isEnabled(); } + async isCancelEditingActionPresent(): Promise { + return this.cancelEditingAction.isPresent(); + } + + async isEditOfflineActionPresent(): Promise { + return this.editOfflineAction.isPresent(); + } + async clickCreateFolder() { const action = this.createFolderAction; diff --git a/e2e/suites/viewer/viewer-actions.test.ts b/e2e/suites/viewer/viewer-actions.test.ts index f295917a1..2b2ab8b91 100755 --- a/e2e/suites/viewer/viewer-actions.test.ts +++ b/e2e/suites/viewer/viewer-actions.test.ts @@ -74,6 +74,7 @@ describe('Viewer actions', () => { const fileForEditOffline = `file1-${Utils.random()}.docx`; let fileForEditOfflineId; const fileForCancelEditing = `file2-${Utils.random()}.docx`; let fileForCancelEditingId; const fileForUploadNewVersion = `file3-${Utils.random()}.docx`; let fileForUploadNewVersionId; + const fileForUploadNewVersion2 = `file4-${Utils.random()}.docx`; let fileForUploadNewVersionId2; beforeAll(async (done) => { parentId = (await apis.user.nodes.createFolder(parent)).entry.id; @@ -88,9 +89,11 @@ describe('Viewer actions', () => { fileForEditOfflineId = (await apis.user.upload.uploadFileWithRename(docxFile, parentId, fileForEditOffline)).entry.id; fileForCancelEditingId = (await apis.user.upload.uploadFileWithRename(docxFile, parentId, fileForCancelEditing)).entry.id; fileForUploadNewVersionId = (await apis.user.upload.uploadFileWithRename(docxFile, parentId, fileForUploadNewVersion)).entry.id; + fileForUploadNewVersionId2 = (await apis.user.upload.uploadFileWithRename(docxFile, parentId, fileForUploadNewVersion2)).entry.id; await apis.user.nodes.lockFile(fileForCancelEditingId); await apis.user.nodes.lockFile(fileForUploadNewVersionId); + await apis.user.nodes.lockFile(fileForUploadNewVersionId2); await loginPage.loginWith(username); @@ -221,6 +224,26 @@ describe('Viewer actions', () => { expect(await apis.user.nodes.getFileVersionLabel(filePersonalFilesId)).toEqual('2.0', 'File has incorrect version label'); }); + it('Upload new version action when node is locked - [MNT-21058]', async () => { + + await dataTable.doubleClickOnRowByName(fileForUploadNewVersion2); + await viewer.waitForViewerToOpen(); + + await toolbar.openMoreMenu(); + expect(await toolbar.menu.isCancelEditingActionPresent()).toBe(true, `'Cancel Editing' button should be shown`); + expect(await toolbar.menu.isEditOfflineActionPresent()).toBe(false, `'Edit Offline' shouldn't be shown`); + + await toolbar.menu.clickMenuItem('Upload New Version'); + await Utils.uploadFileNewVersion(docxFile); + await page.waitForDialog(); + + await uploadNewVersionDialog.clickUpload(); + + await toolbar.openMoreMenu(); + expect(await toolbar.menu.isCancelEditingActionPresent()).toBe(false, `'Cancel Editing' button shouldn't be shown`); + expect(await toolbar.menu.isEditOfflineActionPresent()).toBe(true, `'Edit Offline' should be shown`); + }); + it('Full screen action - [C279282]', async () => { await dataTable.doubleClickOnRowByName(docxPersonalFiles); await viewer.waitForViewerToOpen(); diff --git a/src/app/components/page.component.spec.ts b/src/app/components/page.component.spec.ts index b07b211f2..c6730ef44 100644 --- a/src/app/components/page.component.spec.ts +++ b/src/app/components/page.component.spec.ts @@ -24,20 +24,29 @@ */ import { PageComponent } from './page.component'; +import { + ReloadDocumentListAction, + SetSelectedNodesAction +} from '@alfresco/aca-shared/store'; +import { MinimalNodeEntity } from '@alfresco/js-api'; class TestClass extends PageComponent { node: any; - constructor() { - super(null, null, null); + constructor(store) { + super(store, null, null); } } describe('PageComponent', () => { let component: TestClass; + const store = { + dispatch: jasmine.createSpy('dispatch'), + select: jasmine.createSpy('select') + }; beforeEach(() => { - component = new TestClass(); + component = new TestClass(store); }); describe('getParentNodeId()', () => { @@ -53,4 +62,38 @@ describe('PageComponent', () => { expect(component.getParentNodeId()).toBe(null); }); }); + + describe('Reload', () => { + const locationHref = location.href; + + afterEach(() => { + window.history.pushState({}, null, locationHref); + }); + + it('should not reload if url contains viewer outlet', () => { + window.history.pushState({}, null, `${locationHref}#test(viewer:view)`); + component.reload(); + expect(store.dispatch).not.toHaveBeenCalled(); + }); + + it('should reload if url does not contain viewer outlet', () => { + component.reload(); + expect(store.dispatch).toHaveBeenCalledWith( + new ReloadDocumentListAction() + ); + }); + + it('should set selection after reload if node is passed', () => { + const node = { + entry: { + id: 'node-id' + } + } as MinimalNodeEntity; + + component.reload(node); + expect(store.dispatch['calls'].mostRecent().args[0]).toEqual( + new SetSelectedNodesAction([node]) + ); + }); + }); }); diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index 2dc13c691..5bce95d52 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -133,6 +133,10 @@ export abstract class PageComponent implements OnInit, OnDestroy { } reload(selectedNode?: MinimalNodeEntity): void { + if (this.isOutletPreviewUrl()) { + return; + } + this.store.dispatch(new ReloadDocumentListAction()); if (selectedNode) { this.store.dispatch(new SetSelectedNodesAction([selectedNode])); @@ -146,4 +150,8 @@ export abstract class PageComponent implements OnInit, OnDestroy { trackById(_: number, obj: { id: string }) { return obj.id; } + + private isOutletPreviewUrl(): boolean { + return location.href.includes('viewer:view'); + } } diff --git a/src/app/components/viewer/viewer.component.ts b/src/app/components/viewer/viewer.component.ts index 46d62e8e0..ecf982e66 100644 --- a/src/app/components/viewer/viewer.component.ts +++ b/src/app/components/viewer/viewer.component.ts @@ -188,7 +188,10 @@ export class AppViewerComponent implements OnInit, OnDestroy { debounceTime(300), takeUntil(this.onDestroy$) ) - .subscribe(file => this.apiService.nodeUpdated.next(file.data.entry)); + .subscribe(file => { + this.apiService.nodeUpdated.next(file.data.entry); + this.displayNode(file.data.entry.id); + }); this.previewLocation = this.router.url .substr(0, this.router.url.indexOf('/', 1)) From 2fc8cd4429a3da7edd599d3604a704776a8dd27e Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 2 Jan 2020 21:42:01 +0100 Subject: [PATCH 33/96] merge docker-compose.yaml and docker-compose-keycloak.yaml to one file. Implement start.sh for starting with and without SSO. --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index b2e942dca..8eb77ff1e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -150,7 +150,7 @@ services: APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI: ${APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI} APP_CONFIG_OAUTH2_REDIRECT_LOGIN: ${APP_CONFIG_OAUTH2_REDIRECT_LOGIN} APP_CONFIG_OAUTH2_REDIRECT_LOGOUT: ${APP_CONFIG_OAUTH2_REDIRECT_LOGOUT} - APP_BASE_SHARE_URL: '{protocol}//{hostname}{:port}/workspace/#/preview/s' + APP_BASE_SHARE_URL: '{protocol}//{hostname}{:port}/content-app/#/preview/s' ports: - 4001:8080 From 03bb0b139fe72ef8d287fa97d024667d79f4f2af Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Sun, 5 Jan 2020 18:58:07 +0200 Subject: [PATCH 34/96] add components for search filters and search sorting --- .../search/filters/created-date-filter.ts | 137 +++++++++++++++++ e2e/components/search/filters/facet-filter.ts | 94 ++++++++++++ .../search/filters/generic-filter-panel.ts | 71 +++++++++ e2e/components/search/filters/size-filter.ts | 92 ++++++++++++ e2e/components/search/search-filters.ts | 60 ++++++++ e2e/components/search/search-input.ts | 16 +- .../search/search-sorting-picker.ts | 141 ++++++++++++++++++ e2e/pages/search-results-page.ts | 55 ++++--- 8 files changed, 641 insertions(+), 25 deletions(-) create mode 100755 e2e/components/search/filters/created-date-filter.ts create mode 100755 e2e/components/search/filters/facet-filter.ts create mode 100755 e2e/components/search/filters/generic-filter-panel.ts create mode 100755 e2e/components/search/filters/size-filter.ts create mode 100755 e2e/components/search/search-filters.ts create mode 100755 e2e/components/search/search-sorting-picker.ts diff --git a/e2e/components/search/filters/created-date-filter.ts b/e2e/components/search/filters/created-date-filter.ts new file mode 100755 index 000000000..03d50f3ee --- /dev/null +++ b/e2e/components/search/filters/created-date-filter.ts @@ -0,0 +1,137 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, by, protractor } from 'protractor'; +import { GenericFilterPanel } from './generic-filter-panel'; +import { Utils } from '../../../utilities/utils'; + +export class CreatedDateFilter extends GenericFilterPanel { + constructor() { + super('Created date'); + } + + fromField: ElementFinder = this.panelExpanded.element(by.cssContainingText('.adf-search-date-range .mat-form-field', 'From')); + fromInput: ElementFinder = this.fromField.element(by.css(`[data-automation-id='date-range-from-input']`)); + fromFieldError: ElementFinder = this.fromField.element(by.css(`[data-automation-id='date-range-from-error']`)); + toField: ElementFinder = this.panelExpanded.element(by.cssContainingText('.adf-search-date-range .mat-form-field', 'To')); + toInput: ElementFinder = this.toField.element(by.css(`[data-automation-id='date-range-to-input']`)) + toFieldError: ElementFinder = this.toField.element(by.css(`[data-automation-id='date-range-to-error']`)) + clearButton: ElementFinder = this.panel.element(by.css('.adf-facet-buttons [data-automation-id="date-range-clear-btn"]')); + applyButton: ElementFinder = this.panel.element(by.css('.adf-facet-buttons [data-automation-id="date-range-apply-btn"]')); + + async isFromFieldDisplayed(): Promise { + return (await this.fromField.isPresent()) && (await this.fromField.isDisplayed()); + } + + async isFromErrorDisplayed(): Promise { + return (await this.fromFieldError.isPresent()) && (await this.fromFieldError.isDisplayed()); + } + + async isToFieldDisplayed(): Promise { + return (await this.toField.isPresent()) && (await this.toField.isDisplayed()); + } + + async isToErrorDisplayed(): Promise { + return (await this.toFieldError.isPresent()) && (await this.toFieldError.isDisplayed()); + } + + async isClearButtonEnabled(): Promise { + return await this.clearButton.isEnabled(); + } + + async isApplyButtonEnabled(): Promise { + return await this.applyButton.isEnabled(); + } + + async clickClearButton(): Promise { + if ( await this.isClearButtonEnabled() ) { + await this.clearButton.click(); + } + } + + async clickApplyButton(): Promise { + if ( await this.isApplyButtonEnabled() ) { + await this.applyButton.click(); + } + } + + async getFromValue(): Promise { + try { + const value = await this.fromInput.getAttribute('value'); + return value; + } catch (error) { + return ''; + } + } + + async getFromError(): Promise { + try { + const error = await this.fromFieldError.getText(); + return error; + } catch (err) { + return ''; + } + } + + async getToValue(): Promise { + try { + const value = await this.toInput.getAttribute('value'); + return value; + } catch (err) { + return ''; + } + } + + async getToError(): Promise { + try { + const error = await this.toFieldError.getText(); + return error; + } catch (err) { + return ''; + } + } + + async resetPanel(): Promise { + const fromValue = await this.getFromValue(); + const toValue = await this.getToValue(); + if ( fromValue.length > 0 || toValue.length > 0 ) { + await this.expandPanel(); + await this.clickClearButton(); + await this.collapsePanel(); + } + } + + async enterFromDate(date: string): Promise { + await this.expandPanel(); + await Utils.clearFieldWithBackspace(this.fromInput); + await this.fromInput.sendKeys(date, protractor.Key.TAB); + } + + async enterToDate(date: string): Promise { + await this.expandPanel(); + await Utils.clearFieldWithBackspace(this.toInput); + await this.toInput.sendKeys(date, protractor.Key.TAB); + } +} diff --git a/e2e/components/search/filters/facet-filter.ts b/e2e/components/search/filters/facet-filter.ts new file mode 100755 index 000000000..942524e9c --- /dev/null +++ b/e2e/components/search/filters/facet-filter.ts @@ -0,0 +1,94 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, ElementArrayFinder, by } from 'protractor'; +import { GenericFilterPanel } from './generic-filter-panel'; + +export class FacetFilter extends GenericFilterPanel { + private readonly locators = { + checkbox: '.mat-checkbox', + checkboxChecked: '.mat-checkbox.mat-checkbox-checked', + button: '.adf-facet-buttons button', + categoryInput: 'input[placeholder="Filter category"', + facetsFilter: '.adf-facet-result-filter' + } + + get facets(): ElementArrayFinder { return this.panelExpanded.all(by.css(this.locators.checkbox)); } + get selectedFacets(): ElementArrayFinder { return this.panel.all(by.css(this.locators.checkboxChecked)); } + get clearButton(): ElementFinder { return this.panel.element(by.cssContainingText(this.locators.button, 'Clear all')); } + get facetsFilter(): ElementFinder { return this.panelExpanded.element(by.css(this.locators.facetsFilter)); } + get filterCategoryInput(): ElementFinder { return this.facetsFilter.element(by.css(this.locators.categoryInput)); } + + async getFiltersValues(): Promise { + const list: string[] = await this.facets.map(option => { + return option.getText(); + }); + return list; + } + + async getFiltersCheckedValues(): Promise { + const list: string[] = await this.selectedFacets.map(option => { + return option.getText(); + }); + return list; + } + + async resetPanel(): Promise { + if ( (await this.selectedFacets.count()) > 0 ) { + await this.expandPanel(); + await this.selectedFacets.each(async elem => { + await elem.click(); + }); + } + await this.expandPanel(); + } + + async isFilterFacetsDisplayed(): Promise { + return await this.facetsFilter.isDisplayed(); + } + + async isClearButtonEnabled(): Promise { + return await this.clearButton.isEnabled(); + } + + async clickClearButton(): Promise { + if ( await this.isClearButtonEnabled() ) { + await this.clearButton.click(); + } + } + + async isFilterCategoryInputDisplayed(): Promise { + return await this.filterCategoryInput.isDisplayed(); + } + + async checkCategory(name: string): Promise { + const option = this.facets.filter(async (elem) => (await elem.getText()).includes(name)).first(); + await option.click(); + } + + async filterCategoriesBy(name: string): Promise { + await this.filterCategoryInput.sendKeys(name); + } +} diff --git a/e2e/components/search/filters/generic-filter-panel.ts b/e2e/components/search/filters/generic-filter-panel.ts new file mode 100755 index 000000000..ad74b8afe --- /dev/null +++ b/e2e/components/search/filters/generic-filter-panel.ts @@ -0,0 +1,71 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, by, browser } from 'protractor'; + +export class GenericFilterPanel { + private filterName: string; + + constructor(filterName: string) { + this.filterName = filterName; + } + + private readonly selectors = { + root: 'adf-search-filter', + + panel: '.mat-expansion-panel', + panelExpanded: '.mat-expansion-panel.mat-expanded', + panelHeader: '.mat-expansion-panel-header' + } + + get panel(): ElementFinder { return browser.element(by.cssContainingText(this.selectors.panel, this.filterName)); } + get panelExpanded(): ElementFinder { return browser.element(by.cssContainingText(this.selectors.panelExpanded, this.filterName)); } + get panelHeader(): ElementFinder { return this.panel.element(by.css(this.selectors.panelHeader)); } + + async clickPanelHeader(): Promise { + await this.panelHeader.click(); + } + + async isPanelDisplayed(): Promise { + return (await browser.isElementPresent(this.panel)) && (await this.panel.isDisplayed()); + } + + async isPanelExpanded(): Promise { + return (await this.panelExpanded.isPresent()) && (await this.panelExpanded.isDisplayed()); + } + + async expandPanel(): Promise { + if ( !(await this.isPanelExpanded()) ) { + await this.clickPanelHeader(); + } + } + + async collapsePanel(): Promise { + if ( await this.isPanelExpanded() ) { + await this.clickPanelHeader(); + } + } + +} diff --git a/e2e/components/search/filters/size-filter.ts b/e2e/components/search/filters/size-filter.ts new file mode 100755 index 000000000..76bc477b9 --- /dev/null +++ b/e2e/components/search/filters/size-filter.ts @@ -0,0 +1,92 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, by, ElementArrayFinder } from 'protractor'; +import { GenericFilterPanel } from './generic-filter-panel'; + +export class SizeFilter extends GenericFilterPanel { + constructor() { + super('Size'); + } + + facets: ElementArrayFinder = this.panelExpanded.all(by.css('.mat-checkbox')); + selectedFacets: ElementArrayFinder = this.panel.all(by.css('.mat-checkbox.mat-checkbox-checked')); + clearButton: ElementFinder = this.panel.element(by.cssContainingText('.adf-facet-buttons button', 'Clear all')); + + async getFiltersValues(): Promise { + const list: string[] = await this.facets.map(option => { + return option.getText(); + }); + return list; + } + + async getFiltersCheckedValues(): Promise { + const list: string[] = await this.selectedFacets.map(option => { + return option.getText(); + }); + return list; + } + + async resetPanel(): Promise { + if ( (await this.selectedFacets.count()) > 0 ) { + await this.expandPanel(); + await this.selectedFacets.each(async elem => { + await elem.click(); + }); + } + await this.collapsePanel(); + } + + async isClearButtonEnabled(): Promise { + return await this.clearButton.isEnabled(); + } + + async clickClearButton(): Promise { + if ( await this.isClearButtonEnabled() ) { + await this.clearButton.click(); + } + } + + async checkSizeSmall(): Promise { + const small = this.facets.filter(async (elem) => await elem.getText() === 'Small').first(); + await small.click(); + } + + async checkSizeMedium(): Promise { + const medium = this.facets.filter(async (elem) => await elem.getText() === 'Medium').first(); + await medium.click(); + } + + async checkSizeLarge(): Promise { + const large = this.facets.filter(async (elem) => await elem.getText() === 'Large').first(); + await large.click(); + } + + async checkSizeHuge(): Promise { + const huge = this.facets.filter(async (elem) => await elem.getText() === 'Huge').first(); + await huge.click(); + } + +} diff --git a/e2e/components/search/search-filters.ts b/e2e/components/search/search-filters.ts new file mode 100755 index 000000000..ffda3151c --- /dev/null +++ b/e2e/components/search/search-filters.ts @@ -0,0 +1,60 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, by, browser } from 'protractor'; +import { Component } from '../component'; +import { SizeFilter } from './filters/size-filter'; +import { CreatedDateFilter } from './filters/created-date-filter'; +import { FacetFilter } from './filters/facet-filter'; + +export class SearchFilters extends Component { + private static selectors = { + root: 'adf-search-filter', + }; + + mainPanel: ElementFinder = browser.element(by.css(SearchFilters.selectors.root)); + resetAllButton: ElementFinder = this.component.element(by.cssContainingText('.mat-button', 'Reset all')); + + size = new SizeFilter(); + createdDate = new CreatedDateFilter(); + fileType = new FacetFilter('File type'); + creator = new FacetFilter('Creator'); + modifier = new FacetFilter('Modifier'); + location = new FacetFilter('Location'); + modifiedDate = new FacetFilter('Modified date'); + + constructor(ancestor?: ElementFinder) { + super(SearchFilters.selectors.root, ancestor); + } + + async isSearchFiltersPanelDisplayed(): Promise { + return (await this.mainPanel.isPresent()) && (await this.mainPanel.isDisplayed()); + } + + async clickResetAllButton(): Promise { + await this.resetAllButton.click(); + } + +} diff --git a/e2e/components/search/search-input.ts b/e2e/components/search/search-input.ts index 091cb5046..b2f18529d 100755 --- a/e2e/components/search/search-input.ts +++ b/e2e/components/search/search-input.ts @@ -34,7 +34,7 @@ export class SearchInput extends Component { searchContainer: '.app-search-container', searchButton: '.app-search-button', searchControl: '.app-search-control', - searchInput: 'app-control-input', + searchInput: `input[id='app-control-input']`, searchOptionsArea: 'search-options', optionCheckbox: '.mat-checkbox', clearButton: '.app-clear-icon' @@ -43,7 +43,7 @@ export class SearchInput extends Component { searchButton: ElementFinder = this.component.element(by.css(SearchInput.selectors.searchButton)); searchContainer: ElementFinder = browser.element(by.css(SearchInput.selectors.searchContainer)); searchControl: ElementFinder = browser.element(by.css(SearchInput.selectors.searchControl)); - searchBar: ElementFinder = browser.element(by.id(SearchInput.selectors.searchInput)); + searchInput: ElementFinder = browser.element(by.css(SearchInput.selectors.searchInput)); searchOptionsArea: ElementFinder = browser.element(by.id(SearchInput.selectors.searchOptionsArea)); searchFilesOption: ElementFinder = this.searchOptionsArea.element(by.cssContainingText(SearchInput.selectors.optionCheckbox, 'Files')); searchFoldersOption: ElementFinder = this.searchOptionsArea.element(by.cssContainingText(SearchInput.selectors.optionCheckbox, 'Folders')); @@ -58,6 +58,10 @@ export class SearchInput extends Component { await browser.wait(EC.presenceOf(this.searchControl), BROWSER_WAIT_TIMEOUT, '--- timeout waitForSearchControl ---'); } + async waitForSearchInputToBeInteractive() { + await browser.wait(EC.elementToBeClickable(this.searchControl), BROWSER_WAIT_TIMEOUT, '--- timeout waitForSearchControl ---'); + } + async isSearchContainerDisplayed() { return (await this.searchContainer.isDisplayed()) && (await this.searchButton.isDisplayed()); } @@ -162,9 +166,9 @@ export class SearchInput extends Component { } async searchFor(text: string) { - await browser.wait(EC.elementToBeClickable(this.searchBar), BROWSER_WAIT_TIMEOUT, '---- timeout waiting for searchBar to be clickable'); - await this.searchBar.clear(); - await this.searchBar.sendKeys(text); - await this.searchBar.sendKeys(protractor.Key.ENTER); + await this.waitForSearchInputToBeInteractive(); + await Utils.clearFieldWithBackspace(this.searchInput); + await this.searchInput.sendKeys(text); + await this.searchInput.sendKeys(protractor.Key.ENTER); } } diff --git a/e2e/components/search/search-sorting-picker.ts b/e2e/components/search/search-sorting-picker.ts new file mode 100755 index 000000000..e274a95e3 --- /dev/null +++ b/e2e/components/search/search-sorting-picker.ts @@ -0,0 +1,141 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, by, browser, ExpectedConditions as EC, ElementArrayFinder } from 'protractor'; +import { BROWSER_WAIT_TIMEOUT } from '../../configs'; +import { Component } from '../component'; + +export class SearchSortingPicker extends Component { + private static selectors = { + root: 'adf-search-sorting-picker', + + sortByOption: '.mat-option .mat-option-text' + }; + + sortOrderButton: ElementFinder = this.component.element(by.css('button[mat-icon-button]')); + sortByDropdownCollapsed: ElementFinder = this.component.element(by.css('.mat-select')); + sortByDropdownExpanded: ElementFinder = browser.element(by.css('.mat-select-panel')); + sortByList: ElementArrayFinder = this.sortByDropdownExpanded.all(by.css(SearchSortingPicker.selectors.sortByOption)); + + constructor(ancestor?: ElementFinder) { + super(SearchSortingPicker.selectors.root, ancestor); + } + + async waitForSortByDropdownToExpand(): Promise { + await browser.wait(EC.visibilityOf(this.sortByDropdownExpanded), BROWSER_WAIT_TIMEOUT, 'Timeout waiting for sortBy dropdown to expand'); + } + + async isSortOrderButtonDisplayed(): Promise { + return (await this.sortOrderButton.isPresent()) && (await this.sortOrderButton.isDisplayed()); + } + + async getSortOrder(): Promise<'ASC' | 'DESC' | ''> { + const orderArrow = await this.sortOrderButton.getText(); + + if ( orderArrow.includes('upward') ) { + return 'ASC' + } else if ( orderArrow.includes('downward') ) { + return 'DESC' + } else { + return ''; + } + } + + async isSortByOptionDisplayed(): Promise { + return (await this.sortByDropdownCollapsed.isPresent()) && (await this.sortByDropdownCollapsed.isDisplayed()); + } + + async isSortByDropdownExpanded(): Promise { + return (await this.sortByDropdownExpanded.isPresent()) && (await this.sortByDropdownExpanded.isDisplayed()); + } + + async getSelectedSortByOption(): Promise { + return await this.sortByDropdownCollapsed.getText(); + } + + async clickSortByDropdown(): Promise { + await this.sortByDropdownCollapsed.click(); + await this.waitForSortByDropdownToExpand(); + } + + async getSortByOptionsList(): Promise { + const list: string[] = await this.sortByList.map(async option => { + return option.getText(); + }); + return list; + } + + async sortByOption(option: string): Promise { + if ( !(await this.isSortByDropdownExpanded()) ) { + await this.clickSortByDropdown(); + } + const elem = browser.element(by.cssContainingText(SearchSortingPicker.selectors.sortByOption, option)); + await elem.click(); + } + + async sortByName(): Promise { + await this.sortByOption('Filename'); + } + + async sortByRelevance(): Promise { + await this.sortByOption('Relevance'); + } + + async sortByTitle(): Promise { + await this.sortByOption('Title'); + } + + async sortByModifiedDate(): Promise { + await this.sortByOption('Modified date'); + } + + async sortByModifier(): Promise { + await this.sortByOption('Modifier'); + } + + async sortByCreatedDate(): Promise { + await this.sortByOption('Created date'); + } + + async sortBySize(): Promise { + await this.sortByOption('Size'); + } + + async sortByType(): Promise { + await this.sortByOption('Type'); + } + + async setSortOrderASC(): Promise { + if ( (await this.getSortOrder()) !== 'ASC' ) { + await this.sortOrderButton.click(); + } + } + + async setSortOrderDESC(): Promise { + if ( (await this.getSortOrder()) !== 'DESC' ) { + await this.sortOrderButton.click(); + } + } +} diff --git a/e2e/pages/search-results-page.ts b/e2e/pages/search-results-page.ts index f45bb32aa..ba75bbf41 100755 --- a/e2e/pages/search-results-page.ts +++ b/e2e/pages/search-results-page.ts @@ -23,37 +23,54 @@ * along with Alfresco. If not, see . */ -import { browser, by } from 'protractor'; +import { browser, by, By, ElementFinder, ElementArrayFinder } from 'protractor'; import { BrowsingPage } from './browsing-page'; +import { SearchSortingPicker } from '../components/search/search-sorting-picker'; +import { SearchFilters } from '../components/search/search-filters'; export class SearchResultsPage extends BrowsingPage { private static selectors = { root: 'aca-search-results', - filter: 'adf-search-filter', - expansionPanel: 'mat-expansion-panel', - size: '#expansion-panel-SEARCH.CATEGORIES.SIZE', - createdDate: '#expansion-panel-SEARCH.CATEGORIES.CREATED_DATE', - modifiedDate: '#expansion-panel-SEARCH.CATEGORIES.MODIFIED_DATE', - fileType: '#expansion-panel-SEARCH.FACET_FIELDS.FILE_TYPE', - creator: '#expansion-panel-SEARCH.CATEGORIES.CREATOR', - modifier: '#expansion-panel-SEARCH.CATEGORIES.MODIFIER', - location: '#expansion-panel-SEARCH.CATEGORIES.LOCATION', - - resultsContent: 'adf-search-results__content', resultsContentHeader: '.adf-search-results__content-header', - resultsInfoText: 'adf-search-results--info-text', - resultsFacets: 'adf-search-results__facets', - - sortingPicker: 'adf-sorting-picker' + infoText: '.adf-search-results--info-text', + chipList: '.adf-search-chip-list', + chip: '.mat-chip', + chipCloseIcon: '.mat-chip-remove' }; - async waitForResults() { + root: ElementFinder = browser.element(by.css(SearchResultsPage.selectors.root)); + chipList: ElementFinder = this.root.element(by.css(SearchResultsPage.selectors.chipList)); + infoText: ElementFinder = this.root.element(by.css(SearchResultsPage.selectors.infoText)); + + sortingPicker = new SearchSortingPicker(this.root); + filters = new SearchFilters(this.root); + + async waitForResults(): Promise { await this.dataTable.waitForBody(); } - async getResultsHeader() { - return browser.element(by.css(SearchResultsPage.selectors.resultsContentHeader)).getText(); + async getResultsHeader(): Promise { + return await browser.element(by.css(SearchResultsPage.selectors.resultsContentHeader)).getText(); + } + + async getResultsFoundText(): Promise { + return await this.infoText.getText(); + } + + async getResultsChipsValues(): Promise { + const chips: ElementArrayFinder = this.chipList.all(by.css(SearchResultsPage.selectors.chip)); + const chipsValues: string[] = await chips.map(async elem => { + return (await elem.getText()).replace(`\ncancel`, ''); + }); + return chipsValues; + } + + async removeChip(chipName: string): Promise { + const chip: ElementFinder = browser.element(By.cssContainingText(SearchResultsPage.selectors.chip, chipName)); + const closeChip: ElementFinder = chip.element(by.css(SearchResultsPage.selectors.chipCloseIcon)); + + await closeChip.click(); } } From e27a517ad7e26362d29ca450db9f4f35bb6fb961 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Sun, 5 Jan 2020 19:00:19 +0200 Subject: [PATCH 35/96] automate tests for search filters and search results sorting --- e2e/components/data-table/data-table.ts | 8 + e2e/suites/list-views/empty-list.test.ts | 13 +- e2e/suites/search/search-filters.test.ts | 600 ++++++++++++++++++ e2e/suites/search/search-input.test.ts | 14 +- .../search-results-files-folders.test.ts | 107 +--- .../search/search-results-libraries.test.ts | 1 - e2e/suites/search/search-sorting.test.ts | 202 ++++++ .../repo-client/apis/upload/upload-api.ts | 11 +- e2e/utilities/utils.ts | 7 + 9 files changed, 869 insertions(+), 94 deletions(-) create mode 100644 e2e/suites/search/search-filters.test.ts create mode 100644 e2e/suites/search/search-sorting.test.ts diff --git a/e2e/components/data-table/data-table.ts b/e2e/components/data-table/data-table.ts index 19f244641..69395b507 100755 --- a/e2e/components/data-table/data-table.ts +++ b/e2e/components/data-table/data-table.ts @@ -409,6 +409,14 @@ export class DataTable extends Component { }, {}); } + getSearchResultsRows(): ElementArrayFinder { + return this.body.all(by.css(DataTable.selectors.searchResultsRow)); + } + + getNthSearchResultsRow(nth: number): ElementFinder { + return this.getSearchResultsRows().get(nth - 1); + } + getSearchResultsRowByName(name: string, location: string = '') { if (location) { return this.body.all(by.cssContainingText(DataTable.selectors.searchResultsRow, name)) diff --git a/e2e/suites/list-views/empty-list.test.ts b/e2e/suites/list-views/empty-list.test.ts index 93ecafd09..7c06ebdb0 100755 --- a/e2e/suites/list-views/empty-list.test.ts +++ b/e2e/suites/list-views/empty-list.test.ts @@ -23,7 +23,7 @@ * along with Alfresco. If not, see . */ -import { LoginPage, BrowsingPage } from '../../pages/pages'; +import { LoginPage, BrowsingPage, SearchResultsPage } from '../../pages/pages'; import { Utils } from '../../utilities/utils'; import { RepoClient } from '../../utilities/repo-client/repo-client'; @@ -38,6 +38,7 @@ describe('Empty list views', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); + const searchResultsPage = new SearchResultsPage(); const { dataTable, pagination } = page; const { searchInput } = page.header; @@ -168,7 +169,6 @@ describe('Empty list views', () => { it('Search results - pagination controls not displayed - [C290123]', async () => { await searchInput.clickSearchButton(); - await searchInput.checkOnlyFiles(); /* cspell:disable-next-line */ await searchInput.searchFor('qwertyuiop'); await dataTable.waitForBody(); @@ -181,6 +181,15 @@ describe('Empty list views', () => { expect(await pagination.isNextButtonPresent()).toBe(false, 'Next button is present'); }); + it('Search filters panel is not displayed on empty Search Results page - [C279189]', async () => { + await searchInput.clickSearchButton(); + /* cspell:disable-next-line */ + await searchInput.searchFor('qwertyuiop'); + await dataTable.waitForBody(); + + expect(await searchResultsPage.filters.isSearchFiltersPanelDisplayed()).toBe(false, 'Search filters panel is present'); + }); + it('Empty Search results - Libraries - [C290020]', async () => { await searchInput.clickSearchButton(); await searchInput.checkLibraries(); diff --git a/e2e/suites/search/search-filters.test.ts b/e2e/suites/search/search-filters.test.ts new file mode 100644 index 000000000..4b471519c --- /dev/null +++ b/e2e/suites/search/search-filters.test.ts @@ -0,0 +1,600 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { LoginPage, SearchResultsPage } from '../../pages/pages'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; +import { Utils } from '../../utilities/utils'; +import { FILES, SITE_VISIBILITY, SITE_ROLES } from '../../configs'; +import * as moment from 'moment'; + +fdescribe('Search filters', () => { + const random = Utils.random(); + + const user1 = `user1-${random}`; + const user2 = `user2-${random}`; + + const parent = `parent-${random}`; + let parentId: string; + + const site = `site-${Utils.random()}`; let docLibId; + + const fileJpg = { + name: `search-filters-file-1-${random}.jpg`, + source: FILES.jpgFile + }; + + const filePdf = { + name: `search-filters-file-2-${random}.pdf`, + title: 'search filters title', + description: 'search filters', + source: FILES.pdfFile + }; + + const expectedFileTypes = ['Adobe PDF Document (1)', 'JPEG Image (1)']; + const expectedCreators = [`${user1} ${user1} (1)`, `${user2} ${user2} (1)`]; + const expectedModifiers = [`${user1} ${user1} (1)`, `${user2} ${user2} (1)`]; + const expectedLocations = ['_REPOSITORY_ (1)', `${site} (1)`]; + + const apis = { + admin: new RepoClient(), + user1: new RepoClient(user1, user1), + user2: new RepoClient(user2, user2) + }; + + const loginPage = new LoginPage(); + const page = new SearchResultsPage(); + const { searchInput } = page.header; + const { dataTable, filters } = page; + + const sizeFilter = filters.size; + const fileTypeFilter = filters.fileType; + const createdDateFilter = filters.createdDate; + const creatorFilter = filters.creator; + const locationFilter = filters.location; + const modifierFilter = filters.modifier; + const modifiedDateFilter = filters.modifiedDate; + + beforeAll(async (done) => { + await apis.admin.people.createUser({ username: user1 }); + await apis.admin.people.createUser({ username: user2 }); + parentId = (await apis.user1.nodes.createFolder(parent)).entry.id; + await apis.user1.sites.createSite(site, SITE_VISIBILITY.PUBLIC); + await apis.user1.sites.addSiteMember(site, user2, SITE_ROLES.SITE_MANAGER.ROLE); + docLibId = await apis.admin.sites.getDocLibId(site); + + await apis.user1.nodes.setGranularPermission(parentId, true, user2, 'Collaborator'); + + await apis.user1.upload.uploadFileWithRename(fileJpg.source, docLibId, fileJpg.name); + await apis.user2.upload.uploadFileWithRename(filePdf.source, parentId, filePdf.name, filePdf.title, filePdf.description); + + await apis.user1.search.waitForNodes('search-filters', { expect: 2 }); + + await loginPage.loginWith(user1); + done(); + }); + + beforeEach(async (done) => { + await Utils.pressEscape(); + await page.clickPersonalFilesAndWait(); + + await searchInput.clickSearchButton(); + await searchInput.searchFor('search filters'); + await dataTable.waitForBody(); + done(); + }); + + afterAll(async (done) => { + await Promise.all([ + apis.user1.nodes.deleteNodeById(parentId), + apis.user1.sites.deleteSite(site) + ]); + done(); + }); + + it('Filters are displayed - [C279186]', async () => { + expect(await sizeFilter.isPanelDisplayed()).toBe(true, 'Size filter panel not displayed'); + expect(await createdDateFilter.isPanelDisplayed()).toBe(true, 'Created date filter panel not displayed'); + expect(await fileTypeFilter.isPanelDisplayed()).toBe(true, 'File type filter panel not displayed'); + expect(await creatorFilter.isPanelDisplayed()).toBe(true, 'Creator filter panel not displayed'); + expect(await modifierFilter.isPanelDisplayed()).toBe(true, 'Modifier filter panel not displayed'); + expect(await locationFilter.isPanelDisplayed()).toBe(true, 'Location filter panel not displayed'); + expect(await modifiedDateFilter.isPanelDisplayed()).toBe(true, 'Modified date filter panel not displayed'); + }); + + describe('Filter by Size', () => { + afterEach(async (done) => { + await sizeFilter.resetPanel(); + done(); + }); + + it('Expand / Collapse the Size filter panel - [C279197]', async () => { + expect(await sizeFilter.isPanelExpanded()).toBe(false, 'Size filter panel is expanded'); + + await sizeFilter.expandPanel(); + expect(await sizeFilter.isPanelExpanded()).toBe(true, 'Size filter panel not expanded'); + + const expectedSizes = ['Small', 'Medium', 'Large', 'Huge']; + expect(await sizeFilter.getFiltersValues()).toEqual(expectedSizes, 'Incorrect Size filters facets'); + expect(await sizeFilter.isClearButtonEnabled()).toBe(true, 'Size filter Clear button not enabled'); + + await sizeFilter.collapsePanel(); + expect(await sizeFilter.isPanelExpanded()).toBe(false, 'Size filter panel is expanded'); + }); + + it('Filter by Small - [C279199]', async () => { + await sizeFilter.expandPanel(); + await sizeFilter.checkSizeSmall(); + + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, `${fileJpg.name} not in the list`); + expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, `${filePdf.name} not in the list`); + }); + + it('Filter by Huge - [C279202]', async () => { + await sizeFilter.expandPanel(); + await sizeFilter.checkSizeHuge(); + + expect(await dataTable.isEmptyList()).toBe(true, 'list is not empty'); + }); + + it('Filter by multiple size categories - [C279203]', async () => { + await sizeFilter.expandPanel(); + await sizeFilter.checkSizeSmall(); + await sizeFilter.checkSizeMedium(); + await sizeFilter.checkSizeLarge(); + + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, `${fileJpg.name} not in the list`); + expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, `${filePdf.name} not in the list`); + }); + + it('Clear the Size filter options - [C279198]', async () => { + await sizeFilter.expandPanel(); + await sizeFilter.checkSizeSmall(); + await sizeFilter.checkSizeMedium(); + expect(await sizeFilter.getFiltersCheckedValues()).toEqual(['Small', 'Medium'], 'Incorrect checked Size filters'); + + await sizeFilter.clickClearButton(); + expect(await sizeFilter.getFiltersCheckedValues()).toEqual([], 'Size filters not cleared'); + }); + }); + + describe('Filter by Created date', () => { + const yesterday = moment().subtract(1, 'day').format('DD-MMM-YY'); + const today = moment().format('DD-MMM-YY'); + const future = moment().add(1, 'month').format('DD-MMM-YY'); + + afterEach(async (done) => { + await createdDateFilter.resetPanel(); + done(); + }); + + it('Expand / Collapse the Created date filter panel - [C279211]', async () => { + expect(await createdDateFilter.isPanelExpanded()).toBe(false, 'Created date filter panel is expanded'); + + await createdDateFilter.expandPanel(); + expect(await createdDateFilter.isPanelExpanded()).toBe(true, 'Created date filter panel not expanded'); + + expect(await createdDateFilter.isClearButtonEnabled()).toBe(true, 'Created date CLEAR button not enabled'); + expect(await createdDateFilter.isApplyButtonEnabled()).toBe(false, 'Created date APPLY button not disabled'); + + await createdDateFilter.collapsePanel(); + expect(await createdDateFilter.isPanelExpanded()).toBe(false, 'Created date filter panel is expanded'); + }); + + it('Results are filtered by Created date - [C279217]', async () => { + await createdDateFilter.enterFromDate(yesterday); + await createdDateFilter.enterToDate(yesterday); + + expect(await createdDateFilter.isApplyButtonEnabled()).toBe(true, 'Created date filter Apply button not enabled'); + + await createdDateFilter.clickApplyButton(); + + expect(await dataTable.isItemPresent(filePdf.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(false, 'JPG file is displayed'); + + await createdDateFilter.enterFromDate(yesterday); + await createdDateFilter.enterToDate(today); + + expect(await createdDateFilter.isApplyButtonEnabled()).toBe(true, 'Created date filter Apply button not enabled'); + + await createdDateFilter.clickApplyButton(); + + expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + }); + + it('Clear the Created date filter options - [C279216]', async () => { + await createdDateFilter.enterFromDate(yesterday); + await createdDateFilter.enterToDate(yesterday); + await createdDateFilter.clickApplyButton(); + + expect(await createdDateFilter.getFromValue()).toContain(yesterday); + expect(await createdDateFilter.getToValue()).toContain(yesterday); + + await createdDateFilter.clickClearButton(); + + expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file is displayed'); + expect(await createdDateFilter.getFromValue()).toEqual('', 'From field not empty'); + expect(await createdDateFilter.getToValue()).toEqual('', 'To field not empty'); + }); + + it('From and To values are required - [C279212]', async () => { + await createdDateFilter.enterFromDate(''); + await createdDateFilter.enterToDate(''); + + expect(await createdDateFilter.isFromErrorDisplayed()).toBe(true, 'Error missing for From field'); + expect(await createdDateFilter.isToErrorDisplayed()).toBe(true, 'Error missing for To field'); + expect(await createdDateFilter.getFromError()).toEqual('Required value'); + expect(await createdDateFilter.getToError()).toEqual('Required value'); + }); + + it('Error message is displayed when entering an incorrect date format - [C279213]', async () => { + await createdDateFilter.enterFromDate('03.31.2019'); + await createdDateFilter.enterToDate('invalid text'); + + expect(await createdDateFilter.isFromErrorDisplayed()).toBe(true, 'Error missing for From field'); + expect(await createdDateFilter.isToErrorDisplayed()).toBe(true, 'Error missing for To field'); + expect(await createdDateFilter.getFromError()).toEqual(`Invalid date. The date must be in the format 'DD-MMM-YY'`); + expect(await createdDateFilter.getToError()).toEqual(`Invalid date. The date must be in the format 'DD-MMM-YY'`); + }); + + it('Error message is displayed when entering a date from the future - [C279214]', async () => { + await createdDateFilter.enterFromDate(future); + await createdDateFilter.enterToDate(future); + + expect(await createdDateFilter.isFromErrorDisplayed()).toBe(true, 'Error missing for From field'); + expect(await createdDateFilter.isToErrorDisplayed()).toBe(true, 'Error missing for To field'); + expect(await createdDateFilter.getFromError()).toEqual('The date is beyond the maximum date.'); + expect(await createdDateFilter.getToError()).toEqual('The date is beyond the maximum date.'); + }); + + it('Error message is displayed when From value is bigger than To value - [C279215]', async () => { + await createdDateFilter.enterFromDate(today); + await createdDateFilter.enterToDate(yesterday); + + expect(await createdDateFilter.isToErrorDisplayed()).toBe(true, 'Error missing for To field'); + expect(await createdDateFilter.getToError()).toEqual('No days selected.'); + }); + }); + + describe('Filter by File type', () => { + afterEach(async (done) => { + await filters.clickResetAllButton(); + done(); + }); + + it('Expand / Collapse the File type filter panel - [C279191]', async () => { + expect(await fileTypeFilter.isPanelExpanded()).toBe(true, 'File type filter panel not expanded'); + expect(await fileTypeFilter.getFiltersValues()).toEqual(expectedFileTypes, 'Incorrect File type filters facets'); + expect(await fileTypeFilter.isFilterCategoryInputDisplayed()).toBe(true, 'File type filter categories not displayed'); + + await fileTypeFilter.collapsePanel(); + expect(await fileTypeFilter.isPanelExpanded()).toBe(false, 'File type filter panel is expanded'); + }); + + it('Results are filtered by File type - [C279192]', async () => { + await fileTypeFilter.checkCategory('Adobe PDF Document'); + + expect(await fileTypeFilter.isClearButtonEnabled()).toBe(true, 'File type filter Clear button not enabled'); + expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(false, 'JPG file is displayed'); + expect(await page.getResultsChipsValues()).toEqual(['Adobe PDF Document']); + + await fileTypeFilter.checkCategory('JPEG Image'); + + expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await page.getResultsChipsValues()).toEqual(['Adobe PDF Document', 'JPEG Image']); + }); + + it('Clear the File type filter options - [C279193]', async () => { + await fileTypeFilter.expandPanel(); + await fileTypeFilter.checkCategory('Adobe PDF Document'); + await fileTypeFilter.checkCategory('JPEG Image'); + + expect(await fileTypeFilter.getFiltersCheckedValues()).toEqual(['Adobe PDF Document (1)', 'JPEG Image (1)'], 'Incorrect checked File type filters'); + + await fileTypeFilter.clickClearButton(); + expect(await fileTypeFilter.getFiltersCheckedValues()).toEqual([], 'File types selection not cleared'); + }); + + it('Search for a specific file type - [C279195]', async () => { + expect(await fileTypeFilter.getFiltersValues()).toEqual(expectedFileTypes, 'Incorrect File type filters facets'); + await fileTypeFilter.filterCategoriesBy('PDF'); + expect(await fileTypeFilter.getFiltersValues()).toEqual(['Adobe PDF Document (1)'], 'Incorrect File type filters facets'); + }); + }); + + describe('Filter by Creator', () => { + afterEach(async (done) => { + await filters.clickResetAllButton(); + done(); + }); + + it('Expand / Collapse the Creator filter panel - [C279205]', async () => { + expect(await creatorFilter.isPanelExpanded()).toBe(true, 'Creator filter panel not expanded'); + + expect(await creatorFilter.getFiltersValues()).toEqual(expectedCreators, 'Incorrect Creator filters facets'); + expect(await creatorFilter.isFilterCategoryInputDisplayed()).toBe(true, 'Creator filter categories not displayed'); + + await creatorFilter.collapsePanel(); + expect(await creatorFilter.isPanelExpanded()).toBe(false, 'Creator filter panel is expanded'); + }); + + it('Results are filtered by Creator - [C279206]', async () => { + await creatorFilter.checkCategory(user1); + + expect(await creatorFilter.isClearButtonEnabled()).toBe(true, 'Creator filter Clear button not enabled'); + expect(await dataTable.isItemPresent(filePdf.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await page.getResultsChipsValues()).toEqual([`${user1} ${user1}`]); + + await creatorFilter.checkCategory(user2); + + expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await page.getResultsChipsValues()).toEqual([`${user1} ${user1}`, `${user2} ${user2}`]); + }); + + it('Clear the Creator filter options - [C279207]', async () => { + await creatorFilter.expandPanel(); + await creatorFilter.checkCategory(user1); + await creatorFilter.checkCategory(user2); + expect(await creatorFilter.getFiltersCheckedValues()).toEqual(expectedCreators, 'Incorrect checked Creator filters'); + + await creatorFilter.clickClearButton(); + expect(await creatorFilter.getFiltersCheckedValues()).toEqual([], 'Creator selection not cleared'); + }); + + it('Search for a specific creator - [C279208]', async () => { + expect(await creatorFilter.getFiltersValues()).toEqual(expectedCreators, 'Incorrect Creator filters facets'); + await creatorFilter.filterCategoriesBy(user1); + expect(await creatorFilter.getFiltersValues()).toEqual([`${user1} ${user1} (1)`], 'Incorrect Creator filters facets'); + }); + }); + + describe('Filter by Modifier', () => { + afterEach(async (done) => { + await filters.clickResetAllButton(); + done(); + }); + + it('Expand / Collapse the Modifier filter panel - [C279224]', async () => { + expect(await modifierFilter.isPanelExpanded()).toBe(true, 'Modifier filter panel not expanded'); + + expect(await modifierFilter.getFiltersValues()).toEqual(expectedModifiers, 'Incorrect Modifier filters facets'); + expect(await modifierFilter.isFilterCategoryInputDisplayed()).toBe(true, 'Modifier filter categories not displayed'); + + await modifierFilter.collapsePanel(); + expect(await modifierFilter.isPanelExpanded()).toBe(false, 'Modifier filter panel is expanded'); + }); + + it('Results are filtered by Modifier - [C279225]', async () => { + await modifierFilter.checkCategory(user1); + + expect(await modifierFilter.isClearButtonEnabled()).toBe(true, 'Modifier filter Clear button not enabled'); + expect(await dataTable.isItemPresent(filePdf.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await page.getResultsChipsValues()).toEqual([`${user1} ${user1}`]); + + await modifierFilter.checkCategory(user2); + + expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await page.getResultsChipsValues()).toEqual([`${user1} ${user1}`, `${user2} ${user2}`]); + }); + + it('Clear the Modifier filter options - [C279226]', async () => { + await modifierFilter.expandPanel(); + await modifierFilter.checkCategory(user1); + await modifierFilter.checkCategory(user2); + expect(await modifierFilter.getFiltersCheckedValues()).toEqual(expectedModifiers, 'Incorrect checked Modifier filters'); + + await modifierFilter.clickClearButton(); + expect(await modifierFilter.getFiltersCheckedValues()).toEqual([], 'Modifier selection not cleared'); + }); + + it('Search for a specific modifier - [C279227]', async () => { + expect(await modifierFilter.getFiltersValues()).toEqual(expectedModifiers, 'Incorrect Modifier filters facets'); + await modifierFilter.filterCategoriesBy(user1); + expect(await modifierFilter.getFiltersValues()).toEqual([`${user1} ${user1} (1)`], 'Incorrect Modifier filters facets'); + }); + }); + + describe('Filter by Location', () => { + afterEach(async (done) => { + await filters.clickResetAllButton(); + done(); + }); + + it('Expand / Collapse the Location filter panel - [C279230]', async () => { + expect(await locationFilter.isPanelExpanded()).toBe(true, 'Location filter panel not expanded'); + + expect(await locationFilter.getFiltersValues()).toEqual(expectedLocations, 'Incorrect Location filters facets'); + expect(await locationFilter.isFilterCategoryInputDisplayed()).toBe(true, 'Location filter categories not displayed'); + + await locationFilter.collapsePanel(); + expect(await locationFilter.isPanelExpanded()).toBe(false, 'Location filter panel is expanded'); + }); + + it('Results are filtered by Location - [C279231]', async () => { + await locationFilter.checkCategory(site); + + expect(await locationFilter.isClearButtonEnabled()).toBe(true, 'Location filter Clear button not enabled'); + expect(await dataTable.isItemPresent(filePdf.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await page.getResultsChipsValues()).toEqual([site]); + + await locationFilter.checkCategory('_REPOSITORY_'); + + expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await page.getResultsChipsValues()).toEqual([site, '_REPOSITORY_']); + }); + + it('Clear the Location filter options - [C279232]', async () => { + await locationFilter.expandPanel(); + await locationFilter.checkCategory(site); + await locationFilter.checkCategory('_REPOSITORY_'); + expect(await locationFilter.getFiltersCheckedValues()).toEqual(expectedLocations, 'Incorrect checked Location filters'); + + await locationFilter.clickClearButton(); + expect(await locationFilter.getFiltersCheckedValues()).toEqual([], 'Location selection not cleared'); + }); + + it('Search for a specific location - [C279233]', async () => { + expect(await locationFilter.getFiltersValues()).toEqual(expectedLocations, 'Incorrect Location filters facets'); + await locationFilter.filterCategoriesBy(site); + expect(await locationFilter.getFiltersValues()).toEqual([`${site} (1)`], 'Incorrect Location filters facets'); + }); + }); + + describe('Filter by Modified date', () => { + const expectedDateFilters = ['Today (2)', 'This week (2)', 'This month (2)', 'In the last 6 months (2)', 'This year (2)']; + + afterEach(async (done) => { + await filters.clickResetAllButton(); + done(); + }); + + it('Expand / Collapse the Modified date filter panel - [C279219]', async () => { + expect(await modifiedDateFilter.isPanelExpanded()).toBe(true, 'Modified Date filter panel not expanded'); + + expect(await modifiedDateFilter.getFiltersValues()).toEqual(expectedDateFilters, 'Incorrect Modified Date filters facets'); + expect(await modifiedDateFilter.isFilterCategoryInputDisplayed()).toBe(true, 'Modified Date filter categories not displayed'); + + await modifiedDateFilter.collapsePanel(); + expect(await modifiedDateFilter.isPanelExpanded()).toBe(false, 'Modified Date filter panel is expanded'); + }); + + it('Results are filtered by Modified date - [C279221]', async () => { + await modifiedDateFilter.checkCategory('Today'); + + expect(await modifiedDateFilter.isClearButtonEnabled()).toBe(true, 'Modified date filter Clear button not enabled'); + expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await page.getResultsChipsValues()).toEqual(['Today']); + + await modifiedDateFilter.checkCategory('This week'); + + expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await page.getResultsChipsValues()).toEqual(['Today', 'This week']); + }); + + it('Clear the Modified date filter options - [C279220]', async () => { + await modifiedDateFilter.expandPanel(); + await modifiedDateFilter.checkCategory('Today'); + await modifiedDateFilter.checkCategory('This week'); + await modifiedDateFilter.checkCategory('This month'); + await modifiedDateFilter.checkCategory('In the last 6 months'); + await modifiedDateFilter.checkCategory('This year'); + + expect(await modifiedDateFilter.getFiltersCheckedValues()).toEqual(expectedDateFilters, 'Incorrect checked Modified date filters'); + + await modifiedDateFilter.clickClearButton(); + expect(await modifiedDateFilter.getFiltersCheckedValues()).toEqual([], 'Modified date selection not cleared'); + }); + + it('Search for a specific modified date option - [C325006]', async () => { + expect(await modifiedDateFilter.getFiltersValues()).toEqual(expectedDateFilters, 'Incorrect Modified date filters facets'); + await modifiedDateFilter.filterCategoriesBy('This'); + expect(await modifiedDateFilter.getFiltersValues()).toEqual(['This week (2)', 'This month (2)', 'This year (2)'], 'Incorrect Modified date filters facets'); + }); + }); + + describe('Multiple filters', () => { + afterEach(async (done) => { + await filters.clickResetAllButton(); + await sizeFilter.resetPanel(); + await createdDateFilter.resetPanel(); + done(); + }); + + it('Multiple filters can be applied - [C280051]', async () => { + await sizeFilter.expandPanel(); + await sizeFilter.checkSizeSmall(); + + await fileTypeFilter.expandPanel(); + await fileTypeFilter.checkCategory('JPEG Image'); + await creatorFilter.checkCategory(user1); + await locationFilter.checkCategory(site); + + expect(await dataTable.isItemPresent(filePdf.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await page.getResultsChipsValues()).toEqual(['JPEG Image', `${user1} ${user1}`, site]); + + await page.removeChip('JPEG Image'); + await page.removeChip(`${user1} ${user1}`); + await page.removeChip(site); + + expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await page.getResultsChipsValues()).toEqual([]); + }); + + it('Total results is updated correctly - [C280052]', async () => { + await fileTypeFilter.expandPanel(); + await fileTypeFilter.checkCategory('JPEG Image'); + await creatorFilter.checkCategory(user1); + + expect(await page.getResultsFoundText()).toEqual('1 result found'); + + await page.removeChip('JPEG Image'); + await page.removeChip(`${user1} ${user1}`); + + expect(await page.getResultsFoundText()).toEqual('2 results found'); + }); + + it('Pagination is correct when search results are filtered - [C279188]', async () => { + await fileTypeFilter.expandPanel(); + await fileTypeFilter.checkCategory('JPEG Image'); + await creatorFilter.checkCategory(user1); + + expect(await page.pagination.getRange()).toEqual('Showing 1-1 of 1'); + + await page.removeChip('JPEG Image'); + await page.removeChip(`${user1} ${user1}`); + + expect(await page.pagination.getRange()).toEqual('Showing 1-2 of 2'); + }); + + it('The filter facets display is updated when making a new query - [C308042]', async () => { + expect(await fileTypeFilter.getFiltersValues()).toEqual(expectedFileTypes); + expect(await creatorFilter.getFiltersValues()).toEqual(expectedCreators); + expect(await modifierFilter.getFiltersValues()).toEqual(expectedModifiers); + expect(await locationFilter.getFiltersValues()).toEqual(expectedLocations); + + await searchInput.clickSearchButton(); + await searchInput.searchFor(fileJpg.name); + await dataTable.waitForBody(); + + expect(await fileTypeFilter.getFiltersValues()).toEqual(['JPEG Image (1)']); + expect(await creatorFilter.getFiltersValues()).toEqual([`${user1} ${user1} (1)`]); + expect(await modifierFilter.getFiltersValues()).toEqual([`${user1} ${user1} (1)`]); + expect(await locationFilter.getFiltersValues()).toEqual([`${site} (1)`]); + }); + }); +}); diff --git a/e2e/suites/search/search-input.test.ts b/e2e/suites/search/search-input.test.ts index ac57d4d98..d692d5569 100644 --- a/e2e/suites/search/search-input.test.ts +++ b/e2e/suites/search/search-input.test.ts @@ -48,13 +48,13 @@ describe('Search input', () => { it('Search options are displayed when clicking in the search input - [C289848]', async () => { await searchInput.clickSearchButton(); - expect(await searchInput.isOptionsAreaDisplayed()).toBe(true, '1. Search options not displayed'); - expect(await searchInput.isFilesOptionEnabled()).toBe(true, '2. Files option not enabled'); - expect(await searchInput.isFoldersOptionEnabled()).toBe(true, '3. Folders option not enabled'); - expect(await searchInput.isLibrariesOptionEnabled()).toBe(true, '4. Libraries option not enabled'); - expect(await searchInput.isFilesOptionChecked()).toBe(false, '5. Files option is checked'); - expect(await searchInput.isFoldersOptionChecked()).toBe(false, '6. Folders option is checked'); - expect(await searchInput.isLibrariesOptionChecked()).toBe(false, '7. Libraries option is checked'); + expect(await searchInput.isOptionsAreaDisplayed()).toBe(true, 'Search options not displayed'); + expect(await searchInput.isFilesOptionEnabled()).toBe(true, 'Files option not enabled'); + expect(await searchInput.isFoldersOptionEnabled()).toBe(true, 'Folders option not enabled'); + expect(await searchInput.isLibrariesOptionEnabled()).toBe(true, 'Libraries option not enabled'); + expect(await searchInput.isFilesOptionChecked()).toBe(false, 'Files option is checked'); + expect(await searchInput.isFoldersOptionChecked()).toBe(false, 'Folders option is checked'); + expect(await searchInput.isLibrariesOptionChecked()).toBe(false, 'Libraries option is checked'); }); it('Search options are correctly enabled / disabled - [C289849]', async () => { diff --git a/e2e/suites/search/search-results-files-folders.test.ts b/e2e/suites/search/search-results-files-folders.test.ts index db589b197..bad389200 100644 --- a/e2e/suites/search/search-results-files-folders.test.ts +++ b/e2e/suites/search/search-results-files-folders.test.ts @@ -60,19 +60,9 @@ describe('Search results - files and folders', () => { beforeAll(async done => { await apis.admin.people.createUser({ username }); - fileId = (await apis.user.nodes.createFile( - file, - '-my-', - fileTitle, - fileDescription - )).entry.id; + fileId = (await apis.user.nodes.createFile(file, '-my-', fileTitle, fileDescription)).entry.id; await apis.user.nodes.editNodeContent(fileId, 'edited by user'); - folderId = (await apis.user.nodes.createFolder( - folder, - '-my-', - folderTitle, - folderDescription - )).entry.id; + folderId = (await apis.user.nodes.createFolder(folder, '-my-', folderTitle, folderDescription)).entry.id; fileRussianId = (await apis.user.nodes.createFile(fileRussian)).entry.id; await apis.user.sites.createSite(site); @@ -83,6 +73,11 @@ describe('Search results - files and folders', () => { done(); }); + beforeEach(async done => { + await page.refresh(); + done(); + }); + afterAll(async done => { await Promise.all([ apis.user.nodes.deleteNodeById(fileId), @@ -93,20 +88,13 @@ describe('Search results - files and folders', () => { done(); }); - beforeEach(async done => { - await page.refresh(); - done(); - }); - it('Results page title - [C307002]', async () => { await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor('test-'); await dataTable.waitForBody(); - expect(await page.breadcrumb.getCurrentItemName()).toEqual( - 'Search Results' - ); + expect(await page.breadcrumb.getCurrentItemName()).toEqual('Search Results'); }); it('File information - [C279183]', async () => { @@ -116,38 +104,17 @@ describe('Search results - files and folders', () => { await dataTable.waitForBody(); const fileEntry = await apis.user.nodes.getNodeById(fileId); - const modifiedDate = moment(fileEntry.entry.modifiedAt).format( - 'MMM D, YYYY, h:mm:ss A' - ); + const modifiedDate = moment(fileEntry.entry.modifiedAt).format('MMM D, YYYY, h:mm:ss A'); const modifiedBy = fileEntry.entry.modifiedByUser.displayName; const size = fileEntry.entry.content.sizeInBytes; - expect(await dataTable.isItemPresent(file)).toBe( - true, - `${file} is not displayed` - ); - - expect(await dataTable.getRowCellsCount(file)).toEqual( - 2, - 'incorrect number of columns' - ); - - expect(await dataTable.getSearchResultLinesCount(file)).toEqual( - 4, - 'incorrect number of lines for search result' - ); - expect(await dataTable.getSearchResultNameAndTitle(file)).toBe( - `${file} ( ${fileTitle} )` - ); - expect(await dataTable.getSearchResultDescription(file)).toBe( - fileDescription - ); - expect(await dataTable.getSearchResultModified(file)).toBe( - `Modified: ${modifiedDate} by ${modifiedBy} | Size: ${size} Bytes` - ); - expect(await dataTable.getSearchResultLocation(file)).toMatch( - /Location:\s+Personal Files/ - ); + expect(await dataTable.isItemPresent(file)).toBe(true, `${file} is not displayed`); + expect(await dataTable.getRowCellsCount(file)).toEqual(2, 'incorrect number of columns'); + expect(await dataTable.getSearchResultLinesCount(file)).toEqual(4, 'incorrect number of lines for search result'); + expect(await dataTable.getSearchResultNameAndTitle(file)).toBe(`${file} ( ${fileTitle} )`); + expect(await dataTable.getSearchResultDescription(file)).toBe(fileDescription); + expect(await dataTable.getSearchResultModified(file)).toBe(`Modified: ${modifiedDate} by ${modifiedBy} | Size: ${size} Bytes`); + expect(await dataTable.getSearchResultLocation(file)).toMatch(/Location:\s+Personal Files/); }); it('Folder information - [C306867]', async () => { @@ -157,37 +124,16 @@ describe('Search results - files and folders', () => { await dataTable.waitForBody(); const folderEntry = await apis.user.nodes.getNodeById(folderId); - const modifiedDate = moment(folderEntry.entry.modifiedAt).format( - 'MMM D, YYYY, h:mm:ss A' - ); + const modifiedDate = moment(folderEntry.entry.modifiedAt).format('MMM D, YYYY, h:mm:ss A'); const modifiedBy = folderEntry.entry.modifiedByUser.displayName; - expect(await dataTable.isItemPresent(folder)).toBe( - true, - `${folder} is not displayed` - ); - - expect(await dataTable.getRowCellsCount(folder)).toEqual( - 2, - 'incorrect number of columns' - ); - - expect(await dataTable.getSearchResultLinesCount(folder)).toEqual( - 4, - 'incorrect number of lines for search result' - ); - expect(await dataTable.getSearchResultNameAndTitle(folder)).toBe( - `${folder} ( ${folderTitle} )` - ); - expect(await dataTable.getSearchResultDescription(folder)).toBe( - folderDescription - ); - expect(await dataTable.getSearchResultModified(folder)).toBe( - `Modified: ${modifiedDate} by ${modifiedBy}` - ); - expect(await dataTable.getSearchResultLocation(folder)).toMatch( - /Location:\s+Personal Files/ - ); + expect(await dataTable.isItemPresent(folder)).toBe(true, `${folder} is not displayed`); + expect(await dataTable.getRowCellsCount(folder)).toEqual(2, 'incorrect number of columns'); + expect(await dataTable.getSearchResultLinesCount(folder)).toEqual(4, 'incorrect number of lines for search result'); + expect(await dataTable.getSearchResultNameAndTitle(folder)).toBe(`${folder} ( ${folderTitle} )`); + expect(await dataTable.getSearchResultDescription(folder)).toBe(folderDescription); + expect(await dataTable.getSearchResultModified(folder)).toBe(`Modified: ${modifiedDate} by ${modifiedBy}`); + expect(await dataTable.getSearchResultLocation(folder)).toMatch(/Location:\s+Personal Files/); }); it('Search file with special characters - [C290029]', async () => { @@ -196,10 +142,7 @@ describe('Search results - files and folders', () => { await searchInput.searchFor(fileRussian); await dataTable.waitForBody(); - expect(await dataTable.isItemPresent(fileRussian)).toBe( - true, - `${fileRussian} is not displayed` - ); + expect(await dataTable.isItemPresent(fileRussian)).toBe(true, `${fileRussian} is not displayed`); }); it('Location column redirect - file in user Home - [C279177]', async () => { diff --git a/e2e/suites/search/search-results-libraries.test.ts b/e2e/suites/search/search-results-libraries.test.ts index a40ed84f7..f958fdc03 100644 --- a/e2e/suites/search/search-results-libraries.test.ts +++ b/e2e/suites/search/search-results-libraries.test.ts @@ -63,7 +63,6 @@ describe('Search results - libraries', () => { const adminSite2 = `admin-site-${Utils.random()}`; const adminSite3 = `admin-site-${Utils.random()}`; const adminSite4 = `admin-site-${Utils.random()}`; - const adminPrivate = `admin-site-${Utils.random()}`; const apis = { diff --git a/e2e/suites/search/search-sorting.test.ts b/e2e/suites/search/search-sorting.test.ts new file mode 100644 index 000000000..3e34c1e2d --- /dev/null +++ b/e2e/suites/search/search-sorting.test.ts @@ -0,0 +1,202 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { LoginPage, SearchResultsPage } from '../../pages/pages'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; +import { Utils } from '../../utilities/utils'; +import { FILES } from '../../configs'; + +describe('Search sorting', () => { + const random = Utils.random(); + + const user1 = `user1-${random}`; + const user2 = `user2-${random}`; + + const parent = `parent-${random}`; + let parentId: string; + + const fileJpg = { + name: `search-sort-file-1-${random}.jpg`, + source: FILES.jpgFile + }; + + const filePdf = { + name: `search-sort-file-2-${random}.pdf`, + title: 'search sort title', + description: 'search sort', + source: FILES.pdfFile + }; + + const apis = { + admin: new RepoClient(), + user1: new RepoClient(user1, user1), + user2: new RepoClient(user2, user2) + }; + + const loginPage = new LoginPage(); + const page = new SearchResultsPage(); + const { searchInput } = page.header; + const { dataTable } = page; + + beforeAll(async (done) => { + await apis.admin.people.createUser({ username: user1 }); + await apis.admin.people.createUser({ username: user2 }); + parentId = (await apis.user1.nodes.createFolder(parent)).entry.id; + + await apis.user1.nodes.setGranularPermission(parentId, true, user2, 'Collaborator'); + + await apis.user1.upload.uploadFileWithRename(fileJpg.source, parentId, fileJpg.name); + await apis.user2.upload.uploadFileWithRename(filePdf.source, parentId, filePdf.name, filePdf.title, filePdf.description); + + await apis.user1.search.waitForNodes('search-sort', { expect: 2 }); + + await loginPage.loginWith(user1); + done(); + }); + + beforeEach(async (done) => { + await Utils.pressEscape(); + await page.clickPersonalFilesAndWait(); + + await searchInput.clickSearchButton(); + await searchInput.searchFor('search sort'); + await dataTable.waitForBody(); + done(); + }); + + afterAll(async () => { + await apis.user1.nodes.deleteNodeById(parentId); + }); + + it('Sorting options are displayed - [C277722]', async () => { + expect(await page.sortingPicker.isSortOrderButtonDisplayed()).toBe(true, 'Sort order button not displayed'); + expect(await page.sortingPicker.isSortByOptionDisplayed()).toBe(true, 'Sort options not displayed'); + expect(await page.sortingPicker.getSortOrder()).toBe('DESC', 'Incorrect default sort order'); + expect(await page.sortingPicker.getSelectedSortByOption()).toBe('Relevance', 'Incorrect selected sort option'); + + await page.sortingPicker.clickSortByDropdown(); + + const expectedOptions = [ 'Relevance', 'Filename', 'Title', 'Modified date', 'Modifier', 'Created date', 'Size', 'Type' ]; + expect(await page.sortingPicker.getSortByOptionsList()).toEqual(expectedOptions, 'Incorrect sort options list'); + }); + + it('Sort by Name - [C277728]', async () => { + await page.sortingPicker.sortByName(); + await page.sortingPicker.setSortOrderASC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); + + await page.sortingPicker.sortByName(); + await page.sortingPicker.setSortOrderDESC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); + }); + + it('Sort by Type - [C277740]', async () => { + await page.sortingPicker.sortByType(); + await page.sortingPicker.setSortOrderASC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); + + await page.sortingPicker.sortByType(); + await page.sortingPicker.setSortOrderDESC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); + }); + + it('Sort by Size - [C277738]', async () => { + await page.sortingPicker.sortBySize(); + await page.sortingPicker.setSortOrderASC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); + + await page.sortingPicker.sortBySize(); + await page.sortingPicker.setSortOrderDESC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); + }); + + it('Sort by Created date - [C277734]', async () => { + await page.sortingPicker.sortByCreatedDate(); + await page.sortingPicker.setSortOrderASC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); + + await page.sortingPicker.sortByCreatedDate(); + await page.sortingPicker.setSortOrderDESC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); + }); + + it('Sort by Modified date - [C277736]', async () => { + await page.sortingPicker.sortByModifiedDate(); + await page.sortingPicker.setSortOrderASC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); + + await page.sortingPicker.sortByModifiedDate(); + await page.sortingPicker.setSortOrderDESC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); + }); + + it('Sort by Relevance - [C277727]', async () => { + await page.sortingPicker.sortByRelevance(); + await page.sortingPicker.setSortOrderASC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); + + await page.sortingPicker.sortByRelevance(); + await page.sortingPicker.setSortOrderDESC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); + }); + + it('Sort by Modifier - [C277732]', async () => { + await page.sortingPicker.sortByModifier(); + await page.sortingPicker.setSortOrderASC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name); + + await page.sortingPicker.sortByModifier(); + await page.sortingPicker.setSortOrderDESC(); + + expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name); + expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name); + }); +}); diff --git a/e2e/utilities/repo-client/apis/upload/upload-api.ts b/e2e/utilities/repo-client/apis/upload/upload-api.ts index 2e9bcaea8..e9db895e9 100644 --- a/e2e/utilities/repo-client/apis/upload/upload-api.ts +++ b/e2e/utilities/repo-client/apis/upload/upload-api.ts @@ -51,8 +51,15 @@ export class UploadApi extends RepoApi { } } - async uploadFileWithRename(fileName: string, parentFolderId: string = '-my-', newName: string) { + async uploadFileWithRename(fileName: string, parentId: string = '-my-', newName: string, title: string = '', description: string = '') { const file = fs.createReadStream(`${E2E_ROOT_PATH}/resources/test-files/${fileName}`); + const nodeProps = { + properties: { + 'cm:title': title, + 'cm:description': description + } + }; + const opts = { name: newName, nodeType: 'cm:content' @@ -60,7 +67,7 @@ export class UploadApi extends RepoApi { try { await this.apiAuth(); - return await this.upload.uploadFile(file, '', parentFolderId, null, opts); + return await this.upload.uploadFile(file, '', parentId, nodeProps, opts); } catch (error) { this.handleError(`${this.constructor.name} ${this.uploadFileWithRename.name}`, error); } diff --git a/e2e/utilities/utils.ts b/e2e/utilities/utils.ts index 886b57507..fba5052fd 100755 --- a/e2e/utilities/utils.ts +++ b/e2e/utilities/utils.ts @@ -92,6 +92,13 @@ export class Utils { } } + static async clearFieldWithBackspace(elem: ElementFinder): Promise { + const text = await elem.getAttribute('value'); + for (let i = 0; i < text.length; i++) { + await elem.sendKeys(protractor.Key.BACK_SPACE); + } + } + static async fileExistsOnOS(fileName: string, folderName: string = '', subFolderName: string = '') { const config = await browser.getProcessedConfig(); const filePath = path.join(config.params.downloadFolder, folderName, subFolderName, fileName); From 3d141cf42f61c578a75cc9db9bca14944b828ca5 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Sun, 5 Jan 2020 19:01:00 +0200 Subject: [PATCH 36/96] remove fdescribe --- e2e/suites/search/search-filters.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/suites/search/search-filters.test.ts b/e2e/suites/search/search-filters.test.ts index 4b471519c..6e4a8ea00 100644 --- a/e2e/suites/search/search-filters.test.ts +++ b/e2e/suites/search/search-filters.test.ts @@ -29,7 +29,7 @@ import { Utils } from '../../utilities/utils'; import { FILES, SITE_VISIBILITY, SITE_ROLES } from '../../configs'; import * as moment from 'moment'; -fdescribe('Search filters', () => { +describe('Search filters', () => { const random = Utils.random(); const user1 = `user1-${random}`; From 8077ec5078c08ddc8b66dbdd44cf3bf8b49244c3 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Sun, 5 Jan 2020 21:33:35 +0200 Subject: [PATCH 37/96] small changes --- e2e/suites/search/search-filters.test.ts | 143 ++++++++++++++--------- 1 file changed, 89 insertions(+), 54 deletions(-) diff --git a/e2e/suites/search/search-filters.test.ts b/e2e/suites/search/search-filters.test.ts index 6e4a8ea00..80989f148 100644 --- a/e2e/suites/search/search-filters.test.ts +++ b/e2e/suites/search/search-filters.test.ts @@ -40,12 +40,12 @@ describe('Search filters', () => { const site = `site-${Utils.random()}`; let docLibId; - const fileJpg = { + const fileJpgUser1 = { name: `search-filters-file-1-${random}.jpg`, source: FILES.jpgFile }; - const filePdf = { + const filePdfUser2 = { name: `search-filters-file-2-${random}.pdf`, title: 'search filters title', description: 'search filters', @@ -86,8 +86,8 @@ describe('Search filters', () => { await apis.user1.nodes.setGranularPermission(parentId, true, user2, 'Collaborator'); - await apis.user1.upload.uploadFileWithRename(fileJpg.source, docLibId, fileJpg.name); - await apis.user2.upload.uploadFileWithRename(filePdf.source, parentId, filePdf.name, filePdf.title, filePdf.description); + await apis.user1.upload.uploadFileWithRename(fileJpgUser1.source, docLibId, fileJpgUser1.name); + await apis.user2.upload.uploadFileWithRename(filePdfUser2.source, parentId, filePdfUser2.name, filePdfUser2.title, filePdfUser2.description); await apis.user1.search.waitForNodes('search-filters', { expect: 2 }); @@ -147,8 +147,8 @@ describe('Search filters', () => { await sizeFilter.expandPanel(); await sizeFilter.checkSizeSmall(); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, `${fileJpg.name} not in the list`); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, `${filePdf.name} not in the list`); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, `${fileJpgUser1.name} not in the list`); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, `${filePdfUser2.name} not in the list`); }); it('Filter by Huge - [C279202]', async () => { @@ -164,8 +164,8 @@ describe('Search filters', () => { await sizeFilter.checkSizeMedium(); await sizeFilter.checkSizeLarge(); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, `${fileJpg.name} not in the list`); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, `${filePdf.name} not in the list`); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, `${fileJpgUser1.name} not in the list`); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, `${filePdfUser2.name} not in the list`); }); it('Clear the Size filter options - [C279198]', async () => { @@ -203,6 +203,7 @@ describe('Search filters', () => { }); it('Results are filtered by Created date - [C279217]', async () => { + await createdDateFilter.expandPanel(); await createdDateFilter.enterFromDate(yesterday); await createdDateFilter.enterToDate(yesterday); @@ -210,8 +211,8 @@ describe('Search filters', () => { await createdDateFilter.clickApplyButton(); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(false, 'PDF file is displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(false, 'JPG file is displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(false, 'JPG file is displayed'); await createdDateFilter.enterFromDate(yesterday); await createdDateFilter.enterToDate(today); @@ -220,11 +221,12 @@ describe('Search filters', () => { await createdDateFilter.clickApplyButton(); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); }); it('Clear the Created date filter options - [C279216]', async () => { + await createdDateFilter.expandPanel(); await createdDateFilter.enterFromDate(yesterday); await createdDateFilter.enterToDate(yesterday); await createdDateFilter.clickApplyButton(); @@ -234,47 +236,51 @@ describe('Search filters', () => { await createdDateFilter.clickClearButton(); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file is displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file is displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file is displayed'); expect(await createdDateFilter.getFromValue()).toEqual('', 'From field not empty'); expect(await createdDateFilter.getToValue()).toEqual('', 'To field not empty'); }); it('From and To values are required - [C279212]', async () => { + await createdDateFilter.expandPanel(); await createdDateFilter.enterFromDate(''); await createdDateFilter.enterToDate(''); - expect(await createdDateFilter.isFromErrorDisplayed()).toBe(true, 'Error missing for From field'); - expect(await createdDateFilter.isToErrorDisplayed()).toBe(true, 'Error missing for To field'); + expect(await createdDateFilter.isFromErrorDisplayed()).toBe(true, 'Error missing for From field'); + expect(await createdDateFilter.isToErrorDisplayed()).toBe(true, 'Error missing for To field'); expect(await createdDateFilter.getFromError()).toEqual('Required value'); expect(await createdDateFilter.getToError()).toEqual('Required value'); }); it('Error message is displayed when entering an incorrect date format - [C279213]', async () => { + await createdDateFilter.expandPanel(); await createdDateFilter.enterFromDate('03.31.2019'); await createdDateFilter.enterToDate('invalid text'); - expect(await createdDateFilter.isFromErrorDisplayed()).toBe(true, 'Error missing for From field'); - expect(await createdDateFilter.isToErrorDisplayed()).toBe(true, 'Error missing for To field'); + expect(await createdDateFilter.isFromErrorDisplayed()).toBe(true, 'Error missing for From field'); + expect(await createdDateFilter.isToErrorDisplayed()).toBe(true, 'Error missing for To field'); expect(await createdDateFilter.getFromError()).toEqual(`Invalid date. The date must be in the format 'DD-MMM-YY'`); expect(await createdDateFilter.getToError()).toEqual(`Invalid date. The date must be in the format 'DD-MMM-YY'`); }); it('Error message is displayed when entering a date from the future - [C279214]', async () => { + await createdDateFilter.expandPanel(); await createdDateFilter.enterFromDate(future); await createdDateFilter.enterToDate(future); - expect(await createdDateFilter.isFromErrorDisplayed()).toBe(true, 'Error missing for From field'); - expect(await createdDateFilter.isToErrorDisplayed()).toBe(true, 'Error missing for To field'); + expect(await createdDateFilter.isFromErrorDisplayed()).toBe(true, 'Error missing for From field'); + expect(await createdDateFilter.isToErrorDisplayed()).toBe(true, 'Error missing for To field'); expect(await createdDateFilter.getFromError()).toEqual('The date is beyond the maximum date.'); expect(await createdDateFilter.getToError()).toEqual('The date is beyond the maximum date.'); }); it('Error message is displayed when From value is bigger than To value - [C279215]', async () => { + await createdDateFilter.expandPanel(); await createdDateFilter.enterFromDate(today); await createdDateFilter.enterToDate(yesterday); - expect(await createdDateFilter.isToErrorDisplayed()).toBe(true, 'Error missing for To field'); + expect(await createdDateFilter.isToErrorDisplayed()).toBe(true, 'Error missing for To field'); expect(await createdDateFilter.getToError()).toEqual('No days selected.'); }); }); @@ -295,32 +301,38 @@ describe('Search filters', () => { }); it('Results are filtered by File type - [C279192]', async () => { + await fileTypeFilter.expandPanel(); await fileTypeFilter.checkCategory('Adobe PDF Document'); expect(await fileTypeFilter.isClearButtonEnabled()).toBe(true, 'File type filter Clear button not enabled'); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(false, 'JPG file is displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(false, 'JPG file is displayed'); expect(await page.getResultsChipsValues()).toEqual(['Adobe PDF Document']); await fileTypeFilter.checkCategory('JPEG Image'); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await page.getResultsChipsValues()).toEqual(['Adobe PDF Document', 'JPEG Image']); }); it('Clear the File type filter options - [C279193]', async () => { await fileTypeFilter.expandPanel(); await fileTypeFilter.checkCategory('Adobe PDF Document'); - await fileTypeFilter.checkCategory('JPEG Image'); - expect(await fileTypeFilter.getFiltersCheckedValues()).toEqual(['Adobe PDF Document (1)', 'JPEG Image (1)'], 'Incorrect checked File type filters'); + expect(await fileTypeFilter.getFiltersCheckedValues()).toEqual(['Adobe PDF Document (1)']); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(false, 'JPG file is displayed'); await fileTypeFilter.clickClearButton(); + + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await fileTypeFilter.getFiltersCheckedValues()).toEqual([], 'File types selection not cleared'); }); it('Search for a specific file type - [C279195]', async () => { + await fileTypeFilter.expandPanel(); expect(await fileTypeFilter.getFiltersValues()).toEqual(expectedFileTypes, 'Incorrect File type filters facets'); await fileTypeFilter.filterCategoriesBy('PDF'); expect(await fileTypeFilter.getFiltersValues()).toEqual(['Adobe PDF Document (1)'], 'Incorrect File type filters facets'); @@ -344,31 +356,38 @@ describe('Search filters', () => { }); it('Results are filtered by Creator - [C279206]', async () => { + await creatorFilter.expandPanel(); await creatorFilter.checkCategory(user1); expect(await creatorFilter.isClearButtonEnabled()).toBe(true, 'Creator filter Clear button not enabled'); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(false, 'PDF file is displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await page.getResultsChipsValues()).toEqual([`${user1} ${user1}`]); await creatorFilter.checkCategory(user2); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await page.getResultsChipsValues()).toEqual([`${user1} ${user1}`, `${user2} ${user2}`]); }); it('Clear the Creator filter options - [C279207]', async () => { await creatorFilter.expandPanel(); await creatorFilter.checkCategory(user1); - await creatorFilter.checkCategory(user2); - expect(await creatorFilter.getFiltersCheckedValues()).toEqual(expectedCreators, 'Incorrect checked Creator filters'); + + expect(await creatorFilter.getFiltersCheckedValues()).toEqual([`${user1} ${user1} (1)`]); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); await creatorFilter.clickClearButton(); + + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await creatorFilter.getFiltersCheckedValues()).toEqual([], 'Creator selection not cleared'); }); it('Search for a specific creator - [C279208]', async () => { + await creatorFilter.expandPanel(); expect(await creatorFilter.getFiltersValues()).toEqual(expectedCreators, 'Incorrect Creator filters facets'); await creatorFilter.filterCategoriesBy(user1); expect(await creatorFilter.getFiltersValues()).toEqual([`${user1} ${user1} (1)`], 'Incorrect Creator filters facets'); @@ -392,31 +411,38 @@ describe('Search filters', () => { }); it('Results are filtered by Modifier - [C279225]', async () => { + await modifierFilter.expandPanel(); await modifierFilter.checkCategory(user1); expect(await modifierFilter.isClearButtonEnabled()).toBe(true, 'Modifier filter Clear button not enabled'); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(false, 'PDF file is displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await page.getResultsChipsValues()).toEqual([`${user1} ${user1}`]); await modifierFilter.checkCategory(user2); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await page.getResultsChipsValues()).toEqual([`${user1} ${user1}`, `${user2} ${user2}`]); }); it('Clear the Modifier filter options - [C279226]', async () => { await modifierFilter.expandPanel(); await modifierFilter.checkCategory(user1); - await modifierFilter.checkCategory(user2); - expect(await modifierFilter.getFiltersCheckedValues()).toEqual(expectedModifiers, 'Incorrect checked Modifier filters'); + + expect(await modifierFilter.getFiltersCheckedValues()).toEqual([`${user1} ${user1} (1)`]); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); await modifierFilter.clickClearButton(); + + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await modifierFilter.getFiltersCheckedValues()).toEqual([], 'Modifier selection not cleared'); }); it('Search for a specific modifier - [C279227]', async () => { + await modifierFilter.expandPanel(); expect(await modifierFilter.getFiltersValues()).toEqual(expectedModifiers, 'Incorrect Modifier filters facets'); await modifierFilter.filterCategoriesBy(user1); expect(await modifierFilter.getFiltersValues()).toEqual([`${user1} ${user1} (1)`], 'Incorrect Modifier filters facets'); @@ -440,31 +466,38 @@ describe('Search filters', () => { }); it('Results are filtered by Location - [C279231]', async () => { + await locationFilter.expandPanel(); await locationFilter.checkCategory(site); expect(await locationFilter.isClearButtonEnabled()).toBe(true, 'Location filter Clear button not enabled'); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(false, 'PDF file is displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await page.getResultsChipsValues()).toEqual([site]); await locationFilter.checkCategory('_REPOSITORY_'); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await page.getResultsChipsValues()).toEqual([site, '_REPOSITORY_']); }); it('Clear the Location filter options - [C279232]', async () => { await locationFilter.expandPanel(); await locationFilter.checkCategory(site); - await locationFilter.checkCategory('_REPOSITORY_'); - expect(await locationFilter.getFiltersCheckedValues()).toEqual(expectedLocations, 'Incorrect checked Location filters'); + + expect(await locationFilter.getFiltersCheckedValues()).toEqual([`${site} (1)`]); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); await locationFilter.clickClearButton(); + + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await locationFilter.getFiltersCheckedValues()).toEqual([], 'Location selection not cleared'); }); it('Search for a specific location - [C279233]', async () => { + await locationFilter.expandPanel(); expect(await locationFilter.getFiltersValues()).toEqual(expectedLocations, 'Incorrect Location filters facets'); await locationFilter.filterCategoriesBy(site); expect(await locationFilter.getFiltersValues()).toEqual([`${site} (1)`], 'Incorrect Location filters facets'); @@ -490,17 +523,18 @@ describe('Search filters', () => { }); it('Results are filtered by Modified date - [C279221]', async () => { + await modifiedDateFilter.expandPanel(); await modifiedDateFilter.checkCategory('Today'); expect(await modifiedDateFilter.isClearButtonEnabled()).toBe(true, 'Modified date filter Clear button not enabled'); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await page.getResultsChipsValues()).toEqual(['Today']); await modifiedDateFilter.checkCategory('This week'); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await page.getResultsChipsValues()).toEqual(['Today', 'This week']); }); @@ -519,6 +553,7 @@ describe('Search filters', () => { }); it('Search for a specific modified date option - [C325006]', async () => { + await modifiedDateFilter.expandPanel(); expect(await modifiedDateFilter.getFiltersValues()).toEqual(expectedDateFilters, 'Incorrect Modified date filters facets'); await modifiedDateFilter.filterCategoriesBy('This'); expect(await modifiedDateFilter.getFiltersValues()).toEqual(['This week (2)', 'This month (2)', 'This year (2)'], 'Incorrect Modified date filters facets'); @@ -542,16 +577,16 @@ describe('Search filters', () => { await creatorFilter.checkCategory(user1); await locationFilter.checkCategory(site); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(false, 'PDF file is displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(false, 'PDF file is displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await page.getResultsChipsValues()).toEqual(['JPEG Image', `${user1} ${user1}`, site]); await page.removeChip('JPEG Image'); await page.removeChip(`${user1} ${user1}`); await page.removeChip(site); - expect(await dataTable.isItemPresent(filePdf.name)).toBe(true, 'PDF file not displayed'); - expect(await dataTable.isItemPresent(fileJpg.name)).toBe(true, 'JPG file not displayed'); + expect(await dataTable.isItemPresent(filePdfUser2.name)).toBe(true, 'PDF file not displayed'); + expect(await dataTable.isItemPresent(fileJpgUser1.name)).toBe(true, 'JPG file not displayed'); expect(await page.getResultsChipsValues()).toEqual([]); }); @@ -588,7 +623,7 @@ describe('Search filters', () => { expect(await locationFilter.getFiltersValues()).toEqual(expectedLocations); await searchInput.clickSearchButton(); - await searchInput.searchFor(fileJpg.name); + await searchInput.searchFor(fileJpgUser1.name); await dataTable.waitForBody(); expect(await fileTypeFilter.getFiltersValues()).toEqual(['JPEG Image (1)']); From 98e10adebda9afee56c33f1747e4954fe662361d Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Sun, 5 Jan 2020 22:45:15 +0200 Subject: [PATCH 38/96] try to fix tests failing only on travis --- .travis.yml | 26 ++++++++++--------- e2e/components/search/filters/facet-filter.ts | 5 ++-- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8b0fe2f95..9c54c308d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,18 +33,20 @@ jobs: - npm run test:ci - bash <(curl -s https://codecov.io/bash) -X gcov - stage: e2e - name: Test Suite appNavigation&search - script: npm run build.e2e && SUITE="--suite authentication,listViews,navigation,application,pagination,search" npm run e2e:docker - - name: Test Suite actionsAvailable - script: npm run build.e2e && SUITE="--suite actionsAvailable" npm run e2e:docker - - name: Test Suite addRemoveContent - script: npm run build.e2e && SUITE="--suite addRemoveContent" npm run e2e:docker - - name: Test Suite manageContent - script: npm run build.e2e && SUITE="--suite manageContent" npm run e2e:docker - - name: Test Suite sharingContent&markFavorite - script: npm run build.e2e && SUITE="--suite sharingContent" npm run e2e:docker - - name: Test Suite viewContent&metadata&extensions - script: npm run build.e2e && SUITE="--suite viewer,infoDrawer,extensions" npm run e2e:docker + # name: Test Suite appNavigation&search + # script: npm run build.e2e && SUITE="--suite authentication,listViews,navigation,application,pagination,search" npm run e2e:docker + # - name: Test Suite actionsAvailable + # script: npm run build.e2e && SUITE="--suite actionsAvailable" npm run e2e:docker + # - name: Test Suite addRemoveContent + # script: npm run build.e2e && SUITE="--suite addRemoveContent" npm run e2e:docker + # - name: Test Suite manageContent + # script: npm run build.e2e && SUITE="--suite manageContent" npm run e2e:docker + # - name: Test Suite sharingContent&markFavorite + # script: npm run build.e2e && SUITE="--suite sharingContent" npm run e2e:docker + # - name: Test Suite viewContent&metadata&extensions + # script: npm run build.e2e && SUITE="--suite viewer,infoDrawer,extensions" npm run e2e:docker + name: Test Suite search + script: npm run build.e2e && SUITE="--suite search" npm run e2e:docker after_failure: - alfrescoContainerId=$(docker ps -a | grep 'alfresco-content-repository-community' | awk '{print $1}') diff --git a/e2e/components/search/filters/facet-filter.ts b/e2e/components/search/filters/facet-filter.ts index 942524e9c..99798862a 100755 --- a/e2e/components/search/filters/facet-filter.ts +++ b/e2e/components/search/filters/facet-filter.ts @@ -23,7 +23,7 @@ * along with Alfresco. If not, see . */ -import { ElementFinder, ElementArrayFinder, by } from 'protractor'; +import { ElementFinder, ElementArrayFinder, by, browser } from 'protractor'; import { GenericFilterPanel } from './generic-filter-panel'; export class FacetFilter extends GenericFilterPanel { @@ -85,7 +85,8 @@ export class FacetFilter extends GenericFilterPanel { async checkCategory(name: string): Promise { const option = this.facets.filter(async (elem) => (await elem.getText()).includes(name)).first(); - await option.click(); + await browser.actions().mouseMove(option).perform(); + await browser.actions().click().perform(); } async filterCategoriesBy(name: string): Promise { From 821d0fc106f1708b08858595d5a12b7b49110901 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Sun, 5 Jan 2020 23:24:16 +0200 Subject: [PATCH 39/96] another try --- e2e/components/search/filters/facet-filter.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/e2e/components/search/filters/facet-filter.ts b/e2e/components/search/filters/facet-filter.ts index 99798862a..89fa6de41 100755 --- a/e2e/components/search/filters/facet-filter.ts +++ b/e2e/components/search/filters/facet-filter.ts @@ -85,6 +85,7 @@ export class FacetFilter extends GenericFilterPanel { async checkCategory(name: string): Promise { const option = this.facets.filter(async (elem) => (await elem.getText()).includes(name)).first(); + await browser.executeScript(`arguments[0].scrollIntoView();`, option); await browser.actions().mouseMove(option).perform(); await browser.actions().click().perform(); } From 8496df6a987cdf7c4de320abd8bfd7b977a8868c Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Mon, 6 Jan 2020 00:39:45 +0200 Subject: [PATCH 40/96] re-enable all tests on travis --- .travis.yml | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9c54c308d..0e022904a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,20 +33,18 @@ jobs: - npm run test:ci - bash <(curl -s https://codecov.io/bash) -X gcov - stage: e2e - # name: Test Suite appNavigation&search - # script: npm run build.e2e && SUITE="--suite authentication,listViews,navigation,application,pagination,search" npm run e2e:docker - # - name: Test Suite actionsAvailable - # script: npm run build.e2e && SUITE="--suite actionsAvailable" npm run e2e:docker - # - name: Test Suite addRemoveContent - # script: npm run build.e2e && SUITE="--suite addRemoveContent" npm run e2e:docker - # - name: Test Suite manageContent - # script: npm run build.e2e && SUITE="--suite manageContent" npm run e2e:docker - # - name: Test Suite sharingContent&markFavorite - # script: npm run build.e2e && SUITE="--suite sharingContent" npm run e2e:docker - # - name: Test Suite viewContent&metadata&extensions - # script: npm run build.e2e && SUITE="--suite viewer,infoDrawer,extensions" npm run e2e:docker - name: Test Suite search - script: npm run build.e2e && SUITE="--suite search" npm run e2e:docker + name: Test Suite appNavigation&search + script: npm run build.e2e && SUITE="--suite authentication,listViews,navigation,application,pagination,search" npm run e2e:docker + - name: Test Suite actionsAvailable + script: npm run build.e2e && SUITE="--suite actionsAvailable" npm run e2e:docker + - name: Test Suite addRemoveContent + script: npm run build.e2e && SUITE="--suite addRemoveContent" npm run e2e:docker + - name: Test Suite manageContent + script: npm run build.e2e && SUITE="--suite manageContent" npm run e2e:docker + - name: Test Suite sharingContent&markFavorite + script: npm run build.e2e && SUITE="--suite sharingContent" npm run e2e:docker + - name: Test Suite viewContent&metadata&extensions + script: npm run build.e2e && SUITE="--suite viewer,infoDrawer,extensions" npm run e2e:docker after_failure: - alfrescoContainerId=$(docker ps -a | grep 'alfresco-content-repository-community' | awk '{print $1}') From 9e946361722e8920e2d0418df25dfcf8e1423b54 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Mon, 6 Jan 2020 01:07:25 +0200 Subject: [PATCH 41/96] small change to trigger travis --- e2e/pages/search-results-page.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/e2e/pages/search-results-page.ts b/e2e/pages/search-results-page.ts index ba75bbf41..c6895a645 100755 --- a/e2e/pages/search-results-page.ts +++ b/e2e/pages/search-results-page.ts @@ -70,7 +70,6 @@ export class SearchResultsPage extends BrowsingPage { async removeChip(chipName: string): Promise { const chip: ElementFinder = browser.element(By.cssContainingText(SearchResultsPage.selectors.chip, chipName)); const closeChip: ElementFinder = chip.element(by.css(SearchResultsPage.selectors.chipCloseIcon)); - await closeChip.click(); } } From e44a35f65635181bc4624ea5a9c3cbca00ee608a Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Mon, 6 Jan 2020 01:18:38 +0200 Subject: [PATCH 42/96] re-format travis.yml --- .travis.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0e022904a..8b0fe2f95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,18 +33,18 @@ jobs: - npm run test:ci - bash <(curl -s https://codecov.io/bash) -X gcov - stage: e2e - name: Test Suite appNavigation&search - script: npm run build.e2e && SUITE="--suite authentication,listViews,navigation,application,pagination,search" npm run e2e:docker - - name: Test Suite actionsAvailable - script: npm run build.e2e && SUITE="--suite actionsAvailable" npm run e2e:docker - - name: Test Suite addRemoveContent - script: npm run build.e2e && SUITE="--suite addRemoveContent" npm run e2e:docker - - name: Test Suite manageContent - script: npm run build.e2e && SUITE="--suite manageContent" npm run e2e:docker - - name: Test Suite sharingContent&markFavorite - script: npm run build.e2e && SUITE="--suite sharingContent" npm run e2e:docker - - name: Test Suite viewContent&metadata&extensions - script: npm run build.e2e && SUITE="--suite viewer,infoDrawer,extensions" npm run e2e:docker + name: Test Suite appNavigation&search + script: npm run build.e2e && SUITE="--suite authentication,listViews,navigation,application,pagination,search" npm run e2e:docker + - name: Test Suite actionsAvailable + script: npm run build.e2e && SUITE="--suite actionsAvailable" npm run e2e:docker + - name: Test Suite addRemoveContent + script: npm run build.e2e && SUITE="--suite addRemoveContent" npm run e2e:docker + - name: Test Suite manageContent + script: npm run build.e2e && SUITE="--suite manageContent" npm run e2e:docker + - name: Test Suite sharingContent&markFavorite + script: npm run build.e2e && SUITE="--suite sharingContent" npm run e2e:docker + - name: Test Suite viewContent&metadata&extensions + script: npm run build.e2e && SUITE="--suite viewer,infoDrawer,extensions" npm run e2e:docker after_failure: - alfrescoContainerId=$(docker ps -a | grep 'alfresco-content-repository-community' | awk '{print $1}') From 9007d40a8e387396fcd1cbf1b3e7357561a68c53 Mon Sep 17 00:00:00 2001 From: Martin Muller Date: Mon, 6 Jan 2020 13:33:39 +0100 Subject: [PATCH 43/96] [ACA-2755] SSO: Simplify changing alfresco-js-api (#1290) * include alfresco-js-api * provide update submodules as reset for the submodules --- .gitmodules | 3 +++ alfresco-js-api | 1 + init-submodules.sh | 2 ++ package.json | 1 + scripts/install-local-js-api.sh | 8 ++++++++ start-sso.sh | 18 ------------------ start.sh | 2 +- update-submodules.sh | 14 ++++++++++++++ 8 files changed, 30 insertions(+), 19 deletions(-) create mode 100644 .gitmodules create mode 160000 alfresco-js-api create mode 100755 init-submodules.sh create mode 100755 scripts/install-local-js-api.sh delete mode 100755 start-sso.sh create mode 100755 update-submodules.sh diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..8278f1344 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "alfresco-js-api"] + path = alfresco-js-api + url = https://github.com/Alfresco/alfresco-js-api diff --git a/alfresco-js-api b/alfresco-js-api new file mode 160000 index 000000000..a7e88e552 --- /dev/null +++ b/alfresco-js-api @@ -0,0 +1 @@ +Subproject commit a7e88e55269df1969c98340516290555738df18b diff --git a/init-submodules.sh b/init-submodules.sh new file mode 100755 index 000000000..9dcb97458 --- /dev/null +++ b/init-submodules.sh @@ -0,0 +1,2 @@ +#!/bin/bash +git submodule update --init diff --git a/package.json b/package.json index bb73e46c7..625f35d16 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build.extensions": "npm run build:aos-extension", "build.app": "node --max-old-space-size=8192 node_modules/@angular/cli/bin/ng build app", "build": "npm run validate-config && npm run build.shared && npm run build.extensions && npm run build.app -- --prod", + "build.js-api": "./init-submodules.sh && ./scripts/install-local-js-api.sh && npm run build", "build.e2e": "npm run build.shared && npm run build.extensions && npm run build.app -- --prod --configuration=e2e", "test": "ng test app --code-coverage", "test:ci": "npm run build.shared && npm run build.extensions && ng test adf-office-services-ext --watch=false && ng test app --code-coverage --watch=false", diff --git a/scripts/install-local-js-api.sh b/scripts/install-local-js-api.sh new file mode 100755 index 000000000..f1849891e --- /dev/null +++ b/scripts/install-local-js-api.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +rm -rf node_modules +./alfresco-js-api/scripts/build.sh +npm install +rm -rf node_modules/@alfresco/js-api +mkdir -p node_modules/@alfresco/js-api +cp -rf alfresco-js-api/dist/package/* node_modules/@alfresco/js-api diff --git a/start-sso.sh b/start-sso.sh deleted file mode 100755 index dd5054dd3..000000000 --- a/start-sso.sh +++ /dev/null @@ -1,18 +0,0 @@ -export HOST_IP=$(ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1) -export APP_URL="http://${HOST_IP}:8080" - -export APP_CONFIG_AUTH_TYPE="OAUTH" -export APP_CONFIG_OAUTH2_HOST="http://${HOST_IP}:8085/auth/realms/alfresco" -export APP_CONFIG_OAUTH2_CLIENTID="alfresco" -export APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI="${APP_URL}/assets/silent-refresh.html" -export APP_CONFIG_OAUTH2_REDIRECT_LOGIN="/" -export APP_CONFIG_OAUTH2_REDIRECT_LOGOUT="/logout" - -docker-compose -f docker-compose-keycloak.yml up -d --build - -echo "Waiting for the app..." -npm run wait:app - -echo "HOST_IP: ${HOST_IP}" -echo "Realm: ${APP_CONFIG_OAUTH2_HOST}" -echo "Content Workspace: ${APP_URL}" diff --git a/start.sh b/start.sh index 34de17fc8..7beafa428 100755 --- a/start.sh +++ b/start.sh @@ -70,7 +70,7 @@ if [[ $KEYCLOAK == "true" ]]; then export APP_CONFIG_OAUTH2_CLIENTID="alfresco" export APP_CONFIG_OAUTH2_IMPLICIT_FLOW=true export APP_CONFIG_OAUTH2_SILENT_LOGIN=true - export APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI="${APP_URL}assets/silent-refresh.html" + export APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI="${APP_URL}/assets/silent-refresh.html" export APP_CONFIG_OAUTH2_REDIRECT_LOGIN="/$URL_FRAGMENT/" export APP_CONFIG_OAUTH2_REDIRECT_LOGOUT="/$URL_FRAGMENT/logout" # export APP_BASE_SHARE_URL="${APP_URL}#/preview/s" diff --git a/update-submodules.sh b/update-submodules.sh new file mode 100755 index 000000000..69a420d24 --- /dev/null +++ b/update-submodules.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +git pull +git submodule sync --recursive +git submodule update --init --recursive +# Go through all of the submodules switching them to their branches and updating them + +echo +echo "Updating alfresco-js-api ..." +echo -------------------------- +cd alfresco-js-api && git checkout master && git pull +cd .. + +echo From e17de2f7331d1ea89ad4c8472e4b0cdf650cf4a3 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Tue, 7 Jan 2020 14:23:50 +0200 Subject: [PATCH 44/96] reorganize the tests so that the comment is created closer to the moment when comment created date is checked, in order to avoid this flaky fail: (#1293) Expected 'a few seconds ago' to be 'a minute ago', 'Incorrect comment created time'. --- e2e/suites/info-drawer/comments.test.ts | 181 +++++++++++++----------- 1 file changed, 95 insertions(+), 86 deletions(-) diff --git a/e2e/suites/info-drawer/comments.test.ts b/e2e/suites/info-drawer/comments.test.ts index b7a76fe6d..d250c7fde 100755 --- a/e2e/suites/info-drawer/comments.test.ts +++ b/e2e/suites/info-drawer/comments.test.ts @@ -75,8 +75,6 @@ describe('Comments', () => { fileWith1CommentId = (await apis.user.nodes.createFile(fileWith1Comment, parentId)).entry.id; fileWith2CommentsId = (await apis.user.nodes.createFile(fileWith2Comments, parentId)).entry.id; - commentFile1Entry = (await apis.user.comments.addComment(fileWith1CommentId, 'this is my comment')).entry; - comment1File2Entry = (await apis.user.comments.addComment(fileWith2CommentsId, 'first comment')).entry; comment2File2Entry = (await apis.user.comments.addComment(fileWith2CommentsId, 'second comment')).entry; @@ -96,6 +94,11 @@ describe('Comments', () => { done(); }); + afterEach(async (done) => { + await page.clickPersonalFiles(); + done(); + }); + describe('from Personal Files', () => { beforeEach(async (done) => { await page.clickPersonalFilesAndWait(); @@ -115,23 +118,6 @@ describe('Comments', () => { expect(await commentsTab.isAddCommentButtonEnabled()).toBe(false, 'Add comment button not disabled'); }); - it('Comment info display - [C280582]', async () => { - await dataTable.selectItem(fileWith1Comment); - await page.toolbar.clickViewDetails(); - await infoDrawer.waitForInfoDrawerToOpen(); - await infoDrawer.clickCommentsTab(); - - expect(await commentsTab.getCommentsTabHeaderText()).toBe('Comments (1)'); - expect(await commentsTab.isCommentTextAreaDisplayed()).toBe(true, 'Comment field not present'); - expect(await commentsTab.isAddCommentButtonEnabled()).toBe(false, 'Add comment button not disabled'); - - expect(await commentsTab.isCommentDisplayed(commentFile1Entry.id)).toBe(true, `Comment with id: ${commentFile1Entry.id} not displayed`); - expect(await commentsTab.getCommentText(commentFile1Entry.id)).toBe(commentFile1Entry.content, 'Incorrect comment text'); - expect(await commentsTab.getCommentUserName(commentFile1Entry.id)).toBe(`${username} ${username}`, 'Incorrect comment user'); - expect(await commentsTab.getCommentTime(commentFile1Entry.id)).toBe(moment(commentFile1Entry.createdAt).fromNow(), 'Incorrect comment created time'); - expect(await commentsTab.isCommentUserAvatarDisplayed(commentFile1Entry.id)).toBe(true, 'User avatar not displayed'); - }); - it('Comments are displayed ordered by created date in descending order - [C280583]', async () => { await dataTable.selectItem(fileWith2Comments); await page.toolbar.clickViewDetails(); @@ -219,29 +205,6 @@ describe('Comments', () => { done(); }); - afterEach(async (done) => { - await page.clickPersonalFiles(); - done(); - }); - - it('Comment info display - [C299196]', async () => { - await dataTable.selectItem(fileWith1Comment); - await page.toolbar.clickViewDetails(); - await infoDrawer.waitForInfoDrawerToOpen(); - await infoDrawer.clickCommentsTab(); - - expect(await commentsTab.getCommentsTabHeaderText()).toBe('Comments (1)'); - expect(await commentsTab.isCommentTextAreaDisplayed()).toBe(true, 'Comment field not present'); - expect(await commentsTab.isAddCommentButtonEnabled()).toBe(false, 'Add comment button not disabled'); - - expect(await commentsTab.isCommentDisplayed(commentFile1Entry.id)).toBe(true, `Comment with id: ${commentFile1Entry.id} not displayed`); - expect(await commentsTab.getCommentText(commentFile1Entry.id)).toBe(commentFile1Entry.content, 'Incorrect comment text'); - expect(await commentsTab.getCommentUserName(commentFile1Entry.id)).toBe(`${username} ${username}`, 'Incorrect comment user'); - // ACA-2348 expect broken because of parallel test suites - // expect(await commentsTab.getCommentTime(commentFile1Entry.id)).toBe(moment(commentFile1Entry.createdAt).fromNow(), 'Incorrect comment created time'); - expect(await commentsTab.isCommentUserAvatarDisplayed(commentFile1Entry.id)).toBe(true, 'User avatar not displayed'); - }); - it('Comments are displayed ordered by created date in descending order - [C299197]', async () => { await dataTable.selectItem(fileWith2Comments); await page.toolbar.clickViewDetails(); @@ -303,28 +266,6 @@ describe('Comments', () => { done(); }); - afterEach(async (done) => { - await page.clickPersonalFiles(); - done(); - }); - - it('Comment info display - [C299188]', async () => { - await dataTable.selectItem(fileWith1Comment); - await page.toolbar.clickViewDetails(); - await infoDrawer.waitForInfoDrawerToOpen(); - await infoDrawer.clickCommentsTab(); - - expect(await commentsTab.getCommentsTabHeaderText()).toBe('Comments (1)'); - expect(await commentsTab.isCommentTextAreaDisplayed()).toBe(true, 'Comment field not present'); - expect(await commentsTab.isAddCommentButtonEnabled()).toBe(false, 'Add comment button not disabled'); - - expect(await commentsTab.isCommentDisplayed(commentFile1Entry.id)).toBe(true, `Comment with id: ${commentFile1Entry.id} not displayed`); - expect(await commentsTab.getCommentText(commentFile1Entry.id)).toBe(commentFile1Entry.content, 'Incorrect comment text'); - expect(await commentsTab.getCommentUserName(commentFile1Entry.id)).toBe(`${username} ${username}`, 'Incorrect comment user'); - expect(await commentsTab.getCommentTime(commentFile1Entry.id)).toBe(moment(commentFile1Entry.createdAt).fromNow(), 'Incorrect comment created time'); - expect(await commentsTab.isCommentUserAvatarDisplayed(commentFile1Entry.id)).toBe(true, 'User avatar not displayed'); - }); - it('Comments are displayed ordered by created date in descending order - [C299189]', async () => { await dataTable.selectItem(fileWith2Comments); await page.toolbar.clickViewDetails(); @@ -371,28 +312,6 @@ describe('Comments', () => { done(); }); - afterEach(async (done) => { - await page.clickPersonalFiles(); - done(); - }); - - it('Comment info display - [C299192]', async () => { - await dataTable.selectItem(fileWith1Comment); - await page.toolbar.clickViewDetails(); - await infoDrawer.waitForInfoDrawerToOpen(); - await infoDrawer.clickCommentsTab(); - - expect(await commentsTab.getCommentsTabHeaderText()).toBe('Comments (1)'); - expect(await commentsTab.isCommentTextAreaDisplayed()).toBe(true, 'Comment field not present'); - expect(await commentsTab.isAddCommentButtonEnabled()).toBe(false, 'Add comment button not disabled'); - - expect(await commentsTab.isCommentDisplayed(commentFile1Entry.id)).toBe(true, `Comment with id: ${commentFile1Entry.id} not displayed`); - expect(await commentsTab.getCommentText(commentFile1Entry.id)).toBe(commentFile1Entry.content, 'Incorrect comment text'); - expect(await commentsTab.getCommentUserName(commentFile1Entry.id)).toBe(`${username} ${username}`, 'Incorrect comment user'); - expect(await commentsTab.getCommentTime(commentFile1Entry.id)).toBe(moment(commentFile1Entry.createdAt).fromNow(), 'Incorrect comment created time'); - expect(await commentsTab.isCommentUserAvatarDisplayed(commentFile1Entry.id)).toBe(true, 'User avatar not displayed'); - }); - it('Comments are displayed ordered by created date in descending order - [C299193]', async () => { await dataTable.selectItem(fileWith2Comments); await page.toolbar.clickViewDetails(); @@ -428,4 +347,94 @@ describe('Comments', () => { }); }); + describe('Comment info display', () => { + beforeAll(async (done) => { + commentFile1Entry = (await apis.user.comments.addComment(fileWith1CommentId, 'this is my comment')).entry; + + await apis.user.favorites.waitForApi({ expect: 4 }); + await apis.user.shared.waitForApi({ expect: 3 }); + await apis.user.search.waitForApi(username, { expect: 7 }); + + done(); + }); + + it('File from Personal files - [C280582]', async () => { + await page.clickPersonalFilesAndWait(); + await dataTable.doubleClickOnRowByName(parent); + + await dataTable.selectItem(fileWith1Comment); + await page.toolbar.clickViewDetails(); + await infoDrawer.waitForInfoDrawerToOpen(); + await infoDrawer.clickCommentsTab(); + + expect(await commentsTab.getCommentsTabHeaderText()).toBe('Comments (1)'); + expect(await commentsTab.isCommentTextAreaDisplayed()).toBe(true, 'Comment field not present'); + expect(await commentsTab.isAddCommentButtonEnabled()).toBe(false, 'Add comment button not disabled'); + + expect(await commentsTab.isCommentDisplayed(commentFile1Entry.id)).toBe(true, `Comment with id: ${commentFile1Entry.id} not displayed`); + expect(await commentsTab.getCommentText(commentFile1Entry.id)).toBe(commentFile1Entry.content, 'Incorrect comment text'); + expect(await commentsTab.getCommentUserName(commentFile1Entry.id)).toBe(`${username} ${username}`, 'Incorrect comment user'); + expect(await commentsTab.getCommentTime(commentFile1Entry.id)).toBe(moment(commentFile1Entry.createdAt).fromNow(), 'Incorrect comment created time'); + expect(await commentsTab.isCommentUserAvatarDisplayed(commentFile1Entry.id)).toBe(true, 'User avatar not displayed'); + }); + + it('File from Favorites - [C299196]', async () => { + await page.clickFavoritesAndWait(); + + await dataTable.selectItem(fileWith1Comment); + await page.toolbar.clickViewDetails(); + await infoDrawer.waitForInfoDrawerToOpen(); + await infoDrawer.clickCommentsTab(); + + expect(await commentsTab.getCommentsTabHeaderText()).toBe('Comments (1)'); + expect(await commentsTab.isCommentTextAreaDisplayed()).toBe(true, 'Comment field not present'); + expect(await commentsTab.isAddCommentButtonEnabled()).toBe(false, 'Add comment button not disabled'); + + expect(await commentsTab.isCommentDisplayed(commentFile1Entry.id)).toBe(true, `Comment with id: ${commentFile1Entry.id} not displayed`); + expect(await commentsTab.getCommentText(commentFile1Entry.id)).toBe(commentFile1Entry.content, 'Incorrect comment text'); + expect(await commentsTab.getCommentUserName(commentFile1Entry.id)).toBe(`${username} ${username}`, 'Incorrect comment user'); + expect(await commentsTab.getCommentTime(commentFile1Entry.id)).toBe(moment(commentFile1Entry.createdAt).fromNow(), 'Incorrect comment created time'); + expect(await commentsTab.isCommentUserAvatarDisplayed(commentFile1Entry.id)).toBe(true, 'User avatar not displayed'); + }); + + it('File from Shared Files - [C299188]', async () => { + await page.clickSharedFilesAndWait(); + + await dataTable.selectItem(fileWith1Comment); + await page.toolbar.clickViewDetails(); + await infoDrawer.waitForInfoDrawerToOpen(); + await infoDrawer.clickCommentsTab(); + + expect(await commentsTab.getCommentsTabHeaderText()).toBe('Comments (1)'); + expect(await commentsTab.isCommentTextAreaDisplayed()).toBe(true, 'Comment field not present'); + expect(await commentsTab.isAddCommentButtonEnabled()).toBe(false, 'Add comment button not disabled'); + + expect(await commentsTab.isCommentDisplayed(commentFile1Entry.id)).toBe(true, `Comment with id: ${commentFile1Entry.id} not displayed`); + expect(await commentsTab.getCommentText(commentFile1Entry.id)).toBe(commentFile1Entry.content, 'Incorrect comment text'); + expect(await commentsTab.getCommentUserName(commentFile1Entry.id)).toBe(`${username} ${username}`, 'Incorrect comment user'); + expect(await commentsTab.getCommentTime(commentFile1Entry.id)).toBe(moment(commentFile1Entry.createdAt).fromNow(), 'Incorrect comment created time'); + expect(await commentsTab.isCommentUserAvatarDisplayed(commentFile1Entry.id)).toBe(true, 'User avatar not displayed'); + }); + + it('File from Recent Files - [C299192]', async () => { + await page.clickRecentFilesAndWait(); + + await dataTable.selectItem(fileWith1Comment); + await page.toolbar.clickViewDetails(); + await infoDrawer.waitForInfoDrawerToOpen(); + await infoDrawer.clickCommentsTab(); + + expect(await commentsTab.getCommentsTabHeaderText()).toBe('Comments (1)'); + expect(await commentsTab.isCommentTextAreaDisplayed()).toBe(true, 'Comment field not present'); + expect(await commentsTab.isAddCommentButtonEnabled()).toBe(false, 'Add comment button not disabled'); + + expect(await commentsTab.isCommentDisplayed(commentFile1Entry.id)).toBe(true, `Comment with id: ${commentFile1Entry.id} not displayed`); + expect(await commentsTab.getCommentText(commentFile1Entry.id)).toBe(commentFile1Entry.content, 'Incorrect comment text'); + expect(await commentsTab.getCommentUserName(commentFile1Entry.id)).toBe(`${username} ${username}`, 'Incorrect comment user'); + expect(await commentsTab.getCommentTime(commentFile1Entry.id)).toBe(moment(commentFile1Entry.createdAt).fromNow(), 'Incorrect comment created time'); + expect(await commentsTab.isCommentUserAvatarDisplayed(commentFile1Entry.id)).toBe(true, 'User avatar not displayed'); + }); + + }); + }); From acdda231c40d29d1e09ae01a69e2e1ecd34055e4 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Tue, 7 Jan 2020 20:28:35 +0200 Subject: [PATCH 45/96] user menu options components --- src/app/components/common/common.module.ts | 20 +++++++-- .../language-picker.component.ts | 39 ++++++++++++++++ .../common/logout/logout.component.ts | 44 +++++++++++++++++++ 3 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 src/app/components/common/language-picker/language-picker.component.ts create mode 100644 src/app/components/common/logout/logout.component.ts diff --git a/src/app/components/common/common.module.ts b/src/app/components/common/common.module.ts index 17ac4f12f..a1c972395 100644 --- a/src/app/components/common/common.module.ts +++ b/src/app/components/common/common.module.ts @@ -30,6 +30,8 @@ import { NgModule } from '@angular/core'; import { GenericErrorModule } from '@alfresco/aca-shared'; import { LocationLinkComponent } from './location-link/location-link.component'; import { ToggleSharedComponent } from './toggle-shared/toggle-shared.component'; +import { LanguagePickerComponent } from './language-picker/language-picker.component'; +import { LogoutComponent } from './logout/logout.component'; @NgModule({ imports: [ @@ -38,13 +40,25 @@ import { ToggleSharedComponent } from './toggle-shared/toggle-shared.component'; ExtensionsModule, GenericErrorModule ], - declarations: [LocationLinkComponent, ToggleSharedComponent], + declarations: [ + LocationLinkComponent, + ToggleSharedComponent, + LanguagePickerComponent, + LogoutComponent + ], exports: [ ExtensionsModule, LocationLinkComponent, GenericErrorModule, - ToggleSharedComponent + ToggleSharedComponent, + LanguagePickerComponent, + LogoutComponent ], - entryComponents: [LocationLinkComponent, ToggleSharedComponent] + entryComponents: [ + LocationLinkComponent, + ToggleSharedComponent, + LanguagePickerComponent, + LogoutComponent + ] }) export class AppCommonModule {} diff --git a/src/app/components/common/language-picker/language-picker.component.ts b/src/app/components/common/language-picker/language-picker.component.ts new file mode 100644 index 000000000..2cf2db380 --- /dev/null +++ b/src/app/components/common/language-picker/language-picker.component.ts @@ -0,0 +1,39 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Component } from '@angular/core'; + +@Component({ + selector: 'aca-language-picker', + template: ` + + + + + ` +}) +export class LanguagePickerComponent {} diff --git a/src/app/components/common/logout/logout.component.ts b/src/app/components/common/logout/logout.component.ts new file mode 100644 index 000000000..619193a3b --- /dev/null +++ b/src/app/components/common/logout/logout.component.ts @@ -0,0 +1,44 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Component } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppStore, SetSelectedNodesAction } from '@alfresco/aca-shared/store'; + +@Component({ + selector: 'aca-logout', + template: ` + + ` +}) +export class LogoutComponent { + constructor(private store: Store) {} + + onLogoutEvent() { + this.store.dispatch(new SetSelectedNodesAction([])); + } +} From 5396b3591cca946e971a80845b637fa55909ea8f Mon Sep 17 00:00:00 2001 From: pionnegru Date: Tue, 7 Jan 2020 20:29:47 +0200 Subject: [PATCH 46/96] update extensions module --- src/app/extensions/core.extensions.module.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/extensions/core.extensions.module.ts b/src/app/extensions/core.extensions.module.ts index 60d317cc2..60bdb9b2e 100644 --- a/src/app/extensions/core.extensions.module.ts +++ b/src/app/extensions/core.extensions.module.ts @@ -51,6 +51,8 @@ import { } from '@alfresco/adf-content-services'; import { ToggleSharedComponent } from '../components/common/toggle-shared/toggle-shared.component'; import { ViewNodeComponent } from '../components/toolbar/view-node/view-node.component'; +import { LanguagePickerComponent } from '../components/common/language-picker/language-picker.component'; +import { LogoutComponent } from '../components/common/logout/logout.component'; export function setupExtensions(service: AppExtensionService): Function { return () => service.load(); @@ -101,7 +103,9 @@ export class CoreExtensionsModule { 'app.columns.trashcanName': TrashcanNameColumnComponent, 'app.columns.location': LocationLinkComponent, 'app.toolbar.toggleEditOffline': ToggleEditOfflineComponent, - 'app.toolbar.viewNode': ViewNodeComponent + 'app.toolbar.viewNode': ViewNodeComponent, + 'app.languagePicker': LanguagePickerComponent, + 'app.logout': LogoutComponent }); extensions.setAuthGuards({ From 427ae8aeff982a8af5f852d1a768e65624952009 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Tue, 7 Jan 2020 20:31:50 +0200 Subject: [PATCH 47/96] user options extension and rules --- projects/aca-shared/rules/src/app.rules.ts | 23 ++++++++++++++++ src/app/extensions/core.extensions.module.ts | 4 ++- src/app/extensions/extension.service.ts | 28 +++++++++++++++++++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/projects/aca-shared/rules/src/app.rules.ts b/projects/aca-shared/rules/src/app.rules.ts index 426d49eab..3c53c5ca4 100644 --- a/projects/aca-shared/rules/src/app.rules.ts +++ b/projects/aca-shared/rules/src/app.rules.ts @@ -27,6 +27,11 @@ import { RuleContext } from '@alfresco/adf-extensions'; import * as navigation from './navigation.rules'; import * as repository from './repository.rules'; +export interface AcaRuleContext extends RuleContext { + languagePicker: boolean; + withCredentials: boolean; +} + /** * Checks if user can copy selected node. * JSON ref: `app.canCopyNode` @@ -526,3 +531,21 @@ export function canToggleFavorite(context: RuleContext): boolean { ].some(Boolean) ].every(Boolean); } + +/** + * Checks if application should render language picker menu. + * JSON ref: `canShowLanguagePicker` + * @param context Rule execution context + */ +export function canShowLanguagePicker(context: AcaRuleContext): boolean { + return context.languagePicker; +} + +/** + * Checks if application should render logout option. + * JSON ref: `canShowLogout` + * @param context Rule execution context + */ +export function canShowLogout(context: AcaRuleContext): boolean { + return !context.withCredentials; +} diff --git a/src/app/extensions/core.extensions.module.ts b/src/app/extensions/core.extensions.module.ts index 60bdb9b2e..54cfca4f1 100644 --- a/src/app/extensions/core.extensions.module.ts +++ b/src/app/extensions/core.extensions.module.ts @@ -170,7 +170,9 @@ export class CoreExtensionsModule { 'app.navigation.isSharedFileViewer': rules.isSharedFileViewer, 'repository.isQuickShareEnabled': rules.hasQuickShareEnabled, - 'user.isAdmin': rules.isAdmin + 'user.isAdmin': rules.isAdmin, + 'app.canShowLanguagePicker': rules.canShowLanguagePicker, + 'app.canShowLogout': rules.canShowLogout }); } } diff --git a/src/app/extensions/extension.service.ts b/src/app/extensions/extension.service.ts index 89937256c..363ef3a48 100644 --- a/src/app/extensions/extension.service.ts +++ b/src/app/extensions/extension.service.ts @@ -28,7 +28,11 @@ import { Store } from '@ngrx/store'; import { Route } from '@angular/router'; import { MatIconRegistry } from '@angular/material/icon'; import { DomSanitizer } from '@angular/platform-browser'; -import { AppStore, getRuleContext } from '@alfresco/aca-shared/store'; +import { + AppStore, + getRuleContext, + getLanguagePickerState +} from '@alfresco/aca-shared/store'; import { NodePermissionService } from '@alfresco/aca-shared'; import { SelectionState, @@ -78,6 +82,7 @@ export class AppExtensionService implements RuleContext { sidebar: Array = []; contentMetadata: any; viewerRules: ViewerRules = {}; + userActions: Array = []; documentListPresets: { files: Array; @@ -103,6 +108,8 @@ export class AppExtensionService implements RuleContext { navigation: NavigationState; profile: ProfileState; repository: RepositoryInfo; + withCredentials: boolean; + languagePicker: boolean; references$: Observable; @@ -124,6 +131,10 @@ export class AppExtensionService implements RuleContext { this.profile = result.profile; this.repository = result.repository; }); + + this.store.select(getLanguagePickerState).subscribe(result => { + this.languagePicker = result; + }); } async load() { @@ -170,6 +181,10 @@ export class AppExtensionService implements RuleContext { config, 'features.sidebar' ); + this.userActions = this.loader.getContentActions( + config, + 'features.userActions' + ); this.contentMetadata = this.loadContentMetadata(config); this.documentListPresets = { @@ -186,6 +201,11 @@ export class AppExtensionService implements RuleContext { searchLibraries: this.getDocumentListPreset(config, 'search-libraries') }; + this.withCredentials = this.appConfig.get( + 'auth.withCredentials', + false + ); + if (config.features && config.features.viewer) { this.viewerRules = (config.features.viewer['rules'] || {}); } @@ -473,6 +493,12 @@ export class AppExtensionService implements RuleContext { return this.getAllowedActions(this.contextMenuActions); } + getUserActions(): Array { + return this.userActions + .filter(action => this.filterVisible(action)) + .sort(sortByOrder); + } + copyAction(action: ContentActionRef): ContentActionRef { return { ...action, From 684a9a3d34aa9d006309ae4457d9c71b6820f638 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Tue, 7 Jan 2020 20:32:55 +0200 Subject: [PATCH 48/96] update extension schema --- extension.schema.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/extension.schema.json b/extension.schema.json index d9fe567aa..99f2bebcf 100644 --- a/extension.schema.json +++ b/extension.schema.json @@ -676,6 +676,12 @@ "items": { "$ref": "#/definitions/iconRef" }, "minItems": 1 }, + "userActions": { + "description": "User option menu extensions", + "type": "array", + "items": { "$ref": "#/definitions/contentActionRef" }, + "minItems": 1 + }, "header": { "description": "Application header extensions", "type": "array", From 29c0b697676f76b42be8b4665798fcf4d63714ca Mon Sep 17 00:00:00 2001 From: pionnegru Date: Tue, 7 Jan 2020 20:33:31 +0200 Subject: [PATCH 49/96] declare user actions entries --- src/assets/plugins/app.header.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/assets/plugins/app.header.json b/src/assets/plugins/app.header.json index 8e582c131..5ad36ae22 100644 --- a/src/assets/plugins/app.header.json +++ b/src/assets/plugins/app.header.json @@ -22,6 +22,26 @@ ], "features": { + "userActions": [ + { + "id": "app.languagePicker", + "order": 100, + "type": "custom", + "component": "app.languagePicker", + "rules": { + "visible": "app.canShowLanguagePicker" + } + }, + { + "id": "app.logout", + "order": 200, + "type": "custom", + "component": "app.logout", + "rules": { + "visible": "app.canShowLogout" + } + } + ], "header": [ { "id": "app.header.more", From 75b9b017ddf8a60987ad242dbdcc55883e2aaea8 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Tue, 7 Jan 2020 20:35:47 +0200 Subject: [PATCH 50/96] user menu option item component --- .../user-menu-item.component.html | 36 ++++++++++++ .../current-user/user-menu-item.component.ts | 58 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 src/app/components/current-user/user-menu-item.component.html create mode 100644 src/app/components/current-user/user-menu-item.component.ts diff --git a/src/app/components/current-user/user-menu-item.component.html b/src/app/components/current-user/user-menu-item.component.html new file mode 100644 index 000000000..a6209b143 --- /dev/null +++ b/src/app/components/current-user/user-menu-item.component.html @@ -0,0 +1,36 @@ + diff --git a/src/app/components/current-user/user-menu-item.component.ts b/src/app/components/current-user/user-menu-item.component.ts new file mode 100644 index 000000000..ea5e2c3c0 --- /dev/null +++ b/src/app/components/current-user/user-menu-item.component.ts @@ -0,0 +1,58 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Component, Input, ViewEncapsulation } from '@angular/core'; +import { ContentActionRef } from '@alfresco/adf-extensions'; +import { AppExtensionService } from '../../extensions/extension.service'; + +@Component({ + selector: 'app-user-menu-item', + templateUrl: 'user-menu-item.component.html', + encapsulation: ViewEncapsulation.None, + host: { class: 'app-user-menu-item' } +}) +export class UserMenuItemComponent { + @Input() + actionRef: ContentActionRef; + + constructor(private extensions: AppExtensionService) {} + + runAction() { + if (this.hasClickAction(this.actionRef)) { + this.extensions.runActionById(this.actionRef.actions.click); + } + } + + private hasClickAction(actionRef: ContentActionRef): boolean { + if (actionRef && actionRef.actions && actionRef.actions.click) { + return true; + } + return false; + } + + trackById(_: number, obj: { id: string }) { + return obj.id; + } +} From a8776241b63a201a3b0fed6bbc9340282494c561 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Tue, 7 Jan 2020 20:37:16 +0200 Subject: [PATCH 51/96] dynamically load user menu options --- .../current-user/current-user.component.html | 21 ++++----------- .../current-user/current-user.component.ts | 26 ++++++++++--------- .../current-user/current-user.module.ts | 13 +++++++--- 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/app/components/current-user/current-user.component.html b/src/app/components/current-user/current-user.component.html index a823127cb..87092e647 100644 --- a/src/app/components/current-user/current-user.component.html +++ b/src/app/components/current-user/current-user.component.html @@ -13,21 +13,10 @@ - - - - + + - - - - diff --git a/src/app/components/current-user/current-user.component.ts b/src/app/components/current-user/current-user.component.ts index 8016bc6a6..6ccb79e58 100644 --- a/src/app/components/current-user/current-user.component.ts +++ b/src/app/components/current-user/current-user.component.ts @@ -23,17 +23,16 @@ * along with Alfresco. If not, see . */ -import { Component, ViewEncapsulation } from '@angular/core'; +import { Component, ViewEncapsulation, OnInit } from '@angular/core'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; -import { ProfileState } from '@alfresco/adf-extensions'; +import { ProfileState, ContentActionRef } from '@alfresco/adf-extensions'; import { AppStore, - SetSelectedNodesAction, getUserProfile, getLanguagePickerState } from '@alfresco/aca-shared/store'; -import { AppService } from '@alfresco/aca-shared'; +import { AppExtensionService } from '../../extensions/extension.service'; @Component({ selector: 'aca-current-user', @@ -41,20 +40,23 @@ import { AppService } from '@alfresco/aca-shared'; encapsulation: ViewEncapsulation.None, host: { class: 'aca-current-user' } }) -export class CurrentUserComponent { +export class CurrentUserComponent implements OnInit { profile$: Observable; languagePicker$: Observable; + actions: Array = []; - get showLogout(): boolean { - return !this.appService.withCredentials; - } + constructor( + private store: Store, + private extensions: AppExtensionService + ) {} - constructor(private store: Store, private appService: AppService) { + ngOnInit() { this.profile$ = this.store.select(getUserProfile); - this.languagePicker$ = store.select(getLanguagePickerState); + this.languagePicker$ = this.store.select(getLanguagePickerState); + this.actions = this.extensions.getUserActions(); } - onLogoutEvent() { - this.store.dispatch(new SetSelectedNodesAction([])); + trackByActionId(_: number, action: ContentActionRef) { + return action.id; } } diff --git a/src/app/components/current-user/current-user.module.ts b/src/app/components/current-user/current-user.module.ts index 2fa14bc3b..77f47bc8b 100644 --- a/src/app/components/current-user/current-user.module.ts +++ b/src/app/components/current-user/current-user.module.ts @@ -26,12 +26,19 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { CoreModule } from '@alfresco/adf-core'; +import { ExtensionsModule } from '@alfresco/adf-extensions'; import { CurrentUserComponent } from './current-user.component'; +import { UserMenuItemComponent } from './user-menu-item.component'; import { RouterModule } from '@angular/router'; @NgModule({ - imports: [CommonModule, CoreModule.forChild(), RouterModule], - declarations: [CurrentUserComponent], - exports: [CurrentUserComponent] + imports: [ + CommonModule, + CoreModule.forChild(), + RouterModule, + ExtensionsModule + ], + declarations: [CurrentUserComponent, UserMenuItemComponent], + exports: [CurrentUserComponent, UserMenuItemComponent] }) export class AppCurrentUserModule {} From 673e1f4d755fc3e527095a5d83abf241b47e3b2e Mon Sep 17 00:00:00 2001 From: pionnegru Date: Tue, 7 Jan 2020 20:38:17 +0200 Subject: [PATCH 52/96] update docs --- docs/extending/rules.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/extending/rules.md b/docs/extending/rules.md index 7096c6c3d..7ca46ea0b 100644 --- a/docs/extending/rules.md +++ b/docs/extending/rules.md @@ -166,6 +166,8 @@ The button will be visible only when the linked rule evaluates to `true`. | 1.8.0 | canManagePermissions | Checks if user can manage permissions for the selected node. | | 1.8.0 | canToggleEditOffline | Checks if user can toggle **Edit Offline** mode for selected node. | | 1.8.0 | user.isAdmin | Checks if user is admin. | +| 1.9.0 | app.canShowLanguagePicker | Whether language picker menu should be present or not. | +| 1.9.0 | app.canShowLogout | Whether logout action should be present or not. | ## Navigation Evaluators From ea6eb8b8fc291b8a6708f2cfbbfe4e6ebb4aaa79 Mon Sep 17 00:00:00 2001 From: pionnegru Date: Tue, 7 Jan 2020 20:38:35 +0200 Subject: [PATCH 53/96] tests --- .../aca-shared/rules/src/app.rules.spec.ts | 36 +++++ .../common/logout/logout.component.spec.ts | 70 ++++++++++ .../current-user.component.spec.ts | 86 +++++++++++- .../user-menu-item.component.spec.ts | 126 ++++++++++++++++++ src/app/extensions/extension.service.spec.ts | 113 ++++++++++++++++ 5 files changed, 429 insertions(+), 2 deletions(-) create mode 100644 src/app/components/common/logout/logout.component.spec.ts create mode 100644 src/app/components/current-user/user-menu-item.component.spec.ts diff --git a/projects/aca-shared/rules/src/app.rules.spec.ts b/projects/aca-shared/rules/src/app.rules.spec.ts index 3306e147e..fc307bacd 100644 --- a/projects/aca-shared/rules/src/app.rules.spec.ts +++ b/projects/aca-shared/rules/src/app.rules.spec.ts @@ -439,4 +439,40 @@ describe('app.evaluators', () => { expect(app.isShared(context)).toBe(true); }); }); + + describe('canShowLanguagePicker', () => { + it('should return true when property is true', () => { + const context: any = { + languagePicker: true + }; + + expect(app.canShowLanguagePicker(context)).toBe(true); + }); + + it('should return false when property is false', () => { + const context: any = { + languagePicker: false + }; + + expect(app.canShowLanguagePicker(context)).toBe(false); + }); + }); + + describe('canShowLogout', () => { + it('should return false when `withCredentials` property is true', () => { + const context: any = { + withCredentials: true + }; + + expect(app.canShowLogout(context)).toBe(false); + }); + + it('should return true when `withCredentials` property is false', () => { + const context: any = { + withCredentials: false + }; + + expect(app.canShowLanguagePicker(context)).toBe(true); + }); + }); }); diff --git a/src/app/components/common/logout/logout.component.spec.ts b/src/app/components/common/logout/logout.component.spec.ts new file mode 100644 index 000000000..f5bbb839c --- /dev/null +++ b/src/app/components/common/logout/logout.component.spec.ts @@ -0,0 +1,70 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { + TranslateModule, + TranslateLoader, + TranslateFakeLoader +} from '@ngx-translate/core'; +import { LogoutComponent } from './logout.component'; +import { Store } from '@ngrx/store'; +import { SetSelectedNodesAction } from '@alfresco/aca-shared/store'; + +describe('LogoutComponent', () => { + let fixture: ComponentFixture; + let component: LogoutComponent; + let store; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } + }) + ], + declarations: [LogoutComponent], + providers: [ + { + provide: Store, + useValue: { + dispatch: jasmine.createSpy('dispatch') + } + } + ] + }); + + store = TestBed.get(Store); + fixture = TestBed.createComponent(LogoutComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should reset selected nodes from store', () => { + component.onLogoutEvent(); + + expect(store.dispatch).toHaveBeenCalledWith(new SetSelectedNodesAction([])); + }); +}); diff --git a/src/app/components/current-user/current-user.component.spec.ts b/src/app/components/current-user/current-user.component.spec.ts index cfb33145b..baef2170d 100644 --- a/src/app/components/current-user/current-user.component.spec.ts +++ b/src/app/components/current-user/current-user.component.spec.ts @@ -24,9 +24,91 @@ */ import { CurrentUserComponent } from './current-user.component'; +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { AppTestingModule } from '../../testing/app-testing.module'; +import { AppExtensionService } from '../../extensions/extension.service'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { + AppState, + SetUserProfileAction, + SetLanguagePickerAction +} from '@alfresco/aca-shared/store'; describe('CurrentUserComponent', () => { - it('should be defined', () => { - expect(CurrentUserComponent).toBeDefined(); + let fixture: ComponentFixture; + let component: CurrentUserComponent; + let appExtensionService; + let store: Store; + const person = { + entry: { + id: 'user-id', + firstName: 'Test', + lastName: 'User', + email: 'user@email.com', + enabled: true, + isAdmin: false, + userName: 'user-name' + } + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [AppTestingModule], + declarations: [CurrentUserComponent], + providers: [AppExtensionService], + schemas: [NO_ERRORS_SCHEMA] + }); + + fixture = TestBed.createComponent(CurrentUserComponent); + appExtensionService = TestBed.get(AppExtensionService); + store = TestBed.get(Store); + component = fixture.componentInstance; + }); + + it('should get profile data', done => { + const expectedProfile = { + firstName: 'Test', + lastName: 'User', + userName: 'Test User', + isAdmin: true, + id: 'user-id', + groups: [] + }; + + fixture.detectChanges(); + + store.dispatch( + new SetUserProfileAction({ person: person.entry, groups: [] }) + ); + + component.profile$.subscribe((profile: any) => { + expect(profile).toEqual(jasmine.objectContaining(expectedProfile)); + done(); + }); + }); + + it('should set language picker state', done => { + fixture.detectChanges(); + + store.dispatch(new SetLanguagePickerAction(true)); + + component.languagePicker$.subscribe((languagePicker: boolean) => { + expect(languagePicker).toBe(true); + done(); + }); + }); + + it('should set menu actions', () => { + const actions = [ + { + id: 'action-id' + } + ]; + spyOn(appExtensionService, 'getUserActions').and.returnValue(actions); + + fixture.detectChanges(); + + expect(component.actions).toBe(actions); }); }); diff --git a/src/app/components/current-user/user-menu-item.component.spec.ts b/src/app/components/current-user/user-menu-item.component.spec.ts new file mode 100644 index 000000000..7605d3c71 --- /dev/null +++ b/src/app/components/current-user/user-menu-item.component.spec.ts @@ -0,0 +1,126 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { AppTestingModule } from '../../testing/app-testing.module'; +import { AppExtensionService } from '../../extensions/extension.service'; +import { UserMenuItemComponent } from './user-menu-item.component'; +import { + TranslateModule, + TranslateLoader, + TranslateFakeLoader +} from '@ngx-translate/core'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ContentActionRef } from '@alfresco/adf-extensions'; + +describe('UserMenuItemComponent', () => { + let fixture: ComponentFixture; + let component: UserMenuItemComponent; + let appExtensionService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + AppTestingModule, + TranslateModule.forRoot({ + loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } + }) + ], + declarations: [UserMenuItemComponent], + providers: [AppExtensionService], + schemas: [NO_ERRORS_SCHEMA] + }); + + fixture = TestBed.createComponent(UserMenuItemComponent); + appExtensionService = TestBed.get(AppExtensionService); + component = fixture.componentInstance; + }); + + afterEach(() => { + fixture.destroy(); + }); + + it('should render button action', () => { + component.actionRef = { + id: 'action-button', + title: 'Test Button', + actions: { + click: 'TEST_EVENT' + } + } as ContentActionRef; + fixture.detectChanges(); + + const buttonElement = fixture.nativeElement.querySelector('#action-button'); + expect(buttonElement).not.toBe(null); + }); + + it('should render menu action', () => { + component.actionRef = { + type: 'menu', + id: 'action-menu', + title: 'Test Button', + actions: { + click: 'TEST_EVENT' + } + } as ContentActionRef; + fixture.detectChanges(); + + const menuElement = fixture.nativeElement.querySelector('#action-menu'); + expect(menuElement).not.toBe(null); + }); + + it('should render custom action', () => { + component.actionRef = { + type: 'custom', + id: 'action-custom', + component: 'custom-component' + } as ContentActionRef; + fixture.detectChanges(); + + const componentElement = fixture.nativeElement.querySelector( + '#custom-component' + ); + expect(componentElement).not.toBe(null); + }); + + it('should run defined action', () => { + spyOn(appExtensionService, 'runActionById'); + + component.actionRef = { + id: 'action-button', + title: 'Test Button', + actions: { + click: 'TEST_EVENT' + } + } as ContentActionRef; + fixture.detectChanges(); + + const buttonElement = fixture.nativeElement.querySelector('#action-button'); + buttonElement.dispatchEvent(new MouseEvent('click')); + expect(appExtensionService.runActionById).toHaveBeenCalledWith( + 'TEST_EVENT' + ); + }); +}); diff --git a/src/app/extensions/extension.service.spec.ts b/src/app/extensions/extension.service.spec.ts index 33748a2dc..fabafb767 100644 --- a/src/app/extensions/extension.service.spec.ts +++ b/src/app/extensions/extension.service.spec.ts @@ -39,18 +39,21 @@ import { ExtensionConfig, ComponentRegisterService } from '@alfresco/adf-extensions'; +import { AppConfigService } from '@alfresco/adf-core'; describe('AppExtensionService', () => { let service: AppExtensionService; let store: Store; let extensions: ExtensionService; let components: ComponentRegisterService; + let appConfigService: AppConfigService; beforeEach(() => { TestBed.configureTestingModule({ imports: [AppTestingModule] }); + appConfigService = TestBed.get(AppConfigService); store = TestBed.get(Store); service = TestBed.get(AppExtensionService); extensions = TestBed.get(ExtensionService); @@ -784,4 +787,114 @@ describe('AppExtensionService', () => { expect(service.getSharedLinkViewerToolbarActions()).toEqual(actions); }); }); + + describe('withCredentials', () => { + it('should set `withCredentials` to true from app configuration', () => { + appConfigService.config = { + auth: { withCredentials: true } + }; + applyConfig({ + $id: 'test', + $name: 'test', + $version: '1.0.0', + $license: 'MIT', + $vendor: 'Good company', + $runtime: '1.5.0' + }); + + expect(service.withCredentials).toBe(true); + }); + + it('should set `withCredentials` to false from app configuration', () => { + appConfigService.config = { + auth: { withCredentials: false } + }; + applyConfig({ + $id: 'test', + $name: 'test', + $version: '1.0.0', + $license: 'MIT', + $vendor: 'Good company', + $runtime: '1.5.0' + }); + + expect(service.withCredentials).toBe(false); + }); + + it('should set `withCredentials` to false as default value if no app configuration', () => { + appConfigService.config = {}; + applyConfig({ + $id: 'test', + $name: 'test', + $version: '1.0.0', + $license: 'MIT', + $vendor: 'Good company', + $runtime: '1.5.0' + }); + + expect(service.withCredentials).toBe(false); + }); + }); + + describe('userActions', () => { + it('should load user actions from the config', () => { + applyConfig({ + $id: 'test', + $name: 'test', + $version: '1.0.0', + $license: 'MIT', + $vendor: 'Good company', + $runtime: '1.5.0', + features: { + userActions: [ + { + id: 'aca:toolbar/separator-1', + order: 1, + type: ContentActionType.separator, + title: 'action1' + }, + { + id: 'aca:toolbar/separator-2', + order: 2, + type: ContentActionType.separator, + title: 'action2' + } + ] + } + }); + + expect(service.userActions.length).toBe(2); + }); + + it('should sort user actions by order', () => { + applyConfig({ + $id: 'test', + $name: 'test', + $version: '1.0.0', + $license: 'MIT', + $vendor: 'Good company', + $runtime: '1.5.0', + features: { + userActions: [ + { + id: 'aca:toolbar/separator-2', + order: 2, + type: ContentActionType.separator, + title: 'action2' + }, + { + id: 'aca:toolbar/separator-1', + order: 1, + type: ContentActionType.separator, + title: 'action1' + } + ] + } + }); + + expect(service.userActions.length).toBe(2); + expect(service.userActions[0].id).toBe('aca:toolbar/separator-1'); + expect(service.userActions[1].id).toBe('aca:toolbar/separator-2'); + }); + }); }); From 9104ab33c3ea32043f2af267a5faa52a4be53f18 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Wed, 8 Jan 2020 15:49:46 +0200 Subject: [PATCH 54/96] distinct button state style (#1296) --- .../dialogs/node-templates/create-from-template.dialog.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/dialogs/node-templates/create-from-template.dialog.scss b/src/app/dialogs/node-templates/create-from-template.dialog.scss index b88024c6e..1cc586b47 100644 --- a/src/app/dialogs/node-templates/create-from-template.dialog.scss +++ b/src/app/dialogs/node-templates/create-from-template.dialog.scss @@ -52,11 +52,11 @@ font-weight: normal; } - .create:disabled { - color: mat-color($primary); + .create[disabled] { + opacity: 0.6; } - .create { + .create:enabled { color: mat-color($accent); } } From fab739de05128e1c885d0909ecb87681cfa37a37 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 9 Jan 2020 09:54:54 +0200 Subject: [PATCH 55/96] trim value (#1297) --- src/app/dialogs/node-templates/create-from-template.dialog.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/dialogs/node-templates/create-from-template.dialog.ts b/src/app/dialogs/node-templates/create-from-template.dialog.ts index 9e7562d57..5672bd451 100644 --- a/src/app/dialogs/node-templates/create-from-template.dialog.ts +++ b/src/app/dialogs/node-templates/create-from-template.dialog.ts @@ -69,7 +69,7 @@ export class CreateFileFromTemplateDialogComponent implements OnInit { onSubmit() { const update = { - name: this.form.value.name, + name: this.form.value.name.trim(), properties: { 'cm:title': this.form.value.title, 'cm:description': this.form.value.description From fd970c1ef1c95e5cf76855e0f29960dc6f358782 Mon Sep 17 00:00:00 2001 From: Martin Muller Date: Fri, 10 Jan 2020 12:36:10 +0100 Subject: [PATCH 56/96] ACA-2755 sso simplified ADF integrating (#1295) * Simplify ADF changing --- .gitmodules | 3 +++ alfresco-ng2-components | 1 + package.json | 3 ++- scripts/install-local-adf.sh | 17 +++++++++++++++++ start.sh | 17 +++++++++++++++-- update-submodules.sh | 4 ++++ 6 files changed, 42 insertions(+), 3 deletions(-) create mode 160000 alfresco-ng2-components create mode 100755 scripts/install-local-adf.sh diff --git a/.gitmodules b/.gitmodules index 8278f1344..dbbfe7e84 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "alfresco-js-api"] path = alfresco-js-api url = https://github.com/Alfresco/alfresco-js-api +[submodule "alfresco-ng2-components"] + path = alfresco-ng2-components + url = https://github.com/Alfresco/alfresco-ng2-components diff --git a/alfresco-ng2-components b/alfresco-ng2-components new file mode 160000 index 000000000..20a444261 --- /dev/null +++ b/alfresco-ng2-components @@ -0,0 +1 @@ +Subproject commit 20a444261248efafb0e3df323c7e1753dce4dbb1 diff --git a/package.json b/package.json index 625f35d16..95bc3fcaf 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "build.app": "node --max-old-space-size=8192 node_modules/@angular/cli/bin/ng build app", "build": "npm run validate-config && npm run build.shared && npm run build.extensions && npm run build.app -- --prod", "build.js-api": "./init-submodules.sh && ./scripts/install-local-js-api.sh && npm run build", + "build.adf": "./init-submodules.sh && ./scripts/install-local-adf.sh && npm run build", "build.e2e": "npm run build.shared && npm run build.extensions && npm run build.app -- --prod --configuration=e2e", "test": "ng test app --code-coverage", "test:ci": "npm run build.shared && npm run build.extensions && ng test adf-office-services-ext --watch=false && ng test app --code-coverage --watch=false", @@ -21,7 +22,7 @@ "e2e": "npm run wd:update && protractor --baseUrl=${TEST_BASE_URL:-http://localhost:8080/content-app} $SUITE", "e2e.local": "npm run wd:update && protractor --baseUrl=http://localhost:4200 $SUITE", "wait:app": "wait-on http://${HOST_IP:-localhost}:${HOST_PORT:-8080}/alfresco/ -t 1000000 && wait-on http://${HOST_IP:-localhost}:${HOST_PORT:-8080}/content-app/ -t 400000", - "start:docker": "./start.sh && npm run wait:app", + "start:docker": "./start.sh", "stop:docker": "./start.sh -d", "e2e:docker": "./start.sh && npm run e2e && ./start.sh -d", "spellcheck": "cspell '{src,e2e,projects}/**/*.ts'", diff --git a/scripts/install-local-adf.sh b/scripts/install-local-adf.sh new file mode 100755 index 000000000..1af52ddcb --- /dev/null +++ b/scripts/install-local-adf.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +cd alfresco-ng2-components +npm install +./scripts/build/build-all-lib.sh +./scripts/build/build-content-services.sh +./scripts/build/build-extensions.sh +cd .. +rm -rf node_modules/@alfresco/adf-content-services +rm -rf node_modules/@alfresco/adf-core +rm -rf node_modules/@alfresco/adf-extensions +mkdir -p node_modules/@alfresco/adf-content-services +mkdir -p node_modules/@alfresco/adf-core +mkdir -p node_modules/@alfresco/adf-extensions +cp -rf alfresco-ng2-components/lib/dist/content-services/* node_modules/@alfresco/adf-content-services +cp -rf alfresco-ng2-components/lib/dist/core/* node_modules/@alfresco/adf-core +cp -rf alfresco-ng2-components/lib/dist/extensions/* node_modules/@alfresco/adf-extensions diff --git a/start.sh b/start.sh index 7beafa428..38ad7c1fe 100755 --- a/start.sh +++ b/start.sh @@ -8,6 +8,7 @@ show_help() { echo "-hi or --host-ip set the host ip" echo "-hp or --host-port set the host port. Default 8080" echo "-w or --wait wait for backend. Default true" + echo "-aca. Only redeploy ACA and skip the other docker compose services" echo "-h or --help" } @@ -32,18 +33,24 @@ set_wait(){ WAIT=$1 } +redeploy_aca(){ + REDEPLOY_ACA="true" +} + # Defaults WAIT="true" SET_HOST_IP="" HOST_PORT="8080" KEYCLOAK="false" AIMS_PROPS="" +REDEPLOY_ACA="false" while [[ $1 == -* ]]; do case "$1" in -h|--help|-\?) show_help; exit 0;; -k|--keycloak) set_keycloak; shift;; -d|--down) down; shift;; + -aca) redeploy_aca; shift;; -w|--wait) set_wait $2; shift 2;; -hi|--host-ip) set_host_ip $2; shift 2;; -hp|--host-port) set_host_port $2; shift 2;; @@ -78,9 +85,15 @@ if [[ $KEYCLOAK == "true" ]]; then AIMS_PROPS="-Dauthentication.chain=identity-service1:identity-service,alfrescoNtlm1:alfrescoNtlm" fi -echo "Start docker compose" export AIMS_PROPS=${AIMS_PROPS} -docker-compose up -d --build + +if [[ $REDEPLOY_ACA == "true" ]]; then + echo "Redeploy content-app" + docker-compose up --detach --build content-app +else + echo "Start docker compose" + docker-compose up -d --build +fi if [[ $WAIT == "true" ]]; then echo "http://${HOST_IP:-localhost}:${HOST_PORT:-8080}/$URL_FRAGMENT/" diff --git a/update-submodules.sh b/update-submodules.sh index 69a420d24..a0335e740 100755 --- a/update-submodules.sh +++ b/update-submodules.sh @@ -12,3 +12,7 @@ cd alfresco-js-api && git checkout master && git pull cd .. echo +echo "Updating alfresco-ng2-components ..." +echo -------------------------- +cd alfresco-ng2-components && git checkout master && git pull +cd .. From 503075143bf444874ef196f5d17d1ede9f0716df Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Tue, 14 Jan 2020 10:09:32 +0200 Subject: [PATCH 57/96] [ACA-2871] Create File from template - filter link files (#1298) * filter rows * tests * small rename of the tests Co-authored-by: Adina Parpalita --- .../create-file-from-template.service.spec.ts | 48 +++++++++++++++++++ .../create-file-from-template.service.ts | 13 +++-- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/app/services/create-file-from-template.service.spec.ts b/src/app/services/create-file-from-template.service.spec.ts index 70e7c89be..bcf7626e9 100644 --- a/src/app/services/create-file-from-template.service.spec.ts +++ b/src/app/services/create-file-from-template.service.spec.ts @@ -153,4 +153,52 @@ describe('CreateFileFromTemplateService', () => { new SnackbarErrorAction('APP.MESSAGES.ERRORS.GENERIC') ); })); + + it('should return true if row is not a `link` nodeType', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue( + of({ + id: 'templates-folder-id', + path: { + elements: [], + name: '/Company Home/Data Dictionary' + } + }) + ); + spyOn(dialog, 'open'); + + createFileFromTemplateService.openTemplatesDialog(); + + expect( + dialog.open['calls'].argsFor(0)[1].data.rowFilter({ + node: { entry: { nodeType: 'text' } } + }) + ).toBe(true); + }); + + it('should return false if row is a `link` nodeType', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue( + of({ + id: 'templates-folder-id', + path: { + elements: [], + name: '/Company Home/Data Dictionary' + } + }) + ); + spyOn(dialog, 'open'); + + createFileFromTemplateService.openTemplatesDialog(); + + expect( + dialog.open['calls'].argsFor(0)[1].data.rowFilter({ + node: { entry: { nodeType: 'app:filelink' } } + }) + ).toBe(false); + }); }); diff --git a/src/app/services/create-file-from-template.service.ts b/src/app/services/create-file-from-template.service.ts index f9a8d8790..f99a7cb54 100644 --- a/src/app/services/create-file-from-template.service.ts +++ b/src/app/services/create-file-from-template.service.ts @@ -27,14 +27,15 @@ import { Injectable } from '@angular/core'; import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material'; import { CreateFileFromTemplateDialogComponent } from '../dialogs/node-templates/create-from-template.dialog'; import { Subject, from, of } from 'rxjs'; -import { Node, MinimalNode } from '@alfresco/js-api'; +import { Node, MinimalNode, MinimalNodeEntryEntity } from '@alfresco/js-api'; import { AlfrescoApiService, TranslationService } from '@alfresco/adf-core'; import { switchMap, catchError } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { AppStore, SnackbarErrorAction } from '@alfresco/aca-shared/store'; import { ContentNodeSelectorComponent, - ContentNodeSelectorComponentData + ContentNodeSelectorComponentData, + ShareDataRow } from '@alfresco/adf-content-services'; @Injectable({ @@ -62,7 +63,8 @@ export class CreateFileFromTemplateService { dropdownSiteList: null, breadcrumbTransform: this.transformNode.bind(this), select, - isSelectionValid: this.isSelectionValid.bind(this) + isSelectionValid: this.isSelectionValid.bind(this), + rowFilter: this.rowFilter.bind(this) }; from( @@ -131,4 +133,9 @@ export class CreateFileFromTemplateService { private get title() { return this.translation.instant('NODE_SELECTOR.SELECT_TEMPLATE_TITLE'); } + + private rowFilter(row: ShareDataRow): boolean { + const node: MinimalNodeEntryEntity = row.node.entry; + return node.nodeType !== 'app:filelink'; + } } From 4dcb0d2a26f8fc8aa61cdc0cef2dbc5f1af7843e Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Wed, 15 Jan 2020 12:17:28 +0200 Subject: [PATCH 58/96] disabled action tooltip (#1304) --- src/assets/app.extensions.json | 1 + src/assets/i18n/en.json | 1 + 2 files changed, 2 insertions(+) diff --git a/src/assets/app.extensions.json b/src/assets/app.extensions.json index 44a2fcd3b..1f899a01b 100644 --- a/src/assets/app.extensions.json +++ b/src/assets/app.extensions.json @@ -114,6 +114,7 @@ "icon": "description", "title": "APP.NEW_MENU.MENU_ITEMS.FILE_TEMPLATE", "description": "APP.NEW_MENU.MENU_ITEMS.FILE_TEMPLATE", + "description-disabled": "APP.NEW_MENU.TOOLTIPS.CREATE_FILE_NOT_ALLOWED", "actions": { "click": "CREATE_FILE_FROM_TEMPLATE" }, diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 931b9ad41..e697e1d14 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -63,6 +63,7 @@ "TOOLTIPS": { "CREATE_FOLDER": "Create new folder", "CREATE_FOLDER_NOT_ALLOWED": "Folders cannot be created whilst viewing the current items", + "CREATE_FILE_NOT_ALLOWED": "Files cannot be created whilst viewing the current items", "UPLOAD_FILES": "Select files to upload", "UPLOAD_FILES_NOT_ALLOWED": "Files cannot be uploaded whilst viewing the current items", "UPLOAD_FOLDERS": "Select folders to upload", From d12079e2a746502c3663ff1438fc2600f70138a1 Mon Sep 17 00:00:00 2001 From: Chris Rodriguez Date: Wed, 15 Jan 2020 23:31:15 -0500 Subject: [PATCH 59/96] [ACA-2543] Left Navigation - Button does not have a role (#1306) * chore: a11y removed overriding role from button in menu * chore: removed comment * chore: removed previous change and override role with new role --- .../toolbar/toolbar-menu-item/toolbar-menu-item.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/components/toolbar/toolbar-menu-item/toolbar-menu-item.component.html b/src/app/components/toolbar/toolbar-menu-item/toolbar-menu-item.component.html index 0e043883a..9ffd5e6fd 100644 --- a/src/app/components/toolbar/toolbar-menu-item/toolbar-menu-item.component.html +++ b/src/app/components/toolbar/toolbar-menu-item/toolbar-menu-item.component.html @@ -30,6 +30,7 @@ diff --git a/src/app/dialogs/node-templates/create-from-template.dialog.scss b/src/app/dialogs/node-template/create-from-template.dialog.scss similarity index 93% rename from src/app/dialogs/node-templates/create-from-template.dialog.scss rename to src/app/dialogs/node-template/create-from-template.dialog.scss index 1cc586b47..7cbbb2947 100644 --- a/src/app/dialogs/node-templates/create-from-template.dialog.scss +++ b/src/app/dialogs/node-template/create-from-template.dialog.scss @@ -1,10 +1,10 @@ -@mixin app-create-file-from-template-theme($theme) { +@mixin app-create-from-template-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $foreground: map-get($theme, foreground); $background: map-get($theme, background); - .aca-file-from-template-dialog { + .aca-create-from-template-dialog { ng-component { overflow: visible; } diff --git a/src/app/dialogs/node-templates/create-from-template.dialog.spec.ts b/src/app/dialogs/node-template/create-from-template.dialog.spec.ts similarity index 73% rename from src/app/dialogs/node-templates/create-from-template.dialog.spec.ts rename to src/app/dialogs/node-template/create-from-template.dialog.spec.ts index 80eb35e2a..cf710cadb 100644 --- a/src/app/dialogs/node-templates/create-from-template.dialog.spec.ts +++ b/src/app/dialogs/node-template/create-from-template.dialog.spec.ts @@ -23,19 +23,18 @@ * along with Alfresco. If not, see . */ -import { CreateFileFromTemplateDialogComponent } from './create-from-template.dialog'; +import { CreateFromTemplateDialogComponent } from './create-from-template.dialog'; import { TestBed, ComponentFixture } from '@angular/core/testing'; import { AppTestingModule } from '../../testing/app-testing.module'; -import { CoreModule } from '@alfresco/adf-core'; +import { CoreModule, TranslationMock } from '@alfresco/adf-core'; import { MatDialogModule, - MatDialogRef, - MAT_DIALOG_DATA + MAT_DIALOG_DATA, + MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; -import { CreateFileFromTemplate } from '@alfresco/aca-shared/store'; +import { CreateFromTemplate } from '@alfresco/aca-shared/store'; import { Node } from '@alfresco/js-api'; -import { CreateFromTemplateDialogService } from './create-from-template-dialog.service'; function text(length: number) { return new Array(length) @@ -48,15 +47,15 @@ function text(length: number) { } describe('CreateFileFromTemplateDialogComponent', () => { - let fixture: ComponentFixture; - let component: CreateFileFromTemplateDialogComponent; - let dialogRef: MatDialogRef; + let fixture: ComponentFixture; + let component: CreateFromTemplateDialogComponent; let store; - let createFromTemplateDialogService: CreateFromTemplateDialogService; const data = { id: 'node-id', name: 'node-name', + isFolder: false, + isFile: true, properties: { 'cm:title': 'node-title', 'cm:description': '' @@ -66,36 +65,39 @@ describe('CreateFileFromTemplateDialogComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [CoreModule.forRoot(), AppTestingModule, MatDialogModule], - declarations: [CreateFileFromTemplateDialogComponent], + declarations: [CreateFromTemplateDialogComponent], providers: [ + { + provide: MatDialogRef, + useValue: { + close: jasmine.createSpy('close') + } + }, + { + provide: TranslationMock, + useValue: { + instant: jasmine.createSpy('instant') + } + }, { provide: Store, useValue: { dispatch: jasmine.createSpy('dispatch') } }, - { provide: MAT_DIALOG_DATA, useValue: data }, - { - provide: MatDialogRef, - useValue: { - close: jasmine.createSpy('close') - } - } + { provide: MAT_DIALOG_DATA, useValue: {} } ] }); - fixture = TestBed.createComponent(CreateFileFromTemplateDialogComponent); - dialogRef = TestBed.get(MatDialogRef); + fixture = TestBed.createComponent(CreateFromTemplateDialogComponent); store = TestBed.get(Store); - createFromTemplateDialogService = TestBed.get( - CreateFromTemplateDialogService - ); component = fixture.componentInstance; - - fixture.detectChanges(); + component.data = data as Node; }); it('should populate form with provided dialog data', () => { + fixture.detectChanges(); + expect(component.form.controls.name.value).toBe(data.name); expect(component.form.controls.title.value).toBe( data.properties['cm:title'] @@ -106,32 +108,47 @@ describe('CreateFileFromTemplateDialogComponent', () => { }); it('should invalidate form if required `name` field is invalid', () => { + fixture.detectChanges(); + component.form.controls.name.setValue(''); fixture.detectChanges(); + expect(component.form.invalid).toBe(true); }); it('should invalidate form if required `name` field has `only spaces`', () => { + fixture.detectChanges(); + component.form.controls.name.setValue(' '); fixture.detectChanges(); + expect(component.form.invalid).toBe(true); }); it('should invalidate form if required `name` field has `ending dot`', () => { + fixture.detectChanges(); + component.form.controls.name.setValue('something.'); fixture.detectChanges(); + expect(component.form.invalid).toBe(true); }); it('should invalidate form if `title` text length is long', () => { + fixture.detectChanges(); + component.form.controls.title.setValue(text(260)); fixture.detectChanges(); + expect(component.form.invalid).toBe(true); }); it('should invalidate form if `description` text length is long', () => { + fixture.detectChanges(); + component.form.controls.description.setValue(text(520)); fixture.detectChanges(); + expect(component.form.invalid).toBe(true); }); @@ -139,11 +156,16 @@ describe('CreateFileFromTemplateDialogComponent', () => { const newNode = { id: 'node-id', name: 'new-node-name', + isFolder: false, + isFile: true, properties: { 'cm:title': 'new-node-title', 'cm:description': 'new-node-description' } } as Node; + + fixture.detectChanges(); + component.form.controls.name.setValue('new-node-name'); component.form.controls.title.setValue('new-node-title'); component.form.controls.description.setValue('new-node-description'); @@ -152,27 +174,8 @@ describe('CreateFileFromTemplateDialogComponent', () => { component.onSubmit(); - expect(store.dispatch).toHaveBeenCalledWith( - new CreateFileFromTemplate(newNode) + expect(store.dispatch['calls'].mostRecent().args[0]).toEqual( + new CreateFromTemplate(newNode) ); }); - - it('should close dialog on create file from template success', done => { - const newNode = { - id: 'node-id', - name: 'new-node-name', - properties: { - 'cm:title': 'new-node-title', - 'cm:description': 'new-node-description' - } - } as Node; - - fixture.detectChanges(); - createFromTemplateDialogService.success$.subscribe(node => { - expect(dialogRef.close).toHaveBeenCalledWith(node); - done(); - }); - - createFromTemplateDialogService.success$.next(newNode); - }); }); diff --git a/src/app/dialogs/node-templates/create-from-template.dialog.ts b/src/app/dialogs/node-template/create-from-template.dialog.ts similarity index 76% rename from src/app/dialogs/node-templates/create-from-template.dialog.ts rename to src/app/dialogs/node-template/create-from-template.dialog.ts index 9a247a738..2b5ad1f90 100644 --- a/src/app/dialogs/node-templates/create-from-template.dialog.ts +++ b/src/app/dialogs/node-template/create-from-template.dialog.ts @@ -33,31 +33,27 @@ import { FormControl, ValidationErrors } from '@angular/forms'; -import { CreateFromTemplateDialogService } from './create-from-template-dialog.service'; import { Store } from '@ngrx/store'; -import { AppStore, CreateFileFromTemplate } from '@alfresco/aca-shared/store'; +import { AppStore, CreateFromTemplate } from '@alfresco/aca-shared/store'; +import { TranslationService } from '@alfresco/adf-core'; @Component({ templateUrl: './create-from-template.dialog.html', encapsulation: ViewEncapsulation.None, styleUrls: ['./create-from-template.dialog.scss'] }) -export class CreateFileFromTemplateDialogComponent implements OnInit { +export class CreateFromTemplateDialogComponent implements OnInit { public form: FormGroup; constructor( - private createFromTemplateDialogService: CreateFromTemplateDialogService, + private translationService: TranslationService, private store: Store, private formBuilder: FormBuilder, - private dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any + private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: Node ) {} ngOnInit() { - this.createFromTemplateDialogService.success$.subscribe((data: Node) => { - this.dialogRef.close(data); - }); - this.form = this.formBuilder.group({ name: [ this.data.name, @@ -85,7 +81,21 @@ export class CreateFileFromTemplateDialogComponent implements OnInit { } }; const data: Node = Object.assign({}, this.data, update); - this.store.dispatch(new CreateFileFromTemplate(data)); + this.store.dispatch(new CreateFromTemplate(data)); + } + + title(): string { + if (this.data.isFolder) { + return this.translationService.instant( + 'NODE_FROM_TEMPLATE.FOLDER_DIALOG_TITLE', + { template: this.data.name } + ); + } + + return this.translationService.instant( + 'NODE_FROM_TEMPLATE.FILE_DIALOG_TITLE', + { template: this.data.name } + ); } close() { @@ -101,7 +111,7 @@ export class CreateFileFromTemplateDialogComponent implements OnInit { return isValid ? null : { - message: `FILE_FROM_TEMPLATE.FORM.ERRORS.SPECIAL_CHARACTERS` + message: `NODE_FROM_TEMPLATE.FORM.ERRORS.SPECIAL_CHARACTERS` }; } @@ -115,7 +125,7 @@ export class CreateFileFromTemplateDialogComponent implements OnInit { return isValid ? null : { - message: `FILE_FROM_TEMPLATE.FORM.ERRORS.ENDING_DOT` + message: `NODE_FROM_TEMPLATE.FORM.ERRORS.ENDING_DOT` }; } @@ -126,11 +136,11 @@ export class CreateFileFromTemplateDialogComponent implements OnInit { return isValid ? null : { - message: `FILE_FROM_TEMPLATE.FORM.ERRORS.ONLY_SPACES` + message: `NODE_FROM_TEMPLATE.FORM.ERRORS.ONLY_SPACES` }; } else { return { - message: `FILE_FROM_TEMPLATE.FORM.ERRORS.REQUIRED` + message: `NODE_FROM_TEMPLATE.FORM.ERRORS.REQUIRED` }; } } diff --git a/src/app/dialogs/node-templates/create-from-template-dialog.service.ts b/src/app/dialogs/node-templates/create-from-template-dialog.service.ts deleted file mode 100644 index c6d95a3bf..000000000 --- a/src/app/dialogs/node-templates/create-from-template-dialog.service.ts +++ /dev/null @@ -1,35 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2020 Alfresco Software Limited - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { Injectable } from '@angular/core'; -import { Subject } from 'rxjs'; -import { Node } from '@alfresco/js-api'; - -@Injectable({ - providedIn: 'root' -}) -export class CreateFromTemplateDialogService { - success$: Subject = new Subject(); -} diff --git a/src/app/services/create-file-from-template.service.spec.ts b/src/app/services/create-file-from-template.service.spec.ts deleted file mode 100644 index ca066dfec..000000000 --- a/src/app/services/create-file-from-template.service.spec.ts +++ /dev/null @@ -1,204 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2020 Alfresco Software Limited - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { TestBed, fakeAsync, tick } from '@angular/core/testing'; -import { EffectsModule } from '@ngrx/effects'; -import { AppStore, SnackbarErrorAction } from '@alfresco/aca-shared/store'; -import { TemplateEffects } from '../store/effects/template.effects'; -import { AppTestingModule } from '../testing/app-testing.module'; -import { Store } from '@ngrx/store'; -import { MatDialog } from '@angular/material/dialog'; -import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-core'; -import { CreateFileFromTemplateService } from './create-file-from-template.service'; -import { of } from 'rxjs'; - -describe('CreateFileFromTemplateService', () => { - let dialog: MatDialog; - let store: Store; - let alfrescoApiService: AlfrescoApiService; - let createFileFromTemplateService: CreateFileFromTemplateService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [AppTestingModule, EffectsModule.forRoot([TemplateEffects])], - providers: [ - CreateFileFromTemplateService, - { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock } - ] - }); - - store = TestBed.get(Store); - alfrescoApiService = TestBed.get(AlfrescoApiService); - dialog = TestBed.get(MatDialog); - createFileFromTemplateService = TestBed.get(CreateFileFromTemplateService); - }); - - it('should open dialog with `Node Templates` folder id as data property', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue(of({ id: 'templates-folder-id' })); - spyOn(dialog, 'open'); - - createFileFromTemplateService.openTemplatesDialog(); - - expect(dialog.open['calls'].argsFor(0)[1].data).toEqual( - jasmine.objectContaining({ currentFolderId: 'templates-folder-id' }) - ); - }); - - it('should remove parents for templates node breadcrumb path', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue( - of({ - id: 'templates-folder-id', - path: { - elements: [], - name: '/Company Home/Data Dictionary' - } - }) - ); - spyOn(dialog, 'open'); - - createFileFromTemplateService.openTemplatesDialog(); - - const breadcrumb = dialog.open['calls'] - .argsFor(0)[1] - .data.breadcrumbTransform({ - name: 'Node Templates', - path: { - elements: [{ name: 'Company Home' }, { name: 'Data Dictionary' }], - name: '/Company Home/Data Dictionary' - } - }); - - expect(breadcrumb.path.elements).toEqual([]); - }); - - it('should return false if selected node is not a template file', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue(of({ id: 'templates-folder-id' })); - spyOn(dialog, 'open'); - - createFileFromTemplateService.openTemplatesDialog(); - - const isSelectionValid = dialog.open['calls'] - .argsFor(0)[1] - .data.isSelectionValid({ - isFile: false - }); - - expect(isSelectionValid).toBe(false); - }); - - it('should return true if selected node is a template file', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue(of({ id: 'templates-folder-id' })); - spyOn(dialog, 'open'); - - createFileFromTemplateService.openTemplatesDialog(); - - const isSelectionValid = dialog.open['calls'] - .argsFor(0)[1] - .data.isSelectionValid({ - isFile: true - }); - - expect(isSelectionValid).toBe(true); - }); - - it('should raise an error when getNodeInfo fails', fakeAsync(() => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue( - Promise.reject({ - message: `{ "error": { "statusCode": 404 } } ` - }) - ); - spyOn(store, 'dispatch'); - - createFileFromTemplateService.openTemplatesDialog(); - tick(); - - expect(store.dispatch).toHaveBeenCalledWith( - new SnackbarErrorAction('APP.MESSAGES.ERRORS.GENERIC') - ); - })); - - it('should return true if row is not a `link` nodeType', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue( - of({ - id: 'templates-folder-id', - path: { - elements: [], - name: '/Company Home/Data Dictionary' - } - }) - ); - spyOn(dialog, 'open'); - - createFileFromTemplateService.openTemplatesDialog(); - - expect( - dialog.open['calls'].argsFor(0)[1].data.rowFilter({ - node: { entry: { nodeType: 'text' } } - }) - ).toBe(true); - }); - - it('should return false if row is a `link` nodeType', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue( - of({ - id: 'templates-folder-id', - path: { - elements: [], - name: '/Company Home/Data Dictionary' - } - }) - ); - spyOn(dialog, 'open'); - - createFileFromTemplateService.openTemplatesDialog(); - - expect( - dialog.open['calls'].argsFor(0)[1].data.rowFilter({ - node: { entry: { nodeType: 'app:filelink' } } - }) - ).toBe(false); - }); -}); diff --git a/src/app/services/node-template.service.spec.ts b/src/app/services/node-template.service.spec.ts new file mode 100644 index 000000000..3e94713e5 --- /dev/null +++ b/src/app/services/node-template.service.spec.ts @@ -0,0 +1,308 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { EffectsModule } from '@ngrx/effects'; +import { AppStore, SnackbarErrorAction } from '@alfresco/aca-shared/store'; +import { TemplateEffects } from '../store/effects/template.effects'; +import { AppTestingModule } from '../testing/app-testing.module'; +import { Store } from '@ngrx/store'; +import { MatDialog } from '@angular/material/dialog'; +import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-core'; +import { NodeTemplateService } from './node-template.service'; +import { of } from 'rxjs'; + +describe('NodeTemplateService', () => { + let dialog: MatDialog; + let store: Store; + let alfrescoApiService: AlfrescoApiService; + let nodeTemplateService: NodeTemplateService; + const fileTemplateConfig = { + relativePath: 'relative-path/parent-file-templates', + selectionType: 'file' + }; + const folderTemplateConfig = { + relativePath: 'relative-path/parent-folder-templates', + selectionType: 'folder' + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [AppTestingModule, EffectsModule.forRoot([TemplateEffects])], + providers: [ + NodeTemplateService, + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock } + ] + }); + + store = TestBed.get(Store); + alfrescoApiService = TestBed.get(AlfrescoApiService); + dialog = TestBed.get(MatDialog); + nodeTemplateService = TestBed.get(NodeTemplateService); + }); + + it('should open dialog with parent node `id` as data property', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue(of({ id: 'parent-node-id' })); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(fileTemplateConfig); + + expect(dialog.open['calls'].argsFor(0)[1].data).toEqual( + jasmine.objectContaining({ currentFolderId: 'parent-node-id' }) + ); + }); + + it('should remove parents for templates node breadcrumb path', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue( + of({ + id: 'parent-node-id', + path: { + elements: [], + name: '/Company Home/Data Dictionary' + } + }) + ); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(fileTemplateConfig); + + const breadcrumb = dialog.open['calls'] + .argsFor(0)[1] + .data.breadcrumbTransform({ + name: 'Node Templates', + path: { + elements: [{ name: 'Company Home' }, { name: 'Data Dictionary' }], + name: '/Company Home/Data Dictionary' + } + }); + + expect(breadcrumb.path.elements).toEqual([]); + }); + + it('should raise an error when getNodeInfo fails', fakeAsync(() => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue( + Promise.reject({ + message: `{ "error": { "statusCode": 404 } } ` + }) + ); + spyOn(store, 'dispatch'); + + nodeTemplateService.selectTemplateDialog(fileTemplateConfig); + tick(); + + expect(store.dispatch).toHaveBeenCalledWith( + new SnackbarErrorAction('APP.MESSAGES.ERRORS.GENERIC') + ); + })); + + it('should return true if row is not a `link` nodeType', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue( + of({ + id: 'templates-folder-id', + path: { + elements: [], + name: '/Company Home/Data Dictionary' + } + }) + ); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(fileTemplateConfig); + + expect( + dialog.open['calls'].argsFor(0)[1].data.rowFilter({ + node: { entry: { nodeType: 'text' } } + }) + ).toBe(true); + }); + + it('should return false if row is a `link` nodeType', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue( + of({ + id: 'templates-folder-id', + path: { + elements: [], + name: '/Company Home/Data Dictionary' + } + }) + ); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(fileTemplateConfig); + + expect( + dialog.open['calls'].argsFor(0)[1].data.rowFilter({ + node: { entry: { nodeType: 'app:filelink' } } + }) + ).toBe(false); + }); + + describe('File templates', () => { + it('should return false if selected node is not a file', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(fileTemplateConfig); + + const isSelectionValid = dialog.open['calls'] + .argsFor(0)[1] + .data.isSelectionValid({ + name: 'some-folder-template', + isFile: false, + isFolder: true + }); + + expect(isSelectionValid).toBe(false); + }); + + it('should return true if selected node is a template file', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(fileTemplateConfig); + + const isSelectionValid = dialog.open['calls'] + .argsFor(0)[1] + .data.isSelectionValid({ + name: 'some-file-template', + isFile: true, + isFolder: false + }); + + expect(isSelectionValid).toBe(true); + }); + + it('should set dialog title for file templates', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(fileTemplateConfig); + + const title = dialog.open['calls'].argsFor(0)[1].data.title; + + expect(title).toBe('NODE_SELECTOR.SELECT_FILE_TEMPLATE_TITLE'); + }); + }); + + describe('Folder templates', () => { + it('should return false if selected node is not a folder', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(folderTemplateConfig); + + const isSelectionValid = dialog.open['calls'] + .argsFor(0)[1] + .data.isSelectionValid({ + name: 'some-file-template', + isFile: true, + isFolder: false + }); + + expect(isSelectionValid).toBe(false); + }); + + it('should return false if current node is the parent folder', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(folderTemplateConfig); + + const isSelectionValid = dialog.open['calls'] + .argsFor(0)[1] + .data.isSelectionValid({ + name: 'parent-folder-templates', + isFile: false, + isFolder: true + }); + + expect(isSelectionValid).toBe(false); + }); + + it('should return true if selected node is a folder template', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(folderTemplateConfig); + + const isSelectionValid = dialog.open['calls'] + .argsFor(0)[1] + .data.isSelectionValid({ + name: 'some-folder-template', + isFile: false, + isFolder: true + }); + + expect(isSelectionValid).toBe(true); + }); + + it('should set dialog title for folder templates', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(folderTemplateConfig); + + const title = dialog.open['calls'].argsFor(0)[1].data.title; + + expect(title).toBe('NODE_SELECTOR.SELECT_FOLDER_TEMPLATE_TITLE'); + }); + }); +}); diff --git a/src/app/services/create-file-from-template.service.ts b/src/app/services/node-template.service.ts similarity index 77% rename from src/app/services/create-file-from-template.service.ts rename to src/app/services/node-template.service.ts index 761c550ce..e13a66838 100644 --- a/src/app/services/create-file-from-template.service.ts +++ b/src/app/services/node-template.service.ts @@ -25,7 +25,7 @@ import { Injectable } from '@angular/core'; import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material'; -import { CreateFileFromTemplateDialogComponent } from '../dialogs/node-templates/create-from-template.dialog'; +import { CreateFromTemplateDialogComponent } from '../dialogs/node-template/create-from-template.dialog'; import { Subject, from, of } from 'rxjs'; import { Node, MinimalNode, MinimalNodeEntryEntity } from '@alfresco/js-api'; import { AlfrescoApiService, TranslationService } from '@alfresco/adf-core'; @@ -38,10 +38,17 @@ import { ShareDataRow } from '@alfresco/adf-content-services'; +export interface TemplateDialogConfig { + relativePath: string; + selectionType: string; +} + @Injectable({ providedIn: 'root' }) -export class CreateFileFromTemplateService { +export class NodeTemplateService { + private currentTemplateConfig: TemplateDialogConfig = null; + constructor( private store: Store, private alfrescoApiService: AlfrescoApiService, @@ -49,14 +56,16 @@ export class CreateFileFromTemplateService { public dialog: MatDialog ) {} - openTemplatesDialog(): Subject { + selectTemplateDialog(config: TemplateDialogConfig): Subject { + this.currentTemplateConfig = config; + const select = new Subject(); select.subscribe({ complete: this.close.bind(this) }); const data: ContentNodeSelectorComponentData = { - title: this.title, + title: this.title(config.selectionType), actionName: 'NEXT', dropdownHideMyFiles: true, currentFolderId: null, @@ -69,7 +78,7 @@ export class CreateFileFromTemplateService { from( this.alfrescoApiService.getInstance().nodes.getNodeInfo('-root-', { - relativePath: 'Data Dictionary/Node Templates' + relativePath: config.relativePath }) ) .pipe( @@ -100,10 +109,10 @@ export class CreateFileFromTemplateService { createTemplateDialog( node: Node - ): MatDialogRef { - return this.dialog.open(CreateFileFromTemplateDialogComponent, { + ): MatDialogRef { + return this.dialog.open(CreateFromTemplateDialogComponent, { data: node, - panelClass: 'aca-file-from-template-dialog', + panelClass: 'aca-create-from-template-dialog', width: '630px' }); } @@ -123,6 +132,14 @@ export class CreateFileFromTemplateService { } private isSelectionValid(node: Node): boolean { + if (node.name === this.currentTemplateConfig.relativePath.split('/')[1]) { + return false; + } + + if (this.currentTemplateConfig.selectionType === 'folder') { + return node.isFolder; + } + return node.isFile; } @@ -130,8 +147,16 @@ export class CreateFileFromTemplateService { this.dialog.closeAll(); } - private get title() { - return this.translation.instant('NODE_SELECTOR.SELECT_TEMPLATE_TITLE'); + private title(selectionType: string) { + if (selectionType === 'file') { + return this.translation.instant( + 'NODE_SELECTOR.SELECT_FILE_TEMPLATE_TITLE' + ); + } + + return this.translation.instant( + 'NODE_SELECTOR.SELECT_FOLDER_TEMPLATE_TITLE' + ); } private rowFilter(row: ShareDataRow): boolean { diff --git a/src/app/store/effects/template.effects.spec.ts b/src/app/store/effects/template.effects.spec.ts index 6f4cb9808..e0d522d00 100644 --- a/src/app/store/effects/template.effects.spec.ts +++ b/src/app/store/effects/template.effects.spec.ts @@ -29,25 +29,27 @@ import { TemplateEffects } from './template.effects'; import { EffectsModule } from '@ngrx/effects'; import { Store } from '@ngrx/store'; import { - CreateFileFromTemplate, + CreateFromTemplate, + CreateFromTemplateSuccess, FileFromTemplate, + FolderFromTemplate, SnackbarErrorAction } from '@alfresco/aca-shared/store'; -import { CreateFileFromTemplateService } from '../../services/create-file-from-template.service'; +import { NodeTemplateService } from '../../services/node-template.service'; import { of } from 'rxjs'; import { AlfrescoApiServiceMock, AlfrescoApiService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../services/content-management.service'; import { Node, NodeEntry } from '@alfresco/js-api'; -import { CreateFromTemplateDialogService } from '../../dialogs/node-templates/create-from-template-dialog.service'; +import { MatDialog } from '@angular/material/dialog'; describe('TemplateEffects', () => { let store: Store; - let createFileFromTemplateService: CreateFileFromTemplateService; + let nodeTemplateService: NodeTemplateService; let alfrescoApiService: AlfrescoApiService; let contentManagementService: ContentManagementService; - let createFromTemplateDialogService: CreateFromTemplateDialogService; let copyNodeSpy; let updateNodeSpy; + let matDialog: MatDialog; const node: Node = { name: 'node-name', id: 'node-id', @@ -63,29 +65,41 @@ describe('TemplateEffects', () => { 'cm:description': 'description' } }; + const fileTemplateConfig = { + relativePath: 'Data Dictionary/Node Templates', + selectionType: 'file' + }; + + const folderTemplateConfig = { + relativePath: 'Data Dictionary/Space Templates', + selectionType: 'folder' + }; beforeEach(() => { TestBed.configureTestingModule({ imports: [AppTestingModule, EffectsModule.forRoot([TemplateEffects])], providers: [ - CreateFileFromTemplateService, - { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock } + NodeTemplateService, + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, + { + provide: MatDialog, + useValue: { + closeAll: jasmine.createSpy('closeAll') + } + } ] }); store = TestBed.get(Store); - createFileFromTemplateService = TestBed.get(CreateFileFromTemplateService); + nodeTemplateService = TestBed.get(NodeTemplateService); alfrescoApiService = TestBed.get(AlfrescoApiService); - createFromTemplateDialogService = TestBed.get( - CreateFromTemplateDialogService - ); contentManagementService = TestBed.get(ContentManagementService); + matDialog = TestBed.get(MatDialog); spyOn(store, 'dispatch').and.callThrough(); - spyOn(createFromTemplateDialogService.success$, 'next'); spyOn(contentManagementService.reload, 'next'); spyOn(store, 'select').and.returnValue(of({ id: 'parent-id' })); - spyOn(createFileFromTemplateService, 'openTemplatesDialog').and.returnValue( + spyOn(nodeTemplateService, 'selectTemplateDialog').and.returnValue( of([{ id: 'template-id' }]) ); @@ -98,41 +112,43 @@ describe('TemplateEffects', () => { updateNodeSpy.calls.reset(); }); - it('should reload content on create file from template', fakeAsync(() => { - spyOn( - createFileFromTemplateService, - 'createTemplateDialog' - ).and.returnValue({ afterClosed: () => of(node) }); + it('should open dialog to select template files', fakeAsync(() => { + spyOn(nodeTemplateService, 'createTemplateDialog').and.returnValue({ + afterClosed: () => of(node) + }); store.dispatch(new FileFromTemplate()); - tick(300); + tick(); - expect(contentManagementService.reload.next).toHaveBeenCalled(); + expect(nodeTemplateService.selectTemplateDialog).toHaveBeenCalledWith( + fileTemplateConfig + ); })); - it('should not reload content if no file was created', fakeAsync(() => { - spyOn( - createFileFromTemplateService, - 'createTemplateDialog' - ).and.returnValue({ afterClosed: () => of(null) }); + it('should open dialog to select template folders', fakeAsync(() => { + spyOn(nodeTemplateService, 'createTemplateDialog').and.returnValue({ + afterClosed: () => of(node) + }); - store.dispatch(new FileFromTemplate()); - tick(300); + store.dispatch(new FolderFromTemplate()); + tick(); - expect(contentManagementService.reload.next).not.toHaveBeenCalled(); + expect(nodeTemplateService.selectTemplateDialog).toHaveBeenCalledWith( + folderTemplateConfig + ); })); - it('should call dialog service success event on create file from template', fakeAsync(() => { + it('should create node from template successful', fakeAsync(() => { copyNodeSpy.and.returnValue( of({ entry: { id: 'node-id', properties: {} } }) ); updateNodeSpy.and.returnValue(of({ entry: node })); - store.dispatch(new CreateFileFromTemplate(node)); + store.dispatch(new CreateFromTemplate(node)); tick(); - expect(createFromTemplateDialogService.success$.next).toHaveBeenCalledWith( - node + expect(store.dispatch['calls'].mostRecent().args[0]).toEqual( + new CreateFromTemplateSuccess(node) ); })); @@ -143,12 +159,12 @@ describe('TemplateEffects', () => { }) ); - store.dispatch(new CreateFileFromTemplate(node)); + store.dispatch(new CreateFromTemplate(node)); tick(); - expect( - createFromTemplateDialogService.success$.next - ).not.toHaveBeenCalledWith(); + expect(store.dispatch['calls'].mostRecent().args[0]).not.toEqual( + new CreateFromTemplateSuccess(node) + ); expect(store.dispatch['calls'].argsFor(1)[0]).toEqual( new SnackbarErrorAction('APP.MESSAGES.ERRORS.GENERIC') ); @@ -161,12 +177,12 @@ describe('TemplateEffects', () => { }) ); - store.dispatch(new CreateFileFromTemplate(node)); + store.dispatch(new CreateFromTemplate(node)); tick(); - expect( - createFromTemplateDialogService.success$.next - ).not.toHaveBeenCalledWith(); + expect(store.dispatch['calls'].mostRecent().args[0]).not.toEqual( + new CreateFromTemplateSuccess(node) + ); expect(store.dispatch['calls'].argsFor(1)[0]).toEqual( new SnackbarErrorAction('APP.MESSAGES.ERRORS.CONFLICT') ); @@ -190,11 +206,26 @@ describe('TemplateEffects', () => { }) ); - store.dispatch(new CreateFileFromTemplate(test_node.entry)); + store.dispatch(new CreateFromTemplate(test_node.entry)); tick(); - expect(createFromTemplateDialogService.success$.next).toHaveBeenCalledWith( - test_node.entry + expect(store.dispatch['calls'].mostRecent().args[0]).toEqual( + new CreateFromTemplateSuccess(test_node.entry) + ); + })); + + it('should close dialog on create template success', fakeAsync(() => { + store.dispatch(new CreateFromTemplateSuccess({} as Node)); + tick(); + expect(matDialog.closeAll).toHaveBeenCalled(); + })); + + it('should should reload content on create template success', fakeAsync(() => { + const test_node = { id: 'test-node-id' } as Node; + store.dispatch(new CreateFromTemplateSuccess(test_node)); + tick(); + expect(contentManagementService.reload.next).toHaveBeenCalledWith( + test_node ); })); }); diff --git a/src/app/store/effects/template.effects.ts b/src/app/store/effects/template.effects.ts index 713ad2574..ab6a778de 100644 --- a/src/app/store/effects/template.effects.ts +++ b/src/app/store/effects/template.effects.ts @@ -25,65 +25,64 @@ import { Effect, Actions, ofType } from '@ngrx/effects'; import { Injectable } from '@angular/core'; -import { - map, - switchMap, - debounceTime, - flatMap, - take, - catchError -} from 'rxjs/operators'; +import { map, switchMap, debounceTime, take, catchError } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { FileFromTemplate, - CreateFileFromTemplate, + FolderFromTemplate, + CreateFromTemplate, + CreateFromTemplateSuccess, TemplateActionTypes, getCurrentFolder, AppStore, SnackbarErrorAction } from '@alfresco/aca-shared/store'; -import { CreateFileFromTemplateService } from '../../services/create-file-from-template.service'; +import { + NodeTemplateService, + TemplateDialogConfig +} from '../../services/node-template.service'; import { AlfrescoApiService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../services/content-management.service'; import { from, Observable, of } from 'rxjs'; import { NodeEntry, NodeBodyUpdate, Node } from '@alfresco/js-api'; -import { CreateFromTemplateDialogService } from '../../dialogs/node-templates/create-from-template-dialog.service'; +import { MatDialog } from '@angular/material/dialog'; + @Injectable() export class TemplateEffects { constructor( + private matDialog: MatDialog, private content: ContentManagementService, private store: Store, private apiService: AlfrescoApiService, private actions$: Actions, - private createFromTemplateDialogService: CreateFromTemplateDialogService, - private createFileFromTemplateService: CreateFileFromTemplateService + private nodeTemplateService: NodeTemplateService ) {} @Effect({ dispatch: false }) fileFromTemplate$ = this.actions$.pipe( ofType(TemplateActionTypes.FileFromTemplate), map(() => { - this.createFileFromTemplateService - .openTemplatesDialog() - .pipe( - debounceTime(300), - flatMap(([node]) => - this.createFileFromTemplateService - .createTemplateDialog(node) - .afterClosed() - ) - ) - .subscribe((node: NodeEntry | null) => { - if (node) { - this.content.reload.next(node); - } - }); + this.openDialog({ + relativePath: 'Data Dictionary/Node Templates', + selectionType: 'file' + }); }) ); @Effect({ dispatch: false }) - createFileFromTemplate$ = this.actions$.pipe( - ofType(TemplateActionTypes.CreateFileFromTemplate), + folderFromTemplate$ = this.actions$.pipe( + ofType(TemplateActionTypes.FolderFromTemplate), + map(() => + this.openDialog({ + relativePath: 'Data Dictionary/Space Templates', + selectionType: 'folder' + }) + ) + ); + + @Effect({ dispatch: false }) + createFromTemplate$ = this.actions$.pipe( + ofType(TemplateActionTypes.CreateFromTemplate), map(action => { this.store .select(getCurrentFolder) @@ -95,12 +94,32 @@ export class TemplateEffects { ) .subscribe((node: NodeEntry | null) => { if (node) { - this.createFromTemplateDialogService.success$.next(node.entry); + this.store.dispatch(new CreateFromTemplateSuccess(node.entry)); } }); }) ); + @Effect({ dispatch: false }) + createFromTemplateSuccess$ = this.actions$.pipe( + ofType( + TemplateActionTypes.CreateFromTemplateSuccess + ), + map(payload => { + this.matDialog.closeAll(); + this.content.reload.next(payload.node); + }) + ); + + private openDialog(config: TemplateDialogConfig) { + this.nodeTemplateService + .selectTemplateDialog(config) + .pipe(debounceTime(300)) + .subscribe(([node]) => + this.nodeTemplateService.createTemplateDialog(node) + ); + } + private copyNode(source: Node, parentId: string): Observable { return from( this.apiService.getInstance().nodes.copyNode(source.id, { diff --git a/src/app/ui/custom-theme.scss b/src/app/ui/custom-theme.scss index 3059f4a95..fa20674ca 100644 --- a/src/app/ui/custom-theme.scss +++ b/src/app/ui/custom-theme.scss @@ -10,7 +10,7 @@ @import '../dialogs/node-versions/node-versions.dialog.theme'; @import '../components/create-menu/create-menu.component.scss'; @import '../components/layout/layout.theme.scss'; -@import '../dialogs/node-templates/create-from-template.dialog.scss'; +@import '../dialogs/node-template/create-from-template.dialog.scss'; @import './overrides/adf-style-fixes.theme'; @@ -68,7 +68,7 @@ $warn: map-get($custom-theme, warn); @include sidenav-component-theme($theme); @include aca-current-user-theme($theme); @include aca-context-menu-theme($theme); - @include app-create-file-from-template-theme($theme); + @include app-create-from-template-theme($theme); @include app-create-menu-theme($theme); @include adf-style-fixes($theme); diff --git a/src/assets/app.extensions.json b/src/assets/app.extensions.json index 7f5aa5857..8c4301175 100644 --- a/src/assets/app.extensions.json +++ b/src/assets/app.extensions.json @@ -121,6 +121,20 @@ "rules": { "enabled": "app.navigation.folder.canUpload" } + }, + { + "id": "app.create.folderFromTemplate", + "order": 800, + "icon": "create_new_folder", + "title": "APP.NEW_MENU.MENU_ITEMS.FOLDER_TEMPLATE", + "description": "APP.NEW_MENU.MENU_ITEMS.FOLDER_TEMPLATE", + "description-disabled": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER_NOT_ALLOWED", + "actions": { + "click": "FOLDER_FROM_TEMPLATE" + }, + "rules": { + "enabled": "app.navigation.folder.canUpload" + } } ], "navbar": [ diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index e31b9392f..8825d3e58 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -58,7 +58,8 @@ "UPLOAD_FILE": "Upload File", "UPLOAD_FOLDER": "Upload Folder", "CREATE_LIBRARY": "Create Library", - "FILE_TEMPLATE": "Create file from template" + "FILE_TEMPLATE": "Create file from template", + "FOLDER_TEMPLATE": "Create folder from template" }, "TOOLTIPS": { "CREATE_FOLDER": "Create new folder", @@ -359,12 +360,14 @@ "MOVE_ITEMS": "Move {{ number }} items to...", "SEARCH": "Search", "NEXT": "Next", - "SELECT_TEMPLATE_TITLE": "Select a document template" + "SELECT_FILE_TEMPLATE_TITLE": "Select a document template", + "SELECT_FOLDER_TEMPLATE_TITLE": "Select a folder template" }, - "FILE_FROM_TEMPLATE": { + "NODE_FROM_TEMPLATE": { "CANCEL": "CANCEL", "CREATE": "Create", - "TITLE": "Create new document from '{{ template }}'", + "FOLDER_DIALOG_TITLE": "Create new folder from '{{ template }}'", + "FILE_DIALOG_TITLE": "Create new document from '{{ template }}'", "FORM": { "PLACEHOLDER": { "NAME": "Name", From 34c559c7d53981b16e09073111c4499c52d783b6 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Wed, 22 Jan 2020 12:17:43 +0200 Subject: [PATCH 69/96] filter out folder links (#1314) --- src/app/services/node-template.service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/services/node-template.service.ts b/src/app/services/node-template.service.ts index e13a66838..4dbdf1cc4 100644 --- a/src/app/services/node-template.service.ts +++ b/src/app/services/node-template.service.ts @@ -161,6 +161,8 @@ export class NodeTemplateService { private rowFilter(row: ShareDataRow): boolean { const node: MinimalNodeEntryEntity = row.node.entry; - return node.nodeType !== 'app:filelink'; + return ( + node.nodeType !== 'app:filelink' && node.nodeType !== 'app:folderlink' + ); } } From 9e4e4a9b0ccdef83534b7723d61786ea99c645d4 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Wed, 22 Jan 2020 14:27:29 +0200 Subject: [PATCH 70/96] fix build scripts (#1313) --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 7c41410a8..cdc0bf0ed 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,11 @@ "build:aos-extension": "npx rimraf dist/@alfresco/adf-office-services-ext && ng build adf-office-services-ext && cpr projects/adf-office-services-ext/ngi.json dist/@alfresco/adf-office-services-ext/ngi.json && cpr projects/adf-office-services-ext/assets dist/@alfresco/adf-office-services-ext/assets", "build.shared": "ng build aca-shared", "build.aos": "npm run build:aos-extension", - "build.extensions": "npm run build.shared && npm run build:aos-extension", + "build.extensions": "npm run build.shared && npm run build.aos", "build.app": "node --max-old-space-size=8192 node_modules/@angular/cli/bin/ng build app", - "build": "npm run validate-config && build.extensions && npm run build.app -- --prod", + "build": "npm run validate-config && npm run build.extensions && npm run build.app -- --prod", "build.js-api": "./scripts/install-local-js-api.sh && npm run build", - "build.adf": "./scripts/install-local-adf.sh && build.extensions && npm run build.app", + "build.adf": "./scripts/install-local-adf.sh && npm run build.extensions && npm run build.app", "build.e2e": "npm run build.extensions && npm run build.app -- --prod --configuration=e2e", "test": "ng test app --code-coverage", "test:ci": "npm run build.extensions && ng test adf-office-services-ext --watch=false && ng test app --code-coverage --watch=false", From 7c30ad139f8c3e2c3397d84d52239b4719a80301 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Wed, 22 Jan 2020 16:45:22 +0200 Subject: [PATCH 71/96] check properties object exists (#1316) --- .../dialogs/node-template/create-from-template.dialog.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app/dialogs/node-template/create-from-template.dialog.ts b/src/app/dialogs/node-template/create-from-template.dialog.ts index 2b5ad1f90..1caf9a64d 100644 --- a/src/app/dialogs/node-template/create-from-template.dialog.ts +++ b/src/app/dialogs/node-template/create-from-template.dialog.ts @@ -64,9 +64,12 @@ export class CreateFromTemplateDialogComponent implements OnInit { this.forbidSpecialCharacters ] ], - title: [this.data.properties['cm:title'], Validators.maxLength(256)], + title: [ + this.data.properties ? this.data.properties['cm:title'] : '', + Validators.maxLength(256) + ], description: [ - this.data.properties['cm:description'], + this.data.properties ? this.data.properties['cm:description'] : '', Validators.maxLength(512) ] }); From 5e203cab96c0a3cdf35a420763c0b56d3afdd1cb Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 23 Jan 2020 09:58:30 +0200 Subject: [PATCH 72/96] [ACA-2882] Create from template - generic form errors (#1317) * remove type from error message * change validation message * change required message --- e2e/suites/actions/create-file-from-template.test.ts | 8 ++++---- src/assets/i18n/en.json | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/e2e/suites/actions/create-file-from-template.test.ts b/e2e/suites/actions/create-file-from-template.test.ts index 80537c409..a22409792 100755 --- a/e2e/suites/actions/create-file-from-template.test.ts +++ b/e2e/suites/actions/create-file-from-template.test.ts @@ -252,7 +252,7 @@ describe('Create file from template', () => { expect(await createFromTemplateDialog.getName()).toEqual(template1InRootFolder); await createFromTemplateDialog.deleteNameWithBackspace(); - expect(await createFromTemplateDialog.getValidationMessage()).toEqual('File name is required'); + expect(await createFromTemplateDialog.getValidationMessage()).toEqual('Name is required'); expect(await createFromTemplateDialog.isCreateButtonEnabled()).toBe(false, 'Create button is not disabled'); }); @@ -262,7 +262,7 @@ describe('Create file from template', () => { for (const name of namesWithSpecialChars) { await createFromTemplateDialog.enterName(name); expect(await createFromTemplateDialog.isCreateButtonEnabled()).toBe(false, 'Create button is not disabled'); - expect(await createFromTemplateDialog.getValidationMessage()).toContain(`File name can't contain these characters`); + expect(await createFromTemplateDialog.getValidationMessage()).toContain(`Name can't contain these characters`); } }); @@ -270,14 +270,14 @@ describe('Create file from template', () => { await createFromTemplateDialog.enterName('file-name.'); expect(await createFromTemplateDialog.isCreateButtonEnabled()).toBe(false, 'Create button is not disabled'); - expect(await createFromTemplateDialog.getValidationMessage()).toMatch(`File name can't end with a period .`); + expect(await createFromTemplateDialog.getValidationMessage()).toMatch(`Name can't end with a period .`); }); it('File name containing only spaces - [C325034]', async () => { await createFromTemplateDialog.enterName(' '); expect(await createFromTemplateDialog.isCreateButtonEnabled()).toBe(false, 'Create button is not disabled'); - expect(await createFromTemplateDialog.getValidationMessage()).toMatch(`File name can't contain only spaces`); + expect(await createFromTemplateDialog.getValidationMessage()).toMatch(`Name can't contain only spaces`); }); it('Title too long - [C290146]', async () => { diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 8825d3e58..cfcd50a6a 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -377,10 +377,10 @@ "ERRORS": { "DESCRIPTION_TOO_LONG": "Use 512 characters or less for description", "TITLE_TOO_LONG": "Use 256 characters or less for title", - "REQUIRED": "File name is required", - "SPECIAL_CHARACTERS": "File name can't contain these characters * \" < > \\ / ? : |", - "ENDING_DOT": "File name can't end with a period .", - "ONLY_SPACES": "File name can't contain only spaces" + "REQUIRED": "Name is required", + "SPECIAL_CHARACTERS": "Name can't contain these characters * \" < > \\ / ? : |", + "ENDING_DOT": "Name can't end with a period .", + "ONLY_SPACES": "Name can't contain only spaces" } } }, From 1eab186340b09d40eb2c99c766cdd68610e860bb Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 23 Jan 2020 17:16:26 +0200 Subject: [PATCH 73/96] adf update (#1319) --- package-lock.json | 141 +++++++++++++++++++++++++++++++++++----------- package.json | 8 +-- 2 files changed, 112 insertions(+), 37 deletions(-) diff --git a/package-lock.json b/package-lock.json index e3d920dda..9cebfcffb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,37 +5,37 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57.tgz", - "integrity": "sha512-F1ccqy3tz5G4n54EzEWo6DA2CrZU/hrqmS21QfkyHq3ytChJCqQjAf99L8MG6sIdmHKoLwoofREkS8p8q0K3PA==", + "version": "3.7.0-deb2a0082f254b19d4980d89095a3535976fa606", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-3.7.0-deb2a0082f254b19d4980d89095a3535976fa606.tgz", + "integrity": "sha512-rixkyhLSv+xJdRMKjdiePOif/CftRCdbpH157F+teR2CoBN7CQbJG3d2HpS0r16sB5zMACiv0UFre8Z6Z3mA3w==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/adf-core": { - "version": "3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57.tgz", - "integrity": "sha512-HT1bdNflN3QF/toRnHxpg/4ioGvPfdApFc9ov4odER5Tu8Jx9BJVUBExUnkyKQKMP/KPew/ct9z+qFgHDctVRg==", + "version": "3.7.0-deb2a0082f254b19d4980d89095a3535976fa606", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-3.7.0-deb2a0082f254b19d4980d89095a3535976fa606.tgz", + "integrity": "sha512-cYNRFeqLcc5DPVqlunKZjQ+yygm8JuXqk/B0vY1B8bNUukrbGB1c08ePiBa5phXuUqw6ivUq3DSAcOmayS6saw==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/adf-extensions": { - "version": "3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57", - "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57.tgz", - "integrity": "sha512-4t0laDE57FnPXgwaR82AAuScxsjBCNSUHCQL2LA9JLQ5LdlxaIQTGr/7ZaMmA1D67UD+frL1GkSThu815jvoFA==", + "version": "3.7.0-deb2a0082f254b19d4980d89095a3535976fa606", + "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-3.7.0-deb2a0082f254b19d4980d89095a3535976fa606.tgz", + "integrity": "sha512-BcNNRCD0odNkMfAiU4sCUz5h4ZUWy8wsKVQvAaq/3X1ekqDp1+p/iSPHqjWWbCUX8ptQ+4haoEep5+KP7LgL9g==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/js-api": { - "version": "3.7.0-c48ced828e07de899beecb005cd7c4dc1668f64c", - "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-3.7.0-c48ced828e07de899beecb005cd7c4dc1668f64c.tgz", - "integrity": "sha512-DGNjyhCexaIkyTMZKqKTCRZpdOHcANuo8Qins0XVxoSD7BGP35cp0FXCM7BiCrxFRShoZ1LKG94+CJl6rTxoGg==", + "version": "3.7.0-2d9ba39ba3d09965bf711c615b1985a06a97b195", + "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-3.7.0-2d9ba39ba3d09965bf711c615b1985a06a97b195.tgz", + "integrity": "sha512-wupSj6MzhjvhqrD/s95EC0CgCOiLbD6LD45xnafpZcSVAXV6ltJCaiGI8WkF+Tbx3EuICZzTKNfygXpIjlY82w==", "requires": { "event-emitter": "^0.3.5", "minimatch": "3.0.4", - "superagent": "^3.8.2" + "superagent": "^5.1.2" } }, "@angular-devkit/architect": { @@ -3006,6 +3006,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -3046,7 +3047,8 @@ "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true }, "component-inherit": { "version": "0.0.3", @@ -3306,7 +3308,8 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "cosmiconfig": { "version": "4.0.0", @@ -3778,6 +3781,7 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, "requires": { "ms": "^2.1.1" } @@ -4734,7 +4738,8 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true }, "extend-shallow": { "version": "3.0.2", @@ -4895,6 +4900,11 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, "fastparse": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", @@ -5146,6 +5156,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -7147,7 +7158,8 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true }, "isbinaryfile": { "version": "3.0.3", @@ -8617,7 +8629,8 @@ "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true }, "mime-db": { "version": "1.37.0", @@ -10103,7 +10116,8 @@ "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true }, "progress": { "version": "2.0.3", @@ -10430,7 +10444,8 @@ "qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true }, "querystring": { "version": "0.2.0", @@ -10604,6 +10619,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12272,20 +12288,79 @@ } }, "superagent": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", - "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-5.2.1.tgz", + "integrity": "sha512-46b4Lkwnlz7Ebdv2FBbfuqb3kVkG1jV/SK3EW6NnwL9a3T4h5hHtegNEQfbXvTFbDoUZXId4W3dMgap2f6ic1g==", "requires": { - "component-emitter": "^1.2.0", - "cookiejar": "^2.1.0", - "debug": "^3.1.0", - "extend": "^3.0.0", - "form-data": "^2.3.1", - "formidable": "^1.2.0", - "methods": "^1.1.1", - "mime": "^1.4.1", - "qs": "^6.5.1", - "readable-stream": "^2.3.5" + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "fast-safe-stringify": "^2.0.7", + "form-data": "^3.0.0", + "formidable": "^1.2.1", + "methods": "^1.1.2", + "mime": "^2.4.4", + "qs": "^6.9.1", + "readable-stream": "^3.4.0", + "semver": "^6.3.0" + }, + "dependencies": { + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "form-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", + "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" + }, + "qs": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz", + "integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==" + }, + "readable-stream": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.5.0.tgz", + "integrity": "sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } } }, "supports-color": { diff --git a/package.json b/package.json index cdc0bf0ed..b7f6f4594 100644 --- a/package.json +++ b/package.json @@ -40,10 +40,10 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57", - "@alfresco/adf-core": "3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57", - "@alfresco/adf-extensions": "3.7.0-5c1aff4187ecc00b8d0e162e0f06bb52e1f9bf57", - "@alfresco/js-api": "3.7.0-c48ced828e07de899beecb005cd7c4dc1668f64c", + "@alfresco/adf-content-services": "3.7.0-deb2a0082f254b19d4980d89095a3535976fa606", + "@alfresco/adf-core": "3.7.0-deb2a0082f254b19d4980d89095a3535976fa606", + "@alfresco/adf-extensions": "3.7.0-deb2a0082f254b19d4980d89095a3535976fa606", + "@alfresco/js-api": "3.7.0-2d9ba39ba3d09965bf711c615b1985a06a97b195", "@angular/animations": "7.2.15", "@angular/cdk": "^7.3.7", "@angular/common": "7.2.15", From 2733c69c9a8b0ae37c463c28baf35a66f1a01ae8 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Thu, 23 Jan 2020 17:47:25 +0200 Subject: [PATCH 74/96] [ACA-1921] automate tests for Create folder from template (#1320) * automate tests for Create folder from template added unit test for exclusion of folder links * fix stupid mistake --- e2e/components/menu/menu.ts | 46 ++- e2e/components/sidenav/sidenav.ts | 18 +- .../actions/create-file-from-template.test.ts | 37 +- .../create-folder-from-template.test.ts | 387 ++++++++++++++++++ e2e/suites/actions/new-menu.test.ts | 3 + e2e/suites/actions/upload-file.test.ts | 2 + e2e/utilities/admin-actions.ts | 52 ++- .../repo-client/apis/nodes/nodes-api.ts | 110 +++-- protractor.conf.js | 1 + .../services/node-template.service.spec.ts | 26 +- 10 files changed, 597 insertions(+), 85 deletions(-) create mode 100755 e2e/suites/actions/create-folder-from-template.test.ts diff --git a/e2e/components/menu/menu.ts b/e2e/components/menu/menu.ts index 6d0673c45..e6b44d3a6 100755 --- a/e2e/components/menu/menu.ts +++ b/e2e/components/menu/menu.ts @@ -33,7 +33,15 @@ export class Menu extends Component { root: '.mat-menu-panel', item: '.mat-menu-item', icon: '.mat-icon', - uploadFiles: 'app-upload-files', + + uploadFilesInput: 'app-upload-files', + + uploadFile: 'app.create.uploadFile', + uploadFolder: 'app.create.uploadFolder', + createFolder: 'app.create.folder', + createLibrary: 'app.create.library', + createFileFromTemplate: 'app.create.fileFromTemplate', + createFolderFromTemplate: 'app.create.folderFromTemplate', submenu: 'app-context-menu-item .mat-menu-item', @@ -46,14 +54,20 @@ export class Menu extends Component { items: ElementArrayFinder = this.component.all(by.css(Menu.selectors.item)); backdrop: ElementFinder = browser.element(by.css('.cdk-overlay-backdrop')); - uploadFiles: ElementFinder = browser.element(by.id(Menu.selectors.uploadFiles)); + + uploadFilesInput: ElementFinder = browser.element(by.id(Menu.selectors.uploadFilesInput)); submenus: ElementArrayFinder = browser.element.all(by.css(Menu.selectors.submenu)); + uploadFileAction: ElementFinder = this.component.element(by.id(Menu.selectors.uploadFile)); + uploadFolderAction: ElementFinder = this.component.element(by.id(Menu.selectors.uploadFolder)); + createFolderAction: ElementFinder = this.component.element(by.id(Menu.selectors.createFolder)); + createLibraryAction: ElementFinder = this.component.element(by.id(Menu.selectors.createLibrary)); + createFileFromTemplateAction: ElementFinder = this.component.element(by.id(Menu.selectors.createFileFromTemplate)); + createFolderFromTemplateAction: ElementFinder = this.component.element(by.id(Menu.selectors.createFolderFromTemplate)); + cancelEditingAction: ElementFinder = this.component.element(by.css(Menu.selectors.cancelEditing)); cancelJoinAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'Cancel Join')); copyAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'Copy')); - createFolderAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'Create Folder')); - createLibraryAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'Create Library')); deleteAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'Delete')); downloadAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'Download')); editFolderAction: ElementFinder = this.component.element(by.css(Menu.selectors.editFolder)); @@ -72,9 +86,6 @@ export class Menu extends Component { restoreAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'Restore')); shareAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'Share')); shareEditAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'Shared Link Settings')); - uploadFileAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'Upload File')); - uploadFolderAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'Upload Folder')); - createFileFromTemplateAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'Create file from template')); viewAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'View')); viewDetailsAction: ElementFinder = this.component.element(by.cssContainingText(Menu.selectors.item, 'View Details')); @@ -235,7 +246,7 @@ export class Menu extends Component { } uploadFile(): ElementFinder { - return this.uploadFiles; + return this.uploadFilesInput; } async clickEditFolder(): Promise { @@ -364,6 +375,10 @@ export class Menu extends Component { return (await this.createFileFromTemplateAction.isPresent()) && (await this.createFileFromTemplateAction.isEnabled()); } + async isCreateFolderFromTemplateEnabled(): Promise { + return (await this.createFolderFromTemplateAction.isPresent()) && (await this.createFolderFromTemplateAction.isEnabled()); + } + async clickCreateFolder(): Promise { const action = this.createFolderAction; await action.click(); @@ -374,18 +389,13 @@ export class Menu extends Component { await action.click(); } - async clickUploadFile(): Promise { - const action = this.uploadFileAction; - await action.click(); - } - - async clickUploadFolder(): Promise { - const action = this.uploadFolderAction; - await action.click(); - } - async clickCreateFileFromTemplate(): Promise { const action = this.createFileFromTemplateAction; await action.click(); } + + async clickCreateFolderFromTemplate(): Promise { + const action = this.createFolderFromTemplateAction; + await action.click(); + } } diff --git a/e2e/components/sidenav/sidenav.ts b/e2e/components/sidenav/sidenav.ts index f49553c1f..24b231f2f 100755 --- a/e2e/components/sidenav/sidenav.ts +++ b/e2e/components/sidenav/sidenav.ts @@ -55,6 +55,7 @@ export class Sidenav extends Component { links: ElementArrayFinder = this.component.all(by.css(Sidenav.selectors.link)); activeLink: ElementFinder = this.component.element(by.css(Sidenav.selectors.activeClass)); + newButton: ElementArrayFinder = this.component.all(by.css(Sidenav.selectors.newButton)); personalFiles: ElementFinder = this.component.element(by.css(Sidenav.selectors.personalFiles)); @@ -90,25 +91,28 @@ export class Sidenav extends Component { } async openNewMenu(): Promise { - const { menu, newButton } = this; - - await newButton.click(); - await menu.waitForMenuToOpen(); + await this.newButton.click(); + await this.menu.waitForMenuToOpen(); } async openCreateFolderDialog(): Promise { await this.openNewMenu(); - await this.menu.clickMenuItem('Create Folder'); + await this.menu.clickCreateFolder(); } async openCreateLibraryDialog(): Promise { await this.openNewMenu(); - await this.menu.clickMenuItem('Create Library'); + await this.menu.clickCreateLibrary(); } async openCreateFileFromTemplateDialog(): Promise { await this.openNewMenu(); - await this.menu.clickMenuItem('Create file from template'); + await this.menu.clickCreateFileFromTemplate(); + } + + async openCreateFolderFromTemplateDialog(): Promise { + await this.openNewMenu(); + await this.menu.clickCreateFolderFromTemplate(); } async isActive(name: string): Promise { diff --git a/e2e/suites/actions/create-file-from-template.test.ts b/e2e/suites/actions/create-file-from-template.test.ts index a22409792..21f40ef69 100755 --- a/e2e/suites/actions/create-file-from-template.test.ts +++ b/e2e/suites/actions/create-file-from-template.test.ts @@ -67,7 +67,7 @@ describe('Create file from template', () => { title: `file site title`, description: `file site description` }; - const duplicateFileSite = `duplicate-file-site-${random}`; + const duplicateFileSite = `duplicate-file-site-${random}.txt`; let docLibUserSite: string; const userApi = new RepoClient(username, username); @@ -80,7 +80,7 @@ describe('Create file from template', () => { const createFromTemplateDialog = new CreateFromTemplateDialog(); const { sidenav } = page; - beforeAll( async (done) => { + beforeAll(async () => { await adminApiActions.createUser({ username }); parentId = (await userApi.nodes.createFolder(parent)).entry.id; @@ -88,17 +88,15 @@ describe('Create file from template', () => { await userApi.sites.createSite(siteName); docLibUserSite = await userApi.sites.getDocLibId(siteName); - await userApi.nodes.createFolder(duplicateFileSite, docLibUserSite); + await userApi.nodes.createFile(duplicateFileSite, docLibUserSite); await loginPage.loginWith(username); - done(); }); - afterAll(async (done) => { + afterAll(async () => { await userApi.nodes.deleteNodeById(parentId); await userApi.sites.deleteSite(siteName); - await adminApiActions.cleanNodeTemplatesFolder(); - done(); + await adminApiActions.cleanupNodeTemplatesFolder(); }); beforeEach(async () => { @@ -142,18 +140,16 @@ describe('Create file from template', () => { }; let link: string; - beforeAll(async (done) => { + beforeAll(async () => { await adminApiActions.createNodeTemplatesHierarchy(templates); - await adminApiActions.removeUserAccessOnNode(restrictedTemplateFolder); + await adminApiActions.removeUserAccessOnNodeTemplate(restrictedTemplateFolder); link = (await adminApiActions.createLinkToFileName(template2InRootFolder, await adminApiActions.getNodeTemplatesFolderId())).entry.name; - done(); }); describe('Select Template dialog', () => { - beforeEach(async (done) => { + beforeEach(async () => { await sidenav.openCreateFileFromTemplateDialog(); await selectTemplateDialog.waitForDialogToOpen(); - done(); }); it('Select template - dialog UI - with existing templates - [C325043]', async () => { @@ -230,13 +226,12 @@ describe('Create file from template', () => { }); describe('Create from template dialog', () => { - beforeEach(async (done) => { + beforeEach(async () => { await sidenav.openCreateFileFromTemplateDialog(); await selectTemplateDialog.waitForDialogToOpen(); await selectTemplateDialog.dataTable.selectItem(template1InRootFolder); await selectTemplateDialog.clickNext(); await createFromTemplateDialog.waitForDialogToOpen(); - done(); }); it('Create file from template - dialog UI - [C325020]', async () => { @@ -298,7 +293,7 @@ describe('Create file from template', () => { }); describe('On Personal Files', () => { - beforeEach(async (done) => { + beforeEach(async () => { await page.clickPersonalFilesAndWait(); await page.dataTable.doubleClickOnRowByName(parent); await sidenav.openCreateFileFromTemplateDialog(); @@ -306,7 +301,6 @@ describe('Create file from template', () => { await selectTemplateDialog.dataTable.selectItem(template1InRootFolder); await selectTemplateDialog.clickNext(); await createFromTemplateDialog.waitForDialogToOpen(); - done(); }); it('Create a file from a template - with a new Name - [C325030]', async () => { @@ -318,7 +312,7 @@ describe('Create file from template', () => { expect(await page.dataTable.isItemPresent(file1.name)).toBe(true, 'File not displayed in list view'); }); - it('Create a file from a template - with a Name, Title and Description - [C325026]', async (done) => { + it('Create a file from a template - with a Name, Title and Description - [C325026]', async () => { await createFromTemplateDialog.enterName(file2.name); await createFromTemplateDialog.enterTitle(file2.title); await createFromTemplateDialog.enterDescription(file2.description); @@ -331,7 +325,6 @@ describe('Create file from template', () => { expect(desc).toEqual(file2.description); const title = await userApi.nodes.getNodeTitle(file2.name, parentId); expect(title).toEqual(file2.title); - done(); }); it('Create a file with a duplicate name - [C325028]', async () => { @@ -356,14 +349,14 @@ describe('Create file from template', () => { await createFromTemplateDialog.waitForDialogToClose(); await page.dataTable.waitForHeader(); - expect(await page.dataTable.isItemPresent(nameWithSpaces.trim())).toBe(true, 'Folder not displayed in list view'); + expect(await page.dataTable.isItemPresent(nameWithSpaces.trim())).toBe(true, 'File not displayed in list view'); }); }); describe('On File Libraries', () => { const fileLibrariesPage = new BrowsingPage(); - beforeEach(async (done) => { + beforeEach(async () => { await fileLibrariesPage.goToMyLibrariesAndWait(); await page.dataTable.doubleClickOnRowByName(siteName); await sidenav.openCreateFileFromTemplateDialog(); @@ -371,10 +364,9 @@ describe('Create file from template', () => { await selectTemplateDialog.dataTable.selectItem(template1InRootFolder); await selectTemplateDialog.clickNext(); await createFromTemplateDialog.waitForDialogToOpen(); - done(); }); - it('Create a file from a template - with Name, Title and Description - [C325023]', async (done) => { + it('Create a file from a template - with Name, Title and Description - [C325023]', async () => { await createFromTemplateDialog.enterName(fileSite.name); await createFromTemplateDialog.enterTitle(fileSite.title); await createFromTemplateDialog.enterDescription(fileSite.description); @@ -387,7 +379,6 @@ describe('Create file from template', () => { expect(desc).toEqual(fileSite.description); const title = await userApi.nodes.getNodeTitle(fileSite.name, docLibUserSite); expect(title).toEqual(fileSite.title); - done(); }); it('Cancel file creation - [C325024]', async () => { diff --git a/e2e/suites/actions/create-folder-from-template.test.ts b/e2e/suites/actions/create-folder-from-template.test.ts new file mode 100755 index 000000000..02364c15a --- /dev/null +++ b/e2e/suites/actions/create-folder-from-template.test.ts @@ -0,0 +1,387 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { LoginPage, BrowsingPage } from '../../pages/pages'; +import { SelectTemplateDialog } from '../../components/dialog/select-template-dialog'; +import { CreateFromTemplateDialog } from '../../components/dialog/create-from-template-dialog'; +import { Utils } from '../../utilities/utils'; +import { AdminActions } from '../../utilities/admin-actions'; +import { RepoClient, NodeContentTree } from '../../utilities/repo-client/repo-client'; + +describe('Create folder from template', () => { + const random = Utils.random(); + + const username = `user-${random}`; + + const restrictedTemplateFolder = `restricted-folder-${random}`; + const fileInRestrictedFolder = `restricted-file-${random}.txt`; + + const templateFolder1 = `template-folder1-${random}`; + const fileInFolder1 = `file-1-${random}.txt`; + + const templateFolder2 = `template-folder2-${random}`; + const fileInFolder2 = `file-2-${random}.txt`; + const templateSubFolder = `template-sub-folder-${random}`; + + const fileInRootFolder = `file-in-root-${random}.txt`; + const folderInRootFolder = `folder-in-root-${random}`; + + const parent = `parent-${random}`; + let parentId: string; + + const folder1 = { + name: `folder1-${random}` + }; + const folder2 = { + name: `folder2-${random}`, + title: `folder2 title`, + description: `folder2 description` + }; + const duplicateFolderName = `duplicate-folder-${random}`; + const nameWithSpaces = ` folder-${random} `; + + const siteName = `site-${random}`; + const folderSite = { + name: `folder-site-${random}`, + title: `folder site title`, + description: `folder site description` + }; + const duplicateFolderSite = `duplicate-folder-site-${random}`; + let docLibUserSite: string; + + const templates: NodeContentTree = { + folders: [ + { + name: folderInRootFolder + }, + { + name: templateFolder1, + files: [fileInFolder1] + }, + { + name: templateFolder2, + folders: [ + { + name: templateSubFolder + } + ], + files: [fileInFolder2] + }, + { + name: restrictedTemplateFolder, + files: [fileInRestrictedFolder] + } + ], + files: [fileInRootFolder] + }; + let folderLink: string; + + const userApi = new RepoClient(username, username); + const adminApiActions = new AdminActions(); + + const loginPage = new LoginPage(); + const page = new BrowsingPage(); + const selectTemplateDialog = new SelectTemplateDialog(); + const createFromTemplateDialog = new CreateFromTemplateDialog(); + const { sidenav } = page; + + beforeAll(async () => { + await adminApiActions.createUser({ username }); + + parentId = (await userApi.nodes.createFolder(parent)).entry.id; + await userApi.nodes.createFolder(duplicateFolderName, parentId); + + await userApi.sites.createSite(siteName); + docLibUserSite = await userApi.sites.getDocLibId(siteName); + await userApi.nodes.createFolder(duplicateFolderSite, docLibUserSite); + + await adminApiActions.createSpaceTemplatesHierarchy(templates); + await adminApiActions.removeUserAccessOnSpaceTemplate(restrictedTemplateFolder); + folderLink = (await adminApiActions.createLinkToFolderName(folderInRootFolder, await adminApiActions.getSpaceTemplatesFolderId())).entry.name; + + await loginPage.loginWith(username); + }); + + afterAll(async () => { + await userApi.nodes.deleteNodeById(parentId); + await userApi.sites.deleteSite(siteName); + await adminApiActions.cleanupSpaceTemplatesFolder(); + }); + + beforeEach(async () => { + await page.closeOpenDialogs(); + }); + + describe('Select Template dialog', () => { + beforeEach(async () => { + await sidenav.openCreateFolderFromTemplateDialog(); + await selectTemplateDialog.waitForDialogToOpen(); + }); + + it('Select template - dialog UI - with existing templates - [C325147]', async () => { + expect(await selectTemplateDialog.getTitle()).toEqual('Select a folder template'); + expect(await selectTemplateDialog.dataTable.isEmpty()).toBe(false, 'Datatable is empty'); + expect(await selectTemplateDialog.dataTable.isItemPresent(templateFolder1)).toBe(true, 'template folder not displayed'); + expect(await selectTemplateDialog.dataTable.isItemPresent(templateFolder2)).toBe(true, 'template folder not displayed'); + expect(await selectTemplateDialog.dataTable.isItemPresent(fileInRootFolder)).toBe(true, 'file not displayed'); + expect(await selectTemplateDialog.breadcrumb.getCurrentFolderName()).toEqual('Space Templates'); + expect(await selectTemplateDialog.isNextButtonEnabled()).toBe(false, 'Next button is not disabled'); + expect(await selectTemplateDialog.isCancelButtonEnabled()).toBe(true, 'Cancel button is not enabled'); + }); + + it(`Templates don't appear if user doesn't have permissions to see them - [C325148]`, async () => { + expect(await selectTemplateDialog.dataTable.isItemPresent(restrictedTemplateFolder)).toBe(false, 'restricted template folder is displayed'); + }); + + it('Navigate through the templates list with folder hierarchy - [C325149]', async () => { + expect(await selectTemplateDialog.dataTable.isItemPresent(templateFolder2)).toBe(true, 'template folder not displayed'); + + await selectTemplateDialog.dataTable.doubleClickOnRowByName(templateFolder2); + + expect(await selectTemplateDialog.dataTable.isItemPresent(templateSubFolder)).toBe(true, 'template sub-folder not displayed'); + expect(await selectTemplateDialog.dataTable.isItemPresent(fileInFolder2)).toBe(true, 'template not displayed'); + expect(await selectTemplateDialog.dataTable.isItemPresent(templateFolder1)).toBe(false, 'template folder is displayed'); + expect(await selectTemplateDialog.breadcrumb.getCurrentFolderName()).toEqual(templateFolder2); + + await selectTemplateDialog.dataTable.doubleClickOnRowByName(templateSubFolder); + + expect(await selectTemplateDialog.breadcrumb.getCurrentFolderName()).toEqual(templateSubFolder); + expect(await selectTemplateDialog.dataTable.isEmpty()).toBe(true, 'datatable is not empty'); + + await selectTemplateDialog.breadcrumb.openPath(); + + expect(await selectTemplateDialog.breadcrumb.getPathItems()).toEqual([ templateFolder2, 'Space Templates' ]); + }); + + it(`Templates list doesn't allow multiple selection - [C325150]`, async () => { + expect(await selectTemplateDialog.dataTable.getSelectedRowsCount()).toEqual(0, 'Incorrect number of selected rows'); + + await selectTemplateDialog.dataTable.selectItem(templateFolder1); + expect(await selectTemplateDialog.dataTable.getSelectedRowsCount()).toEqual(1, 'Incorrect number of selected rows'); + expect(await selectTemplateDialog.dataTable.getSelectedRowsNames()).toEqual([ templateFolder1 ], 'Incorrect selected item'); + + await Utils.pressCmd(); + await selectTemplateDialog.dataTable.selectItem(templateFolder2); + await Utils.releaseKeyPressed(); + + expect(await selectTemplateDialog.dataTable.getSelectedRowsCount()).toEqual(1, 'Incorrect number of selected rows'); + expect(await selectTemplateDialog.dataTable.getSelectedRowsNames()).toEqual([ templateFolder2 ], 'Incorrect selected item'); + }); + + it('Links to folders are not displayed - [C325153]', async () => { + expect(await selectTemplateDialog.dataTable.isItemPresent(folderLink)).toBe(false, 'Link to folder is displayed'); + }); + + it('Cancel the Select template dialog - [C325151]', async () => { + expect(await selectTemplateDialog.isCancelButtonEnabled()).toBe(true, 'Cancel button is not enabled'); + + await selectTemplateDialog.clickCancel(); + + expect(await selectTemplateDialog.isDialogOpen()).toBe(false, 'Select Template dialog is open'); + }); + + it('Next button is disabled when selecting a file - [C325139]', async () => { + expect(await selectTemplateDialog.isNextButtonEnabled()).toBe(false, 'Next button is enabled'); + + await selectTemplateDialog.dataTable.selectItem(fileInRootFolder); + + expect(await selectTemplateDialog.isNextButtonEnabled()).toBe(false, 'Next button is enabled'); + }); + }); + + describe('Create from template dialog', () => { + beforeEach(async () => { + await sidenav.openCreateFolderFromTemplateDialog(); + await selectTemplateDialog.waitForDialogToOpen(); + await selectTemplateDialog.dataTable.selectItem(templateFolder1); + await selectTemplateDialog.clickNext(); + await createFromTemplateDialog.waitForDialogToOpen(); + }); + + it('Create folder from template - dialog UI - [C325142]', async () => { + expect(await createFromTemplateDialog.getTitle()).toEqual(`Create new folder from '${templateFolder1}'`); + expect(await createFromTemplateDialog.isNameFieldDisplayed()).toBe(true, 'Name field not displayed'); + expect(await createFromTemplateDialog.isTitleFieldDisplayed()).toBe(true, 'Title field not displayed'); + expect(await createFromTemplateDialog.isDescriptionFieldDisplayed()).toBe(true, 'Description field not displayed'); + expect(await createFromTemplateDialog.isCancelButtonEnabled()).toBe(true, 'Cancel button is not enabled'); + expect(await createFromTemplateDialog.isCreateButtonEnabled()).toBe(true, 'Create button is not enabled'); + }); + + it('Folder name is required - [C325143]', async () => { + expect(await createFromTemplateDialog.getName()).toEqual(templateFolder1); + await createFromTemplateDialog.deleteNameWithBackspace(); + + expect(await createFromTemplateDialog.getValidationMessage()).toEqual('Name is required'); + expect(await createFromTemplateDialog.isCreateButtonEnabled()).toBe(false, 'Create button is not disabled'); + }); + + it('Special characters in folder name - [C325144]', async () => { + const namesWithSpecialChars = [ 'a*a', 'a"a', 'aa', `a\\a`, 'a/a', 'a?a', 'a:a', 'a|a' ]; + + for (const name of namesWithSpecialChars) { + await createFromTemplateDialog.enterName(name); + expect(await createFromTemplateDialog.isCreateButtonEnabled()).toBe(false, 'Create button is not disabled'); + expect(await createFromTemplateDialog.getValidationMessage()).toContain(`Name can't contain these characters`); + } + }); + + it('Folder name ending with a dot - [C325145]', async () => { + await createFromTemplateDialog.enterName('folder-name.'); + + expect(await createFromTemplateDialog.isCreateButtonEnabled()).toBe(false, 'Create button is not disabled'); + expect(await createFromTemplateDialog.getValidationMessage()).toMatch(`Name can't end with a period .`); + }); + + it('Folder name containing only spaces - [C325146]', async () => { + await createFromTemplateDialog.enterName(' '); + + expect(await createFromTemplateDialog.isCreateButtonEnabled()).toBe(false, 'Create button is not disabled'); + expect(await createFromTemplateDialog.getValidationMessage()).toMatch(`Name can't contain only spaces`); + }); + + it('Title too long - [C325141]', async () => { + await createFromTemplateDialog.enterTitle(Utils.string257); + await Utils.pressTab(); + + expect(await createFromTemplateDialog.isCreateButtonEnabled()).toBe(false, 'Create button is not disabled'); + expect(await createFromTemplateDialog.getValidationMessage()).toMatch(`Use 256 characters or less for title`); + }); + + it('Description too long - [C325140]', async () => { + await createFromTemplateDialog.enterDescription(Utils.string513); + await Utils.pressTab(); + + expect(await createFromTemplateDialog.isCreateButtonEnabled()).toBe(false, 'Create button is not disabled'); + expect(await createFromTemplateDialog.getValidationMessage()).toMatch(`Use 512 characters or less for description`); + }); + }); + + describe('On Personal Files', () => { + beforeEach(async () => { + await page.clickPersonalFilesAndWait(); + await page.dataTable.doubleClickOnRowByName(parent); + await sidenav.openCreateFolderFromTemplateDialog(); + await selectTemplateDialog.waitForDialogToOpen(); + await selectTemplateDialog.dataTable.selectItem(templateFolder1); + await selectTemplateDialog.clickNext(); + await createFromTemplateDialog.waitForDialogToOpen(); + }); + + it('Create a folder from a template - with a new Name - [C325157]', async () => { + await createFromTemplateDialog.enterName(folder1.name); + await createFromTemplateDialog.clickCreate(); + await createFromTemplateDialog.waitForDialogToClose(); + await page.dataTable.waitForHeader(); + + expect(await page.dataTable.isItemPresent(folder1.name)).toBe(true, 'Folder not displayed in list view'); + }); + + it('Create a folder from a template - with a Name, Title and Description - [C325154]', async () => { + await createFromTemplateDialog.enterName(folder2.name); + await createFromTemplateDialog.enterTitle(folder2.title); + await createFromTemplateDialog.enterDescription(folder2.description); + await createFromTemplateDialog.clickCreate(); + await createFromTemplateDialog.waitForDialogToClose(); + await page.dataTable.waitForHeader(); + + expect(await page.dataTable.isItemPresent(folder2.name)).toBe(true, 'Folder not displayed in list view'); + const desc = await userApi.nodes.getNodeDescription(folder2.name, parentId); + expect(desc).toEqual(folder2.description); + const title = await userApi.nodes.getNodeTitle(folder2.name, parentId); + expect(title).toEqual(folder2.title); + }); + + it('Create a folder with a duplicate name - [C325156]', async () => { + await createFromTemplateDialog.enterName(duplicateFolderName); + await createFromTemplateDialog.clickCreate(); + + expect(await page.getSnackBarMessage()).toEqual(`This name is already in use, try a different name.`); + expect(await createFromTemplateDialog.isDialogOpen()).toBe(true, 'dialog is not present'); + }); + + it('Cancel folder creation - [C325155]', async () => { + await createFromTemplateDialog.enterName('test'); + await createFromTemplateDialog.clickCancel(); + + expect(await createFromTemplateDialog.isDialogOpen()).not.toBe(true, 'dialog is not closed'); + expect(await page.dataTable.isItemPresent('test')).toBe(false, 'Folder should not appear in the list'); + }); + + it('Trim spaces from folder Name - [C325158]', async () => { + await createFromTemplateDialog.enterName(nameWithSpaces); + await createFromTemplateDialog.clickCreate(); + await createFromTemplateDialog.waitForDialogToClose(); + await page.dataTable.waitForHeader(); + + expect(await page.dataTable.isItemPresent(nameWithSpaces.trim())).toBe(true, 'Folder not displayed in list view'); + }); + }); + + describe('On File Libraries', () => { + const fileLibrariesPage = new BrowsingPage(); + + beforeEach(async () => { + await fileLibrariesPage.goToMyLibrariesAndWait(); + await page.dataTable.doubleClickOnRowByName(siteName); + await sidenav.openCreateFolderFromTemplateDialog(); + await selectTemplateDialog.waitForDialogToOpen(); + await selectTemplateDialog.dataTable.selectItem(templateFolder1); + await selectTemplateDialog.clickNext(); + await createFromTemplateDialog.waitForDialogToOpen(); + }); + + it('Create a folder from a template - with Name, Title and Description - [C325161]', async () => { + await createFromTemplateDialog.enterName(folderSite.name); + await createFromTemplateDialog.enterTitle(folderSite.title); + await createFromTemplateDialog.enterDescription(folderSite.description); + await createFromTemplateDialog.clickCreate(); + await createFromTemplateDialog.waitForDialogToClose(); + await page.dataTable.waitForHeader(); + + expect(await page.dataTable.isItemPresent(folderSite.name)).toBe(true, 'Folder not displayed in list view'); + const desc = await userApi.nodes.getNodeDescription(folderSite.name, docLibUserSite); + expect(desc).toEqual(folderSite.description); + const title = await userApi.nodes.getNodeTitle(folderSite.name, docLibUserSite); + expect(title).toEqual(folderSite.title); + }); + + it('Cancel folder creation - [C325162]', async () => { + await createFromTemplateDialog.enterName('test'); + await createFromTemplateDialog.clickCancel(); + + expect(await createFromTemplateDialog.isDialogOpen()).not.toBe(true, 'dialog is not closed'); + expect(await page.dataTable.isItemPresent('test')).toBe(false, 'Folder should not appear in the list'); + }); + + it('Create a folder with a duplicate name - [C325163]', async () => { + await createFromTemplateDialog.enterName(duplicateFolderSite); + await createFromTemplateDialog.clickCreate(); + + expect(await page.getSnackBarMessage()).toEqual(`This name is already in use, try a different name.`); + expect(await createFromTemplateDialog.isDialogOpen()).toBe(true, 'dialog is not present'); + }); + }); + +}); diff --git a/e2e/suites/actions/new-menu.test.ts b/e2e/suites/actions/new-menu.test.ts index 308df4d6a..59627e4a0 100755 --- a/e2e/suites/actions/new-menu.test.ts +++ b/e2e/suites/actions/new-menu.test.ts @@ -77,6 +77,7 @@ describe('New menu', () => { expect(await menu.isCreateLibraryEnabled()).toBe(true, 'Create Library option not enabled'); expect(await menu.isCreateFileFromTemplateEnabled()).toBe(true, 'Create file from template is not enabled'); + expect(await menu.isCreateFolderFromTemplateEnabled()).toBe(true, 'Create folder from template is not enabled'); }); it('Actions in File Libraries - user with enough permissions - [C280393]', async () => { @@ -91,6 +92,7 @@ describe('New menu', () => { expect(await menu.isCreateLibraryEnabled()).toBe(true, 'Create Library option not enabled'); expect(await menu.isCreateFileFromTemplateEnabled()).toBe(true, 'Create file from template is not enabled'); + expect(await menu.isCreateFolderFromTemplateEnabled()).toBe(true, 'Create folder from template is not enabled'); }); it('Actions in File Libraries - user without enough permissions - [C280397]', async () => { @@ -105,6 +107,7 @@ describe('New menu', () => { expect(await menu.isCreateLibraryEnabled()).toBe(true, 'Create Library option not enabled'); expect(await menu.isCreateFileFromTemplateEnabled()).toBe(false, 'Create file from template is not disabled'); + expect(await menu.isCreateFolderFromTemplateEnabled()).toBe(false, 'Create folder from template is not disabled'); }); it('Enabled actions tooltips - [C216342]', async () => { diff --git a/e2e/suites/actions/upload-file.test.ts b/e2e/suites/actions/upload-file.test.ts index 04642cb67..b9eb37dfb 100755 --- a/e2e/suites/actions/upload-file.test.ts +++ b/e2e/suites/actions/upload-file.test.ts @@ -63,5 +63,7 @@ describe('Upload files', () => { await dataTable.doubleClickOnRowByName(folder1); await page.sidenav.openNewMenu(); await page.sidenav.menu.uploadFile().sendKeys(`${__dirname}/create-folder.test.ts`); + + expect(await dataTable.isItemPresent('create-folder.test.ts')).toBe(true, 'file not uploaded'); }); }); diff --git a/e2e/utilities/admin-actions.ts b/e2e/utilities/admin-actions.ts index a8b859cd7..980c59825 100755 --- a/e2e/utilities/admin-actions.ts +++ b/e2e/utilities/admin-actions.ts @@ -54,6 +54,10 @@ export class AdminActions { return await this.adminApi.nodes.getNodeIdFromParent('Node Templates', await this.getDataDictionaryId()); } + async getSpaceTemplatesFolderId(): Promise { + return await this.adminApi.nodes.getNodeIdFromParent('Space Templates', await this.getDataDictionaryId()); + } + async createUser(user: PersonModel): Promise { return await this.adminApi.people.createUser(user); } @@ -68,19 +72,47 @@ export class AdminActions { return await this.adminApi.nodes.createContent(hierarchy, `Data Dictionary/Node Templates`); } - async removeUserAccessOnNode(nodeName: string): Promise { + async createSpaceTemplate(name: string, title: string = '', description: string = ''): Promise { + const templatesRootFolderId: string = await this.getSpaceTemplatesFolderId(); + + return await this.adminApi.nodes.createFolder(name, templatesRootFolderId, title, description); + } + + async createSpaceTemplatesHierarchy(hierarchy: NodeContentTree): Promise { + return await this.adminApi.nodes.createContent(hierarchy, `Data Dictionary/Space Templates`); + } + + async removeUserAccessOnNodeTemplate(nodeName: string): Promise { const templatesRootFolderId = await this.getNodeTemplatesFolderId(); const nodeId: string = await this.adminApi.nodes.getNodeIdFromParent(nodeName, templatesRootFolderId); return await this.adminApi.nodes.setInheritPermissions(nodeId, false); } - async cleanNodeTemplatesFolder(): Promise { + async removeUserAccessOnSpaceTemplate(nodeName: string): Promise { + const templatesRootFolderId = await this.getSpaceTemplatesFolderId(); + const nodeId: string = await this.adminApi.nodes.getNodeIdFromParent(nodeName, templatesRootFolderId); + + return await this.adminApi.nodes.setInheritPermissions(nodeId, false); + } + + async cleanupNodeTemplatesFolder(): Promise { return await this.adminApi.nodes.deleteNodeChildren(await this.getNodeTemplatesFolderId()); } + async cleanupSpaceTemplatesFolder(): Promise { + const spaceTemplatesNodeId = await this.getSpaceTemplatesFolderId(); + + // folder links are deleted automatically when original folder is deleted + // Software Engineering Project is the default folder template coming from ACS, should not be deleted + const nodesToDelete = (await this.adminApi.nodes.getNodeChildren(spaceTemplatesNodeId)).list.entries + .filter(node => (node.entry.nodeType !== 'app:folderlink') && (node.entry.name !== 'Software Engineering Project')) + .map(node => node.entry.id); + return await this.adminApi.nodes.deleteNodesById(nodesToDelete); + } + async createLinkToFileId(originalFileId: string, destinationParentId: string): Promise { - return await this.adminApi.nodes.createNodeLink(originalFileId, destinationParentId); + return await this.adminApi.nodes.createFileLink(originalFileId, destinationParentId); } async createLinkToFileName(originalFileName: string, originalFileParentId: string, destinationParentId?: string): Promise { @@ -93,4 +125,18 @@ export class AdminActions { return await this.createLinkToFileId(nodeId, destinationParentId); } + async createLinkToFolderId(originalFolderId: string, destinationParentId: string): Promise { + return await this.adminApi.nodes.createFolderLink(originalFolderId, destinationParentId); + } + + async createLinkToFolderName(originalFolderName: string, originalFolderParentId: string, destinationParentId?: string): Promise { + if (!destinationParentId) { + destinationParentId = originalFolderParentId + }; + + const nodeId = await this.adminApi.nodes.getNodeIdFromParent(originalFolderName, originalFolderParentId); + + return await this.createLinkToFolderId(nodeId, destinationParentId); + } + } diff --git a/e2e/utilities/repo-client/apis/nodes/nodes-api.ts b/e2e/utilities/repo-client/apis/nodes/nodes-api.ts index 580d4476a..4db0b18c9 100755 --- a/e2e/utilities/repo-client/apis/nodes/nodes-api.ts +++ b/e2e/utilities/repo-client/apis/nodes/nodes-api.ts @@ -179,11 +179,9 @@ export class NodesApi extends RepoApi { async deleteNodesById(ids: string[], permanent: boolean = true): Promise { try { - await ids.reduce(async (previous, current) => { - await previous; - const req = await this.deleteNodeById(current, permanent); - return req; - }, Promise.resolve()); + for (const id of ids) { + await this.deleteNodeById(id, permanent); + } } catch (error) { this.handleError(`${this.constructor.name} ${this.deleteNodesById.name}`, error); } @@ -202,10 +200,17 @@ export class NodesApi extends RepoApi { } } - async deleteNodeChildren(parentId: string): Promise { + async deleteNodeChildren(parentId: string, exceptNodesNamed?: string[]): Promise { try { const listEntries = (await this.getNodeChildren(parentId)).list.entries; - const nodeIds = listEntries.map(entries => entries.entry.id); + let nodeIds: string[]; + if (exceptNodesNamed) { + nodeIds = listEntries + .filter(entries => !exceptNodesNamed.includes(entries.entry.name)) + .map(entries => entries.entry.id); + } else { + nodeIds = listEntries.map(entries => entries.entry.id); + } await this.deleteNodesById(nodeIds); } catch (error) { this.handleError(`${this.constructor.name} ${this.deleteNodeChildren.name}`, error); @@ -225,26 +230,7 @@ export class NodesApi extends RepoApi { } } - async createNodeLink(originalNodeId: string, destinationId: string): Promise { - const name = (await this.getNodeById(originalNodeId)).entry.name; - const nodeBody = { - name: `Link to ${name}.url`, - nodeType: 'app:filelink', - properties: { - 'cm:destination': originalNodeId - } - } - - try { - await this.apiAuth(); - return await this.nodesApi.createNode(destinationId, nodeBody); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.createNode.name}`, error); - return null; - } - } - - async createNode(nodeType: string, name: string, parentId: string = '-my-', title: string = '', description: string = '', imageProps: any = null, author: string = '', majorVersion: boolean = true): Promise { + async createNode(nodeType: string, name: string, parentId: string = '-my-', title: string = '', description: string = '', imageProps: any = null, author: string = '', majorVersion: boolean = true, aspectNames: string[] = null): Promise { const nodeBody = { name, nodeType, @@ -253,7 +239,7 @@ export class NodesApi extends RepoApi { 'cm:description': description, 'cm:author': author }, - aspectNames: ['cm:versionable'] // workaround for REPO-4772 + aspectNames }; if (imageProps) { nodeBody.properties = Object.assign(nodeBody.properties, imageProps); @@ -268,9 +254,12 @@ export class NodesApi extends RepoApi { } } - async createFile(name: string, parentId: string = '-my-', title: string = '', description: string = '', author: string = '', majorVersion: boolean = true): Promise { + async createFile(name: string, parentId: string = '-my-', title: string = '', description: string = '', author: string = '', majorVersion: boolean = true, aspectNames: string[] = null): Promise { + if (!aspectNames) { + aspectNames = ['cm:versionable'] // workaround for REPO-4772 + } try { - return await this.createNode('cm:content', name, parentId, title, description, null, author, majorVersion); + return await this.createNode('cm:content', name, parentId, title, description, null, author, majorVersion, aspectNames); } catch (error) { this.handleError(`${this.constructor.name} ${this.createFile.name}`, error); return null; @@ -286,9 +275,9 @@ export class NodesApi extends RepoApi { } } - async createFolder(name: string, parentId: string = '-my-', title: string = '', description: string = '', author: string = ''): Promise { + async createFolder(name: string, parentId: string = '-my-', title: string = '', description: string = '', author: string = '', aspectNames: string[] = null): Promise { try { - return await this.createNode('cm:folder', name, parentId, title, description, null, author); + return await this.createNode('cm:folder', name, parentId, title, description, null, author, null, aspectNames); } catch (error) { this.handleError(`${this.constructor.name} ${this.createFolder.name}`, error); return null; @@ -328,6 +317,61 @@ export class NodesApi extends RepoApi { } } + async addAspects(nodeId: string, aspectNames: string[]): Promise { + try { + await this.apiAuth(); + return this.nodesApi.updateNode(nodeId, { aspectNames }); + } catch (error) { + this.handleError(`${this.constructor.name} ${this.addAspects.name}`, error); + return null; + } + } + + async createFileLink(originalNodeId: string, destinationId: string): Promise { + const name = (await this.getNodeById(originalNodeId)).entry.name; + const nodeBody = { + name: `Link to ${name}.url`, + nodeType: 'app:filelink', + properties: { + 'cm:destination': originalNodeId + } + } + + try { + await this.apiAuth(); + const link = await this.nodesApi.createNode(destinationId, nodeBody); + await this.addAspects(originalNodeId, ['app:linked']); + return link; + } catch (error) { + this.handleError(`${this.constructor.name} ${this.createFileLink.name}`, error); + return null; + } + } + + async createFolderLink(originalNodeId: string, destinationId: string): Promise { + const name = (await this.getNodeById(originalNodeId)).entry.name; + const nodeBody = { + name: `Link to ${name}.url`, + nodeType: 'app:folderlink', + properties: { + 'cm:title': `Link to ${name}.url`, + 'cm:destination': originalNodeId, + 'cm:description': `Link to ${name}.url`, + 'app:icon': 'space-icon-link' + } + } + + try { + await this.apiAuth(); + const link = await this.nodesApi.createNode(destinationId, nodeBody); + await this.addAspects(originalNodeId, ['app:linked']); + return link; + } catch (error) { + this.handleError(`${this.constructor.name} ${this.createFolderLink.name}`, error); + return null; + } + } + // node content async getNodeContent(nodeId: string): Promise { try { @@ -405,7 +449,7 @@ export class NodesApi extends RepoApi { try { await this.apiAuth(); - return await this.nodesApi.lockNode(nodeId, data ); + return await this.nodesApi.lockNode(nodeId, data); } catch (error) { this.handleError(`${this.constructor.name} ${this.lockFile.name}`, error); return null; diff --git a/protractor.conf.js b/protractor.conf.js index 2e7c2adf2..4e74a0823 100755 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -69,6 +69,7 @@ exports.config = { addRemoveContent: [ './e2e/suites/actions/new-menu.test.ts', './e2e/suites/actions/create-folder.test.ts', + './e2e/suites/actions/create-folder-from-template.test.ts', './e2e/suites/actions/create-library.test.ts', './e2e/suites/actions/create-file-from-template.test.ts', './e2e/suites/actions/upload-file.test.ts', diff --git a/src/app/services/node-template.service.spec.ts b/src/app/services/node-template.service.spec.ts index 3e94713e5..7233c6941 100644 --- a/src/app/services/node-template.service.spec.ts +++ b/src/app/services/node-template.service.spec.ts @@ -150,7 +150,7 @@ describe('NodeTemplateService', () => { ).toBe(true); }); - it('should return false if row is a `link` nodeType', () => { + it('should return false if row is a `filelink` nodeType', () => { spyOn( alfrescoApiService.getInstance().nodes, 'getNodeInfo' @@ -174,6 +174,30 @@ describe('NodeTemplateService', () => { ).toBe(false); }); + it('should return false if row is a `folderlink` nodeType', () => { + spyOn( + alfrescoApiService.getInstance().nodes, + 'getNodeInfo' + ).and.returnValue( + of({ + id: 'templates-folder-id', + path: { + elements: [], + name: '/Company Home/Data Dictionary' + } + }) + ); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(fileTemplateConfig); + + expect( + dialog.open['calls'].argsFor(0)[1].data.rowFilter({ + node: { entry: { nodeType: 'app:folderlink' } } + }) + ).toBe(false); + }); + describe('File templates', () => { it('should return false if selected node is not a file', () => { spyOn( From 4a849fead1f871a7bb4cfd055675a5d63d91d545 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Fri, 24 Jan 2020 00:05:20 +0100 Subject: [PATCH 75/96] fix: package.json & package-lock.json to reduce vulnerabilities (#1305) The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-JS-PDFJSDIST-469200 --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9cebfcffb..f86902960 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9903,12 +9903,12 @@ } }, "pdfjs-dist": { - "version": "2.0.489", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.0.489.tgz", - "integrity": "sha1-Y+VLKSqGeQpFRpfrRNQ0e4+/rSc=", + "version": "2.0.943", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.0.943.tgz", + "integrity": "sha512-iLhNcm4XceTHRaSU5o22ZGCm4YpuW5+rf4+BJFH/feBhMQLbCGBry+Jet8Q419QDI4qgARaIQzXuiNrsNWS8Yw==", "requires": { "node-ensure": "^0.0.0", - "worker-loader": "^1.1.1" + "worker-loader": "^2.0.0" } }, "pend": { @@ -13949,9 +13949,9 @@ } }, "worker-loader": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-1.1.1.tgz", - "integrity": "sha512-qJZLVS/jMCBITDzPo/RuweYSIG8VJP5P67mP/71alGyTZRe1LYJFdwLjLalY3T5ifx0bMDRD3OB6P2p1escvlg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-2.0.0.tgz", + "integrity": "sha512-tnvNp4K3KQOpfRnD20m8xltE3eWh89Ye+5oj7wXEEHKac1P4oZ6p9oTj8/8ExqoSBnk9nu5Pr4nKfQ1hn2APJw==", "requires": { "loader-utils": "^1.0.0", "schema-utils": "^0.4.0" diff --git a/package.json b/package.json index b7f6f4594..2b4db479f 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "minimatch-browser": "^1.0.0", "moment": "^2.24.0", "moment-es6": "1.0.0", - "pdfjs-dist": "2.0.489", + "pdfjs-dist": "2.0.943", "rxjs": "^6.5.2", "zone.js": "0.8.29" }, From f0a9b5bf4387e5b4d9b378ded464be8793593739 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Mon, 27 Jan 2020 13:13:37 +0200 Subject: [PATCH 76/96] explicit route string over generic name (#1318) --- src/app/components/layout/app-layout/app-layout.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/layout/app-layout/app-layout.component.ts b/src/app/components/layout/app-layout/app-layout.component.ts index c1d82a8c9..3ebd604fd 100644 --- a/src/app/components/layout/app-layout/app-layout.component.ts +++ b/src/app/components/layout/app-layout/app-layout.component.ts @@ -70,7 +70,7 @@ export class AppLayoutComponent implements OnInit, OnDestroy { direction: Directionality; private minimizeConditions: string[] = ['search']; - private hideConditions: string[] = ['preview']; + private hideConditions: string[] = ['/preview/']; constructor( protected store: Store, From 4c7a95c7e6f8a320bd8f0d35944576babe732181 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Mon, 27 Jan 2020 13:14:46 +0200 Subject: [PATCH 77/96] [ACA-2870] Create from template - extra unnecessary call is performed when opening the dialog (#1321) * hide inputs via configuration * remove styling workaround --- src/app/services/node-template.service.ts | 2 ++ src/app/ui/overrides/adf-style-fixes.theme.scss | 11 ----------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/app/services/node-template.service.ts b/src/app/services/node-template.service.ts index 4dbdf1cc4..8633d5093 100644 --- a/src/app/services/node-template.service.ts +++ b/src/app/services/node-template.service.ts @@ -72,6 +72,8 @@ export class NodeTemplateService { dropdownSiteList: null, breadcrumbTransform: this.transformNode.bind(this), select, + showSearch: false, + showDropdownSiteList: false, isSelectionValid: this.isSelectionValid.bind(this), rowFilter: this.rowFilter.bind(this) }; diff --git a/src/app/ui/overrides/adf-style-fixes.theme.scss b/src/app/ui/overrides/adf-style-fixes.theme.scss index b5279f1c8..52383281a 100644 --- a/src/app/ui/overrides/adf-style-fixes.theme.scss +++ b/src/app/ui/overrides/adf-style-fixes.theme.scss @@ -13,15 +13,4 @@ display: none; } } - - .aca-template-node-selector-dialog { - adf-content-node-selector-panel { - .adf-content-node-selector-content-input { - display: none; - } - .adf-sites-dropdown { - display: none; - } - } - } } From 5102f7d64d29899bf08dc6c66c88df91f347ddc8 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Tue, 28 Jan 2020 09:00:48 +0200 Subject: [PATCH 78/96] [ACA-2704] move Locked By to aca-shared library (#1322) * move component to aca-shared * use aca-shared import * update e2e * fix selector prefix * remove * move node utils to aca-shared * update reference * fix lint * fix linting --- .../locked-by/locked-by.component.scss | 6 ++++ .../locked-by/locked-by.component.ts | 2 +- .../components/locked-by/locked-by.module.ts | 36 +++++++++++++++++++ .../aca-shared/src/lib}/utils/node.utils.ts | 0 projects/aca-shared/src/public-api.ts | 4 +++ .../document-list-custom-components.module.ts | 11 +++--- .../name-column/name-column.component.ts | 2 +- .../comments-tab/comments-tab.component.ts | 3 +- .../metadata-tab/metadata-tab.component.ts | 3 +- src/app/components/page.component.ts | 2 +- src/app/directives/lock-node.directive.ts | 2 +- 11 files changed, 58 insertions(+), 13 deletions(-) rename {src/app/components/dl-custom-components => projects/aca-shared/src/lib/components}/locked-by/locked-by.component.scss (52%) rename {src/app/components/dl-custom-components => projects/aca-shared/src/lib/components}/locked-by/locked-by.component.ts (97%) create mode 100644 projects/aca-shared/src/lib/components/locked-by/locked-by.module.ts rename {src/app => projects/aca-shared/src/lib}/utils/node.utils.ts (100%) diff --git a/src/app/components/dl-custom-components/locked-by/locked-by.component.scss b/projects/aca-shared/src/lib/components/locked-by/locked-by.component.scss similarity index 52% rename from src/app/components/dl-custom-components/locked-by/locked-by.component.scss rename to projects/aca-shared/src/lib/components/locked-by/locked-by.component.scss index 95483bd13..d8af3451a 100644 --- a/src/app/components/dl-custom-components/locked-by/locked-by.component.scss +++ b/projects/aca-shared/src/lib/components/locked-by/locked-by.component.scss @@ -1,4 +1,9 @@ .aca-locked-by { + display: flex; + align-items: center; + padding: 0 10px; + color: var(--theme-text-color, rgba(0, 0, 0, 0.54)); + .locked_by--icon { font-size: 14px; width: 14px; @@ -7,5 +12,6 @@ .locked_by--name { font-size: 12px; + padding: 0 2px; } } diff --git a/src/app/components/dl-custom-components/locked-by/locked-by.component.ts b/projects/aca-shared/src/lib/components/locked-by/locked-by.component.ts similarity index 97% rename from src/app/components/dl-custom-components/locked-by/locked-by.component.ts rename to projects/aca-shared/src/lib/components/locked-by/locked-by.component.ts index 96e88b65e..664dea37c 100644 --- a/src/app/components/dl-custom-components/locked-by/locked-by.component.ts +++ b/projects/aca-shared/src/lib/components/locked-by/locked-by.component.ts @@ -46,7 +46,7 @@ import { NodeEntry } from '@alfresco/js-api'; class: 'aca-locked-by' } }) -export class LockByComponent implements OnInit { +export class LockedByComponent implements OnInit { @Input() context: any; diff --git a/projects/aca-shared/src/lib/components/locked-by/locked-by.module.ts b/projects/aca-shared/src/lib/components/locked-by/locked-by.module.ts new file mode 100644 index 000000000..578023565 --- /dev/null +++ b/projects/aca-shared/src/lib/components/locked-by/locked-by.module.ts @@ -0,0 +1,36 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { NgModule } from '@angular/core'; +import { LockedByComponent } from './locked-by.component'; +import { MatIconModule } from '@angular/material/icon'; +import { CommonModule } from '@angular/common'; + +@NgModule({ + imports: [CommonModule, MatIconModule], + declarations: [LockedByComponent], + exports: [LockedByComponent] +}) +export class LockedByModule {} diff --git a/src/app/utils/node.utils.ts b/projects/aca-shared/src/lib/utils/node.utils.ts similarity index 100% rename from src/app/utils/node.utils.ts rename to projects/aca-shared/src/lib/utils/node.utils.ts diff --git a/projects/aca-shared/src/public-api.ts b/projects/aca-shared/src/public-api.ts index de7d4d9aa..a3a2a55b1 100644 --- a/projects/aca-shared/src/public-api.ts +++ b/projects/aca-shared/src/public-api.ts @@ -28,6 +28,8 @@ export * from './lib/components/page-layout/page-layout-error.component'; export * from './lib/components/page-layout/page-layout-header.component'; export * from './lib/components/page-layout/page-layout.component'; export * from './lib/components/page-layout/page-layout.module'; +export * from './lib/components/locked-by/locked-by.component'; +export * from './lib/components/locked-by/locked-by.module'; export * from './lib/routing/app.routes.strategy'; export * from './lib/routing/shared.guard'; @@ -42,4 +44,6 @@ export * from './lib/components/generic-error/generic-error.module'; export * from './lib/directives/contextmenu/contextmenu.directive'; export * from './lib/directives/contextmenu/contextmenu.module'; +export * from './lib/utils/node.utils'; + export * from './lib/shared.module'; diff --git a/src/app/components/dl-custom-components/document-list-custom-components.module.ts b/src/app/components/dl-custom-components/document-list-custom-components.module.ts index c1c27ce62..12058e56a 100644 --- a/src/app/components/dl-custom-components/document-list-custom-components.module.ts +++ b/src/app/components/dl-custom-components/document-list-custom-components.module.ts @@ -26,7 +26,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { CustomNameColumnComponent } from './name-column/name-column.component'; -import { LockByComponent } from './locked-by/locked-by.component'; +import { LockedByModule } from '@alfresco/aca-shared'; import { ContentModule } from '@alfresco/adf-content-services'; import { MaterialModule } from '../../material.module'; import { CoreModule } from '@alfresco/adf-core'; @@ -36,10 +36,11 @@ import { CoreModule } from '@alfresco/adf-core'; BrowserModule, CoreModule.forChild(), ContentModule.forChild(), - MaterialModule + MaterialModule, + LockedByModule ], - declarations: [CustomNameColumnComponent, LockByComponent], - exports: [CustomNameColumnComponent, LockByComponent], - entryComponents: [CustomNameColumnComponent, LockByComponent] + declarations: [CustomNameColumnComponent], + exports: [CustomNameColumnComponent], + entryComponents: [CustomNameColumnComponent] }) export class DocumentListCustomComponentsModule {} diff --git a/src/app/components/dl-custom-components/name-column/name-column.component.ts b/src/app/components/dl-custom-components/name-column/name-column.component.ts index b26577c25..e23ce9723 100644 --- a/src/app/components/dl-custom-components/name-column/name-column.component.ts +++ b/src/app/components/dl-custom-components/name-column/name-column.component.ts @@ -37,7 +37,7 @@ import { Actions, ofType } from '@ngrx/effects'; import { Subject } from 'rxjs'; import { filter, takeUntil } from 'rxjs/operators'; import { NodeActionTypes } from '@alfresco/aca-shared/store'; -import { isLocked } from '../../../utils/node.utils'; +import { isLocked } from '@alfresco/aca-shared'; @Component({ selector: 'aca-custom-name-column', diff --git a/src/app/components/info-drawer/comments-tab/comments-tab.component.ts b/src/app/components/info-drawer/comments-tab/comments-tab.component.ts index d8c4ee8ce..4a42d4f8f 100644 --- a/src/app/components/info-drawer/comments-tab/comments-tab.component.ts +++ b/src/app/components/info-drawer/comments-tab/comments-tab.component.ts @@ -25,8 +25,7 @@ import { Component, Input } from '@angular/core'; import { MinimalNodeEntryEntity } from '@alfresco/js-api'; -import { NodePermissionService } from '@alfresco/aca-shared'; -import { isLocked } from '../../../utils/node.utils'; +import { NodePermissionService, isLocked } from '@alfresco/aca-shared'; @Component({ selector: 'app-comments-tab', diff --git a/src/app/components/info-drawer/metadata-tab/metadata-tab.component.ts b/src/app/components/info-drawer/metadata-tab/metadata-tab.component.ts index 190e2242e..33fc05e35 100644 --- a/src/app/components/info-drawer/metadata-tab/metadata-tab.component.ts +++ b/src/app/components/info-drawer/metadata-tab/metadata-tab.component.ts @@ -31,11 +31,10 @@ import { OnDestroy } from '@angular/core'; import { MinimalNodeEntryEntity } from '@alfresco/js-api'; -import { NodePermissionService } from '@alfresco/aca-shared'; +import { NodePermissionService, isLocked } from '@alfresco/aca-shared'; import { AppStore, infoDrawerMetadataAspect } from '@alfresco/aca-shared/store'; import { AppExtensionService } from '../../../extensions/extension.service'; import { AppConfigService, NotificationService } from '@alfresco/adf-core'; -import { isLocked } from '../../../utils/node.utils'; import { Observable, Subject } from 'rxjs'; import { Store } from '@ngrx/store'; import { ContentMetadataService } from '@alfresco/adf-content-services'; diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index 9f0765f9a..ed0e259d2 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -47,7 +47,7 @@ import { ViewNodeExtras, SetSelectedNodesAction } from '@alfresco/aca-shared/store'; -import { isLocked, isLibrary } from '../utils/node.utils'; +import { isLocked, isLibrary } from '@alfresco/aca-shared'; export abstract class PageComponent implements OnInit, OnDestroy { onDestroy$: Subject = new Subject(); diff --git a/src/app/directives/lock-node.directive.ts b/src/app/directives/lock-node.directive.ts index 6953a7c35..15e701e5a 100644 --- a/src/app/directives/lock-node.directive.ts +++ b/src/app/directives/lock-node.directive.ts @@ -32,7 +32,7 @@ import { } from '@angular/core'; import { NodeEntry, NodeBodyLock, SharedLinkEntry } from '@alfresco/js-api'; import { AlfrescoApiService } from '@alfresco/adf-core'; -import { isLocked } from '../utils/node.utils'; +import { isLocked } from '@alfresco/aca-shared'; @Directive({ selector: '[acaLockNode]', From 874392159d039efa7048cbd33e61ddb846b82964 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 31 Jan 2020 06:53:55 +0200 Subject: [PATCH 79/96] resolve node id for different nodes (#1327) --- .../src/lib/aos-extension.service.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/projects/adf-office-services-ext/src/lib/aos-extension.service.ts b/projects/adf-office-services-ext/src/lib/aos-extension.service.ts index 02ee9c2c5..dbc75f64d 100644 --- a/projects/adf-office-services-ext/src/lib/aos-extension.service.ts +++ b/projects/adf-office-services-ext/src/lib/aos-extension.service.ts @@ -44,7 +44,7 @@ export class AosEditOnlineService { ) {} onActionEditOnlineAos(node: MinimalNodeEntryEntity): void { - if (node && node.isFile && node.properties) { + if (node && this.isFile(node) && node.properties) { if (node.isLocked) { // const checkedOut = node.aspectNames.find( // (aspect: string) => aspect === 'cm:checkedOut' @@ -92,9 +92,9 @@ export class AosEditOnlineService { private triggerEditOnlineAos(node: MinimalNodeEntryEntity): void { const aosHost = this.appConfigService.get('aosHost'); - const url = `${aosHost}/_aos_nodeid/${node.id}/${encodeURIComponent( - node.name - )}`; + const url = `${aosHost}/_aos_nodeid/${this.getNodeId( + node + )}/${encodeURIComponent(node.name)}`; const fileExtension = getFileExtension(node.name); const protocolHandler = this.getProtocolForFileExtension(fileExtension); @@ -134,4 +134,14 @@ export class AosEditOnlineService { } }, 500); } + + private isFile(node: MinimalNodeEntryEntity): boolean { + const implicitFile = (node).nodeId || (node).guid; + + return !!implicitFile || node.isFile; + } + + private getNodeId(node: MinimalNodeEntryEntity): string { + return (node).nodeId || (node).guid || node.id; + } } From 2ce7eb7c7dd134632ab82ba2506fbfbdbeba1996 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Sat, 1 Feb 2020 07:58:51 +0200 Subject: [PATCH 80/96] set info drawer state based on location --- src/app/components/page.component.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index ed0e259d2..3c76019d0 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -32,7 +32,7 @@ import { OnDestroy, OnInit, ViewChild } from '@angular/core'; import { Store } from '@ngrx/store'; import { MinimalNodeEntity, MinimalNodeEntryEntity } from '@alfresco/js-api'; import { Observable, Subject, Subscription } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { takeUntil, map } from 'rxjs/operators'; import { AppExtensionService } from '../extensions/extension.service'; import { ContentManagementService } from '../services/content-management.service'; import { @@ -76,7 +76,12 @@ export abstract class PageComponent implements OnInit, OnDestroy { ngOnInit() { this.sharedPreviewUrl$ = this.store.select(getSharedUrl); - this.infoDrawerOpened$ = this.store.select(isInfoDrawerOpened); + this.infoDrawerOpened$ = this.store.select(isInfoDrawerOpened).pipe( + map(infoDrawerState => { + return !this.isOutletPreviewUrl() && infoDrawerState; + }) + ); + this.documentDisplayMode$ = this.store.select(getDocumentDisplayMode); this.store From 1389c0bf5fd737892e2d142b0ae9267d3b1d1c08 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Sat, 1 Feb 2020 07:59:53 +0200 Subject: [PATCH 81/96] update tests --- src/app/components/page.component.spec.ts | 86 ++++++++++++++++++++--- 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/src/app/components/page.component.spec.ts b/src/app/components/page.component.spec.ts index 39cb70d2e..fd690f498 100644 --- a/src/app/components/page.component.spec.ts +++ b/src/app/components/page.component.spec.ts @@ -23,30 +23,55 @@ * along with Alfresco. If not, see . */ +import { TestBed, ComponentFixture } from '@angular/core/testing'; import { PageComponent } from './page.component'; import { ReloadDocumentListAction, - SetSelectedNodesAction + SetSelectedNodesAction, + SetInfoDrawerStateAction, + AppState, + AppStore } from '@alfresco/aca-shared/store'; import { MinimalNodeEntity } from '@alfresco/js-api'; +import { ContentManagementService } from '../services/content-management.service'; +import { EffectsModule } from '@ngrx/effects'; +import { ViewerEffects } from '../store/effects'; +import { Store } from '@ngrx/store'; +import { AppExtensionService } from '../extensions/extension.service'; +import { AppTestingModule } from '../testing/app-testing.module'; +import { Component } from '@angular/core'; -class TestClass extends PageComponent { +@Component({ + selector: 'aca-test', + template: '' +}) +class TestComponent extends PageComponent { node: any; - constructor(store) { - super(store, null, null); + constructor( + store: Store, + extensions: AppExtensionService, + content: ContentManagementService + ) { + super(store, extensions, content); } } describe('PageComponent', () => { - let component: TestClass; - const store = { - dispatch: jasmine.createSpy('dispatch'), - select: jasmine.createSpy('select') - }; + let component: TestComponent; + let store: Store; + let fixture: ComponentFixture; beforeEach(() => { - component = new TestClass(store); + TestBed.configureTestingModule({ + imports: [AppTestingModule, EffectsModule.forRoot([ViewerEffects])], + declarations: [TestComponent], + providers: [ContentManagementService, AppExtensionService] + }); + + store = TestBed.get(Store); + fixture = TestBed.createComponent(TestComponent); + component = fixture.componentInstance; }); describe('getParentNodeId()', () => { @@ -63,6 +88,42 @@ describe('PageComponent', () => { }); }); + describe('Info Drawer state', () => { + const locationHref = location.href; + + afterEach(() => { + window.history.pushState({}, null, locationHref); + }); + + it('should open info drawer on action event', done => { + window.history.pushState({}, null, `${locationHref}#test`); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + component.infoDrawerOpened$.subscribe(state => { + expect(state).toBe(true); + done(); + }); + }); + + store.dispatch(new SetInfoDrawerStateAction(true)); + }); + + it('should not open info drawer if viewer outlet is active', done => { + window.history.pushState({}, null, `${locationHref}#test(viewer:view)`); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + component.infoDrawerOpened$.subscribe(state => { + expect(state).toBe(false); + done(); + }); + }); + + store.dispatch(new SetInfoDrawerStateAction(true)); + }); + }); + describe('Reload', () => { const locationHref = location.href; @@ -72,11 +133,15 @@ describe('PageComponent', () => { it('should not reload if url contains viewer outlet', () => { window.history.pushState({}, null, `${locationHref}#test(viewer:view)`); + spyOn(store, 'dispatch'); + component.reload(); expect(store.dispatch).not.toHaveBeenCalled(); }); it('should reload if url does not contain viewer outlet', () => { + spyOn(store, 'dispatch'); + component.reload(); expect(store.dispatch).toHaveBeenCalledWith( new ReloadDocumentListAction() @@ -89,6 +154,7 @@ describe('PageComponent', () => { id: 'node-id' } } as MinimalNodeEntity; + spyOn(store, 'dispatch'); component.reload(node); expect(store.dispatch['calls'].mostRecent().args[0]).toEqual( From dc63b58cd697a5523d1c0be929ec4bb50078dd37 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Wed, 5 Feb 2020 11:51:21 +0200 Subject: [PATCH 82/96] upgrade puppeteer to use the latest chrome (#1330) --- package-lock.json | 63 +++++++++++++++++++++++++++-------------------- package.json | 2 +- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index f86902960..39d095178 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1249,6 +1249,12 @@ "@types/jasmine": "*" } }, + "@types/mime-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz", + "integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=", + "dev": true + }, "@types/node": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-9.3.0.tgz", @@ -10358,15 +10364,17 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "puppeteer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-2.0.0.tgz", - "integrity": "sha512-t3MmTWzQxPRP71teU6l0jX47PHXlc4Z52sQv4LJQSZLq1ttkKS2yGM3gaI57uQwZkNaoGd0+HPPMELZkcyhlqA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-2.1.0.tgz", + "integrity": "sha512-PC4oKMtwAElo8YtS/cYnk2/dew/3TonsGKKzjpFLWwkhBCteFsOZCVOXTt2QlP6w53mH0YsJE+fPLPzOW+DCug==", "dev": true, "requires": { + "@types/mime-types": "^2.1.0", "debug": "^4.1.0", "extract-zip": "^1.6.6", - "https-proxy-agent": "^3.0.0", + "https-proxy-agent": "^4.0.0", "mime": "^2.0.3", + "mime-types": "^2.1.25", "progress": "^2.0.1", "proxy-from-env": "^1.0.0", "rimraf": "^2.6.1", @@ -10374,13 +10382,10 @@ }, "dependencies": { "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "requires": { - "es6-promisify": "^5.0.0" - } + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", + "dev": true }, "debug": { "version": "4.1.1", @@ -10392,24 +10397,13 @@ } }, "https-proxy-agent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", - "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", "dev": true, "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "agent-base": "5", + "debug": "4" } }, "mime": { @@ -10418,6 +10412,21 @@ "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", "dev": true }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "dev": true, + "requires": { + "mime-db": "1.43.0" + } + }, "ws": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", diff --git a/package.json b/package.json index 2b4db479f..59101789c 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "prettier": "^1.17.1", "protractor": "5.4.2", "protractor-screenshoter-plugin": "0.10.3", - "puppeteer": "^2.0.0", + "puppeteer": "^2.1.0", "rxjs-tslint-rules": "^4.19.0", "selenium-webdriver": "4.0.0-alpha.1", "ts-node": "^8.0.3", From 1e3c21fca22fa0c872049efa94ae4a5bc2565407 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 6 Feb 2020 07:03:25 +0200 Subject: [PATCH 83/96] level 2 heading --- .../permission-dialog/node-permissions.dialog.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/components/permissions/permission-dialog/node-permissions.dialog.html b/src/app/components/permissions/permission-dialog/node-permissions.dialog.html index dcd7a180c..c4ad08e2e 100644 --- a/src/app/components/permissions/permission-dialog/node-permissions.dialog.html +++ b/src/app/components/permissions/permission-dialog/node-permissions.dialog.html @@ -1,4 +1,6 @@ -
{{'PERMISSIONS.DIALOG.TITLE' | translate}}
+
+ {{'PERMISSIONS.DIALOG.TITLE' | translate}} +
From d4f04323b39fc2522254c4a31a32ed4806e7de2d Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 6 Feb 2020 15:31:27 +0200 Subject: [PATCH 84/96] ADF 3.7.0-bab49 (#1324) * adf 3.7.0-1754 * fix header name selector * fix more / less state * click correct button * check correct button * remove Thumbnail column from headers list * 3.7.0-0256a update * remove Thumbnail. from headers list * remove Thumbnail * header cell value selector * adf 3.7.0-bab49 * change selector after accessibility fixes Co-authored-by: Adina Parpalita --- e2e/components/data-table/data-table.ts | 10 ++++---- .../extensions/ext-document-list.test.ts | 4 ---- .../file-folder-properties.test.ts | 22 ++++++++--------- e2e/suites/list-views/favorites.test.ts | 2 +- e2e/suites/list-views/file-libraries.test.ts | 4 ++-- e2e/suites/list-views/personal-files.test.ts | 2 +- e2e/suites/list-views/recent-files.test.ts | 2 +- e2e/suites/list-views/shared-files.test.ts | 2 +- e2e/suites/list-views/trash.test.ts | 4 ++-- .../search/search-results-libraries.test.ts | 2 +- package-lock.json | 24 +++++++++---------- package.json | 8 +++---- 12 files changed, 41 insertions(+), 45 deletions(-) diff --git a/e2e/components/data-table/data-table.ts b/e2e/components/data-table/data-table.ts index f04198d34..57ea8cf7a 100755 --- a/e2e/components/data-table/data-table.ts +++ b/e2e/components/data-table/data-table.ts @@ -34,11 +34,11 @@ export class DataTable extends Component { root: 'adf-datatable', head: '.adf-datatable-header', - columnHeader: '.adf-datatable-row .adf-datatable-cell-header', + columnHeader: '.adf-datatable-row .adf-datatable-cell-header .adf-datatable-cell-value', sortedColumnHeader: ` - .adf-datatable__header--sorted-asc, - .adf-datatable__header--sorted-desc - `, + .adf-datatable__header--sorted-asc .adf-datatable-cell-value, + .adf-datatable__header--sorted-desc .adf-datatable-cell-value + `, body: '.adf-datatable-body', row: '.adf-datatable-row[role]', @@ -125,7 +125,7 @@ export class DataTable extends Component { } async getSortingOrder(): Promise { - const str = await this.getSortedColumnHeader().getAttribute('class'); + const str = await this.getSortedColumnHeader().element(by.xpath('..')).getAttribute('class'); if (str.includes('asc')) { return 'asc'; } diff --git a/e2e/suites/extensions/ext-document-list.test.ts b/e2e/suites/extensions/ext-document-list.test.ts index 410fba5b8..adeaa446b 100644 --- a/e2e/suites/extensions/ext-document-list.test.ts +++ b/e2e/suites/extensions/ext-document-list.test.ts @@ -38,10 +38,6 @@ describe('Extensions - DocumentList presets', () => { id: 'app.files.name', label: 'Name' }, - { - id: 'app.files.thumbnail', - label: 'Thumbnail' - }, { id: 'app.files.size', label: 'Size', diff --git a/e2e/suites/info-drawer/file-folder-properties.test.ts b/e2e/suites/info-drawer/file-folder-properties.test.ts index 62c9dc136..161ccdea8 100755 --- a/e2e/suites/info-drawer/file-folder-properties.test.ts +++ b/e2e/suites/info-drawer/file-folder-properties.test.ts @@ -140,7 +140,7 @@ describe('File / Folder properties', () => { expect(await propertiesTab.getVisiblePropertiesLabels()).toEqual(expectedPropLabels, 'Incorrect properties displayed'); expect(await propertiesTab.getVisiblePropertiesValues()).toEqual(expectedPropValues, 'Incorrect properties values'); expect(await propertiesTab.isEditPropertiesButtonEnabled()).toBe(true, 'Edit button not enabled'); - expect(await propertiesTab.isLessInfoButtonEnabled()).toBe(true, 'Less information button not enabled'); + expect(await propertiesTab.isMoreInfoButtonEnabled()).toBe(true, 'More information button not enabled'); }); it('Folder properties - [C307106]', async () => { @@ -174,7 +174,7 @@ describe('File / Folder properties', () => { expect(await propertiesTab.getVisiblePropertiesLabels()).toEqual(expectedPropLabels, 'Incorrect properties displayed'); expect(await propertiesTab.getVisiblePropertiesValues()).toEqual(expectedPropValues, 'Incorrect properties values'); expect(await propertiesTab.isEditPropertiesButtonEnabled()).toBe(true, 'Edit button not enabled'); - expect(await propertiesTab.isLessInfoButtonEnabled()).toBe(true, 'Less information button not enabled'); + expect(await propertiesTab.isMoreInfoButtonEnabled()).toBe(true, 'More information button not enabled'); }); it('Less / More information buttons - [C269004]', async () => { @@ -182,19 +182,19 @@ describe('File / Folder properties', () => { await page.toolbar.clickViewDetails(); await infoDrawer.waitForInfoDrawerToOpen(); - expect(await propertiesTab.isLessInfoButtonEnabled()).toBe(true, 'Less information button not enabled'); - expect(await propertiesTab.isPropertiesListExpanded()).toBe(true, 'Properties list not expanded'); - - await propertiesTab.clickLessInformationButton(); - - expect(await propertiesTab.isLessInfoButtonDisplayed()).toBe(false, 'Less information button displayed'); expect(await propertiesTab.isMoreInfoButtonEnabled()).toBe(true, 'More information button not enabled'); - expect(await propertiesTab.isPropertiesListExpanded()).toBe(false, 'Properties list expanded'); + expect(await propertiesTab.isPropertiesListExpanded()).toBe(true, 'Properties list not expanded'); await propertiesTab.clickMoreInformationButton(); expect(await propertiesTab.isMoreInfoButtonDisplayed()).toBe(false, 'More information button displayed'); expect(await propertiesTab.isLessInfoButtonEnabled()).toBe(true, 'Less information button not enabled'); + expect(await propertiesTab.isPropertiesListExpanded()).toBe(false, 'Properties list expanded'); + + await propertiesTab.clickLessInformationButton(); + + expect(await propertiesTab.isMoreInfoButtonDisplayed()).toBe(true, 'More information button not displayed'); + expect(await propertiesTab.isLessInfoButtonEnabled()).toBe(false, 'Less information button enabled'); expect(await propertiesTab.isPropertiesListExpanded()).toBe(true, 'Properties list not expanded'); }); @@ -234,7 +234,7 @@ describe('File / Folder properties', () => { await page.toolbar.clickViewDetails(); await infoDrawer.waitForInfoDrawerToOpen(); - await propertiesTab.clickLessInformationButton(); + await propertiesTab.clickMoreInformationButton(); await propertiesTab.clickImagePropertiesPanel(); await propertiesTab.waitForImagePropertiesPanelToExpand(); @@ -242,7 +242,7 @@ describe('File / Folder properties', () => { expect(await propertiesTab.getVisiblePropertiesLabels()).toEqual(expectedPropLabels, 'Incorrect properties displayed'); expect(await propertiesTab.getVisiblePropertiesValues()).toEqual(expectedPropValues, 'Incorrect properties values'); expect(await propertiesTab.isEditPropertiesButtonEnabled()).toBe(true, 'Edit button not enabled'); - expect(await propertiesTab.isMoreInfoButtonEnabled()).toBe(true, 'More information button not enabled'); + expect(await propertiesTab.isLessInfoButtonEnabled()).toBe(true, 'Less information button not enabled'); }); }); diff --git a/e2e/suites/list-views/favorites.test.ts b/e2e/suites/list-views/favorites.test.ts index 4fc408b04..f071eb3eb 100755 --- a/e2e/suites/list-views/favorites.test.ts +++ b/e2e/suites/list-views/favorites.test.ts @@ -88,7 +88,7 @@ describe('Favorites', () => { }); it('has the correct columns - [C280482]', async () => { - const expectedColumns = [ 'Thumbnail', 'Name', 'Location', 'Size', 'Modified', 'Modified by' ]; + const expectedColumns = [ 'Name', 'Location', 'Size', 'Modified', 'Modified by' ]; const actualColumns = await dataTable.getColumnHeadersText(); expect(actualColumns).toEqual(expectedColumns); diff --git a/e2e/suites/list-views/file-libraries.test.ts b/e2e/suites/list-views/file-libraries.test.ts index 753b34e36..3c5713ed4 100755 --- a/e2e/suites/list-views/file-libraries.test.ts +++ b/e2e/suites/list-views/file-libraries.test.ts @@ -103,7 +103,7 @@ describe('File Libraries', () => { }); it('has the correct columns - [C217095]', async () => { - const expectedColumns = [ 'Thumbnail', 'Name', 'My Role', 'Visibility' ]; + const expectedColumns = [ 'Name', 'My Role', 'Visibility' ]; const actualColumns = await dataTable.getColumnHeadersText(); expect(actualColumns).toEqual(expectedColumns); @@ -172,7 +172,7 @@ describe('File Libraries', () => { }); it('has the correct columns - [C289893]', async () => { - const expectedColumns = [ 'Thumbnail', 'Name', 'My Role', 'Visibility' ]; + const expectedColumns = [ 'Name', 'My Role', 'Visibility' ]; const actualColumns = await dataTable.getColumnHeadersText(); expect(actualColumns).toEqual(expectedColumns); diff --git a/e2e/suites/list-views/personal-files.test.ts b/e2e/suites/list-views/personal-files.test.ts index c6303cdc9..5f8072e45 100755 --- a/e2e/suites/list-views/personal-files.test.ts +++ b/e2e/suites/list-views/personal-files.test.ts @@ -94,7 +94,7 @@ describe('Personal Files', () => { }); it('has the correct columns - [C217142]', async () => { - const expectedColumns = [ 'Thumbnail', 'Name', 'Size', 'Modified', 'Modified by' ]; + const expectedColumns = [ 'Name', 'Size', 'Modified', 'Modified by' ]; const actualColumns = await dataTable.getColumnHeadersText(); expect(actualColumns).toEqual(expectedColumns); diff --git a/e2e/suites/list-views/recent-files.test.ts b/e2e/suites/list-views/recent-files.test.ts index 7bb581644..37a1ffc69 100755 --- a/e2e/suites/list-views/recent-files.test.ts +++ b/e2e/suites/list-views/recent-files.test.ts @@ -81,7 +81,7 @@ describe('Recent Files', () => { }); it('has the correct columns - [C213168]', async () => { - const expectedColumns = [ 'Thumbnail', 'Name', 'Location', 'Size', 'Modified' ]; + const expectedColumns = [ 'Name', 'Location', 'Size', 'Modified' ]; const actualColumns = await dataTable.getColumnHeadersText(); expect(actualColumns).toEqual(expectedColumns); diff --git a/e2e/suites/list-views/shared-files.test.ts b/e2e/suites/list-views/shared-files.test.ts index df6108f9c..909a45fa5 100755 --- a/e2e/suites/list-views/shared-files.test.ts +++ b/e2e/suites/list-views/shared-files.test.ts @@ -87,7 +87,7 @@ describe('Shared Files', () => { }); it('has the correct columns - [C213113]', async () => { - const expectedColumns = [ 'Thumbnail', 'Name', 'Location', 'Size', 'Modified', 'Modified by', 'Shared by' ]; + const expectedColumns = [ 'Name', 'Location', 'Size', 'Modified', 'Modified by', 'Shared by' ]; const actualColumns = await dataTable.getColumnHeadersText(); expect(actualColumns).toEqual(expectedColumns); diff --git a/e2e/suites/list-views/trash.test.ts b/e2e/suites/list-views/trash.test.ts index a11d64b32..890afd8a9 100755 --- a/e2e/suites/list-views/trash.test.ts +++ b/e2e/suites/list-views/trash.test.ts @@ -99,7 +99,7 @@ describe('Trash', () => { }); it('has the correct columns - [C213217]', async () => { - const expectedColumns = [ 'Thumbnail', 'Name', 'Location', 'Size', 'Deleted', 'Deleted by' ]; + const expectedColumns = [ 'Name', 'Location', 'Size', 'Deleted', 'Deleted by' ]; const actualColumns = await dataTable.getColumnHeadersText(); expect(actualColumns).toEqual(expectedColumns); @@ -128,7 +128,7 @@ describe('Trash', () => { }); it('has the correct columns - [C280494]', async () => { - const expectedColumns = [ 'Thumbnail', 'Name', 'Location', 'Size', 'Deleted']; + const expectedColumns = [ 'Name', 'Location', 'Size', 'Deleted']; const actualColumns = await dataTable.getColumnHeadersText(); expect(actualColumns).toEqual(expectedColumns); diff --git a/e2e/suites/search/search-results-libraries.test.ts b/e2e/suites/search/search-results-libraries.test.ts index 652e08849..6316009b2 100644 --- a/e2e/suites/search/search-results-libraries.test.ts +++ b/e2e/suites/search/search-results-libraries.test.ts @@ -172,7 +172,7 @@ describe('Search results - libraries', () => { await searchInput.searchFor(site1.name); await dataTable.waitForBody(); - const expectedColumns = [ 'Thumbnail', 'Name', 'My Role', 'Visibility' ]; + const expectedColumns = [ 'Name', 'My Role', 'Visibility' ]; const actualColumns = await dataTable.getColumnHeadersText(); expect(actualColumns).toEqual(expectedColumns); diff --git a/package-lock.json b/package-lock.json index 39d095178..76680f0ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,33 +5,33 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "3.7.0-deb2a0082f254b19d4980d89095a3535976fa606", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-3.7.0-deb2a0082f254b19d4980d89095a3535976fa606.tgz", - "integrity": "sha512-rixkyhLSv+xJdRMKjdiePOif/CftRCdbpH157F+teR2CoBN7CQbJG3d2HpS0r16sB5zMACiv0UFre8Z6Z3mA3w==", + "version": "3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950.tgz", + "integrity": "sha512-VuCu4NBFBQXjoFlXP7csj0Y6AxmNgbcGhbXe+2wVEZHKBMaoyU41ys0CHbSnPxb1LdeEOdsTR4zuqiOkY4DQPg==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/adf-core": { - "version": "3.7.0-deb2a0082f254b19d4980d89095a3535976fa606", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-3.7.0-deb2a0082f254b19d4980d89095a3535976fa606.tgz", - "integrity": "sha512-cYNRFeqLcc5DPVqlunKZjQ+yygm8JuXqk/B0vY1B8bNUukrbGB1c08ePiBa5phXuUqw6ivUq3DSAcOmayS6saw==", + "version": "3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950.tgz", + "integrity": "sha512-Xu0wxe4I3FxYVrFkAO27qYiQ07AJLBm0cL6AIDbiuQzTmUAGBBoXuc4ePCdajFDOmDgrty2fcoxpUNuNH3PYzg==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/adf-extensions": { - "version": "3.7.0-deb2a0082f254b19d4980d89095a3535976fa606", - "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-3.7.0-deb2a0082f254b19d4980d89095a3535976fa606.tgz", - "integrity": "sha512-BcNNRCD0odNkMfAiU4sCUz5h4ZUWy8wsKVQvAaq/3X1ekqDp1+p/iSPHqjWWbCUX8ptQ+4haoEep5+KP7LgL9g==", + "version": "3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950", + "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950.tgz", + "integrity": "sha512-X88LSdwP7MeaATGiAMC0JwaHzbsIaUKHaaoKj9QqxKfOmhyFymZMiEHgDNpJt85ecRm5mv4tf0REz0D3f1IF3Q==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/js-api": { - "version": "3.7.0-2d9ba39ba3d09965bf711c615b1985a06a97b195", - "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-3.7.0-2d9ba39ba3d09965bf711c615b1985a06a97b195.tgz", - "integrity": "sha512-wupSj6MzhjvhqrD/s95EC0CgCOiLbD6LD45xnafpZcSVAXV6ltJCaiGI8WkF+Tbx3EuICZzTKNfygXpIjlY82w==", + "version": "3.7.0-6da900b2340825533ad43e86422faccc3d2195d1", + "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-3.7.0-6da900b2340825533ad43e86422faccc3d2195d1.tgz", + "integrity": "sha512-K8vjqek1YFyUCHzKnVwowh4EcODwnbGBhH5eDh/crUo5AsAu7JzSWf7U6VBOPWKgZSKLFAN8GLa3EeQdyAqDsQ==", "requires": { "event-emitter": "^0.3.5", "minimatch": "3.0.4", diff --git a/package.json b/package.json index 59101789c..a60c632e6 100644 --- a/package.json +++ b/package.json @@ -40,10 +40,10 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "3.7.0-deb2a0082f254b19d4980d89095a3535976fa606", - "@alfresco/adf-core": "3.7.0-deb2a0082f254b19d4980d89095a3535976fa606", - "@alfresco/adf-extensions": "3.7.0-deb2a0082f254b19d4980d89095a3535976fa606", - "@alfresco/js-api": "3.7.0-2d9ba39ba3d09965bf711c615b1985a06a97b195", + "@alfresco/adf-content-services": "3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950", + "@alfresco/adf-core": "3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950", + "@alfresco/adf-extensions": "3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950", + "@alfresco/js-api": "3.7.0-6da900b2340825533ad43e86422faccc3d2195d1", "@angular/animations": "7.2.15", "@angular/cdk": "^7.3.7", "@angular/common": "7.2.15", From 38a2edf6f1fd96b187eb489a9a650de988a05d01 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 6 Feb 2020 15:32:49 +0100 Subject: [PATCH 85/96] Forgot commit authguard change for aca-2755 --- src/app/app.routes.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 8f764e0ad..a9a3ae65a 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -35,7 +35,7 @@ import { AppSharedRuleGuard, GenericErrorComponent } from '@alfresco/aca-shared'; -import { AuthGuardEcm, AuthGuard } from '@alfresco/adf-core'; +import { AuthGuardEcm } from '@alfresco/adf-core'; import { FavoritesComponent } from './components/favorites/favorites.component'; import { RecentFilesComponent } from './components/recent-files/recent-files.component'; import { SharedFilesComponent } from './components/shared-files/shared-files.component'; @@ -76,7 +76,7 @@ export const APP_ROUTES: Routes = [ { path: '', component: AppLayoutComponent, - canActivate: [AuthGuard], + canActivate: [AuthGuardEcm], children: [ { path: '', From 3a56835a65ae36957cd2986375a76465caf4e16a Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Fri, 7 Feb 2020 11:02:36 +0200 Subject: [PATCH 86/96] upgrade to ADF 3.7.0 --- package-lock.json | 24 ++++++++++++------------ package.json | 8 ++++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 76680f0ce..3bcb32138 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,33 +5,33 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950.tgz", - "integrity": "sha512-VuCu4NBFBQXjoFlXP7csj0Y6AxmNgbcGhbXe+2wVEZHKBMaoyU41ys0CHbSnPxb1LdeEOdsTR4zuqiOkY4DQPg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-3.7.0.tgz", + "integrity": "sha512-AMFck7pdrYGL0I4AhbFV4RBNE5I273Q9/99m4tNcpctAQJVVo/ZeZ1dpgibkrz2LL9Bd+WwNsqWMUTf0e0ZIMQ==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/adf-core": { - "version": "3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950.tgz", - "integrity": "sha512-Xu0wxe4I3FxYVrFkAO27qYiQ07AJLBm0cL6AIDbiuQzTmUAGBBoXuc4ePCdajFDOmDgrty2fcoxpUNuNH3PYzg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-3.7.0.tgz", + "integrity": "sha512-A5z85OkZSG6CdH4KUbhDFchZp0mQderSjOPhjGw6EI409DpbZy4UcNf0dsocAMTIdDXh0s4ubmcWN+5NqZqQpw==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/adf-extensions": { - "version": "3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950", - "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950.tgz", - "integrity": "sha512-X88LSdwP7MeaATGiAMC0JwaHzbsIaUKHaaoKj9QqxKfOmhyFymZMiEHgDNpJt85ecRm5mv4tf0REz0D3f1IF3Q==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-3.7.0.tgz", + "integrity": "sha512-tYM6ddTKceTRemKW2nHiiHJJFH1a+U7l4LTdqNoRyTM66J4s5HDm/G+zsQBy1k7ybPTGC56d1mWA0jqq+gnEEQ==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/js-api": { - "version": "3.7.0-6da900b2340825533ad43e86422faccc3d2195d1", - "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-3.7.0-6da900b2340825533ad43e86422faccc3d2195d1.tgz", - "integrity": "sha512-K8vjqek1YFyUCHzKnVwowh4EcODwnbGBhH5eDh/crUo5AsAu7JzSWf7U6VBOPWKgZSKLFAN8GLa3EeQdyAqDsQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-3.7.0.tgz", + "integrity": "sha512-5bAk+RVC/VkmYHTI+LQVrOC2xqE308ns/Z4FF+FYUikhhqgB1OJIyt3vPSVP4hNSaxFsvan1owmVXMVqqCCgeA==", "requires": { "event-emitter": "^0.3.5", "minimatch": "3.0.4", diff --git a/package.json b/package.json index a60c632e6..d1ffe6dc4 100644 --- a/package.json +++ b/package.json @@ -40,10 +40,10 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950", - "@alfresco/adf-core": "3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950", - "@alfresco/adf-extensions": "3.7.0-bab490663216664f7d5f4cc0bff7726fca7f9950", - "@alfresco/js-api": "3.7.0-6da900b2340825533ad43e86422faccc3d2195d1", + "@alfresco/adf-content-services": "3.7.0", + "@alfresco/adf-core": "3.7.0", + "@alfresco/adf-extensions": "3.7.0", + "@alfresco/js-api": "3.7.0", "@angular/animations": "7.2.15", "@angular/cdk": "^7.3.7", "@angular/common": "7.2.15", From fe52b0f468607b767804dddef0c39bcf249abc35 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Mon, 10 Feb 2020 14:14:21 +0200 Subject: [PATCH 87/96] [ACA-2840] automate tests for the destination picker (#1332) * automate tests for the destination picker * fix spellcheck --- e2e/components/data-table/data-table.ts | 1 - .../dialog/content-node-selector-dialog.ts | 157 +++++++++ e2e/components/dialog/copy-move-dialog.ts | 126 ------- .../actions/{ => copy-move}/copy.test.ts | 18 +- .../destination-picker-dialog.test.ts | 332 ++++++++++++++++++ .../actions/{ => copy-move}/move.test.ts | 26 +- e2e/suites/viewer/viewer-actions.test.ts | 4 +- protractor.conf.js | 2 +- 8 files changed, 514 insertions(+), 152 deletions(-) create mode 100755 e2e/components/dialog/content-node-selector-dialog.ts delete mode 100755 e2e/components/dialog/copy-move-dialog.ts rename e2e/suites/actions/{ => copy-move}/copy.test.ts (98%) create mode 100755 e2e/suites/actions/copy-move/destination-picker-dialog.test.ts rename e2e/suites/actions/{ => copy-move}/move.test.ts (97%) diff --git a/e2e/components/data-table/data-table.ts b/e2e/components/data-table/data-table.ts index 57ea8cf7a..d383f075d 100755 --- a/e2e/components/data-table/data-table.ts +++ b/e2e/components/data-table/data-table.ts @@ -72,7 +72,6 @@ export class DataTable extends Component { emptyFolderDragAndDrop: ElementFinder = this.component.element(by.css(DataTable.selectors.emptyFolderDragAndDrop)); emptyListTitle: ElementFinder = this.component.element(by.css(DataTable.selectors.emptyListTitle)); emptyListSubtitle: ElementFinder = this.component.element(by.css(DataTable.selectors.emptyListSubtitle)); - emptyListContainerText: ElementFinder = this.component.element(by.css(DataTable.selectors.emptyListContainer)); emptySearchText: ElementFinder = this.component.element(by.css(DataTable.selectors.emptySearchText)); diff --git a/e2e/components/dialog/content-node-selector-dialog.ts b/e2e/components/dialog/content-node-selector-dialog.ts new file mode 100755 index 000000000..0bac88b04 --- /dev/null +++ b/e2e/components/dialog/content-node-selector-dialog.ts @@ -0,0 +1,157 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, by, browser, ExpectedConditions as EC, protractor } from 'protractor'; +import { BROWSER_WAIT_TIMEOUT } from '../../configs'; +import { Component } from '../component'; +import { Utils } from '../../utilities/utils'; +import { DropDownBreadcrumb } from '../breadcrumb/dropdown-breadcrumb'; +import { DataTable } from '../data-table/data-table'; + +export class ContentNodeSelectorDialog extends Component { + private static selectors = { + root: '.adf-content-node-selector-dialog', + + title: '.mat-dialog-title', + locationDropDown: 'site-dropdown-container', + locationOption: '.mat-option .mat-option-text', + + dataTable: '.adf-datatable-body', + selectedRow: '.adf-is-selected', + + button: '.mat-dialog-actions button', + chooseAction: '.adf-choose-action', + + searchInput: '#searchInput', + toolbarTitle: '.adf-toolbar-title' + }; + + title: ElementFinder = this.component.element(by.css(ContentNodeSelectorDialog.selectors.title)); + locationDropDown: ElementFinder = this.component.element(by.id(ContentNodeSelectorDialog.selectors.locationDropDown)); + locationPersonalFiles: ElementFinder = browser.element(by.cssContainingText(ContentNodeSelectorDialog.selectors.locationOption, 'Personal Files')); + locationFileLibraries: ElementFinder = browser.element(by.cssContainingText(ContentNodeSelectorDialog.selectors.locationOption, 'File Libraries')); + + cancelButton: ElementFinder = this.component.element(by.cssContainingText(ContentNodeSelectorDialog.selectors.button, 'Cancel')); + copyButton: ElementFinder = this.component.element(by.css(ContentNodeSelectorDialog.selectors.chooseAction)); + moveButton: ElementFinder = this.component.element(by.cssContainingText(ContentNodeSelectorDialog.selectors.button, 'Move')); + + searchInput: ElementFinder = this.component.element(by.css(ContentNodeSelectorDialog.selectors.searchInput)); + toolbarTitle: ElementFinder = this.component.element(by.css(ContentNodeSelectorDialog.selectors.toolbarTitle)); + + breadcrumb: DropDownBreadcrumb = new DropDownBreadcrumb(); + dataTable: DataTable = new DataTable(ContentNodeSelectorDialog.selectors.root); + + constructor(ancestor?: string) { + super(ContentNodeSelectorDialog.selectors.root, ancestor); + } + + async waitForDialogToOpen(): Promise { + await browser.wait(EC.presenceOf(this.title), BROWSER_WAIT_TIMEOUT, 'timeout waiting for dialog title'); + await browser.wait(EC.presenceOf(browser.element(by.css('.cdk-overlay-backdrop'))), BROWSER_WAIT_TIMEOUT, 'timeout waiting for overlay backdrop'); + } + + async waitForDialogToClose(): Promise { + await browser.wait(EC.stalenessOf(this.title), BROWSER_WAIT_TIMEOUT); + } + + async waitForDropDownToOpen(): Promise { + await browser.wait(EC.presenceOf(this.locationPersonalFiles), BROWSER_WAIT_TIMEOUT); + } + + async waitForDropDownToClose(): Promise { + await browser.wait(EC.stalenessOf(browser.$(ContentNodeSelectorDialog.selectors.locationOption)), BROWSER_WAIT_TIMEOUT); + } + + async waitForRowToBeSelected(): Promise { + await browser.wait(EC.presenceOf(this.component.element(by.css(ContentNodeSelectorDialog.selectors.selectedRow))), BROWSER_WAIT_TIMEOUT); + } + + async isDialogOpen(): Promise { + return browser.$(ContentNodeSelectorDialog.selectors.root).isDisplayed(); + } + + async getTitle(): Promise { + return this.title.getText(); + } + + async clickCancel(): Promise { + await this.cancelButton.click(); + await this.waitForDialogToClose(); + } + + async clickCopy(): Promise { + await this.copyButton.click(); + } + + async clickMove(): Promise { + await this.moveButton.click(); + } + + async selectLocation(location: 'Personal Files' | 'File Libraries'): Promise { + await this.locationDropDown.click(); + await this.waitForDropDownToOpen(); + + if (location === 'Personal Files') { + await this.locationPersonalFiles.click(); + } else { + await this.locationFileLibraries.click(); + } + + await this.waitForDropDownToClose(); + } + + async selectDestination(folderName: string): Promise { + const row = this.dataTable.getRowByName(folderName); + await Utils.waitUntilElementClickable(row); + await row.click(); + await this.waitForRowToBeSelected(); + } + + async isSearchInputPresent(): Promise { + return await this.searchInput.isPresent(); + } + + async isSelectLocationDropdownDisplayed(): Promise { + return (await this.locationDropDown.isPresent()) && (await this.locationDropDown.isDisplayed()); + } + + async isCopyButtonEnabled(): Promise { + return (await this.copyButton.isPresent()) && (await this.copyButton.isEnabled()); + } + + async isCancelButtonEnabled(): Promise { + return (await this.cancelButton.isPresent()) && (await this.cancelButton.isEnabled()); + } + + async searchFor(text: string): Promise { + await Utils.clearFieldWithBackspace(this.searchInput); + await this.searchInput.sendKeys(text); + await this.searchInput.sendKeys(protractor.Key.ENTER); + } + + async getToolbarTitle(): Promise { + return await this.toolbarTitle.getText(); + } +} diff --git a/e2e/components/dialog/copy-move-dialog.ts b/e2e/components/dialog/copy-move-dialog.ts deleted file mode 100755 index 7f54623ff..000000000 --- a/e2e/components/dialog/copy-move-dialog.ts +++ /dev/null @@ -1,126 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2020 Alfresco Software Limited - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { ElementFinder, by, browser, ExpectedConditions as EC } from 'protractor'; -import { BROWSER_WAIT_TIMEOUT } from '../../configs'; -import { Component } from '../component'; -import { Utils } from './../../utilities/utils'; - -export class CopyMoveDialog extends Component { - private static selectors = { - root: '.adf-content-node-selector-dialog', - - title: '.mat-dialog-title', - locationDropDown: 'site-dropdown-container', - locationOption: '.mat-option .mat-option-text', - - dataTable: '.adf-datatable-body', - selectedRow: '.adf-is-selected', - - button: '.mat-dialog-actions button' - }; - - title: ElementFinder = this.component.element(by.css(CopyMoveDialog.selectors.title)); - dataTable: ElementFinder = this.component.element(by.css(CopyMoveDialog.selectors.dataTable)); - locationDropDown: ElementFinder = this.component.element(by.id(CopyMoveDialog.selectors.locationDropDown)); - locationPersonalFiles: ElementFinder = browser.element(by.cssContainingText(CopyMoveDialog.selectors.locationOption, 'Personal Files')); - locationFileLibraries: ElementFinder = browser.element(by.cssContainingText(CopyMoveDialog.selectors.locationOption, 'File Libraries')); - - cancelButton: ElementFinder = this.component.element(by.cssContainingText(CopyMoveDialog.selectors.button, 'Cancel')); - copyButton: ElementFinder = this.component.element(by.cssContainingText(CopyMoveDialog.selectors.button, 'Copy')); - moveButton: ElementFinder = this.component.element(by.cssContainingText(CopyMoveDialog.selectors.button, 'Move')); - - constructor(ancestor?: string) { - super(CopyMoveDialog.selectors.root, ancestor); - } - - async waitForDialogToClose() { - await browser.wait(EC.stalenessOf(this.title), BROWSER_WAIT_TIMEOUT); - } - - async waitForDropDownToOpen() { - await browser.wait(EC.presenceOf(this.locationPersonalFiles), BROWSER_WAIT_TIMEOUT); - } - - async waitForDropDownToClose() { - await browser.wait(EC.stalenessOf(browser.$(CopyMoveDialog.selectors.locationOption)), BROWSER_WAIT_TIMEOUT); - } - - async waitForRowToBeSelected() { - await browser.wait(EC.presenceOf(this.component.element(by.css(CopyMoveDialog.selectors.selectedRow))), BROWSER_WAIT_TIMEOUT); - } - - async isDialogOpen() { - return browser.$(CopyMoveDialog.selectors.root).isDisplayed(); - } - - async getTitle() { - return this.title.getText(); - } - - async clickCancel() { - await this.cancelButton.click(); - await this.waitForDialogToClose(); - } - - async clickCopy() { - await this.copyButton.click(); - } - - async clickMove() { - await this.moveButton.click(); - } - - getRow(folderName: string) { - return this.dataTable.element(by.cssContainingText('.adf-name-location-cell', folderName)); - } - - async doubleClickOnRow(name: string) { - const item = this.getRow(name); - await Utils.waitUntilElementClickable(item); - await browser.actions().mouseMove(item).perform(); - await browser.actions().click().click().perform(); - } - - async selectLocation(location: 'Personal Files' | 'File Libraries') { - await this.locationDropDown.click(); - await this.waitForDropDownToOpen(); - - if (location === 'Personal Files') { - await this.locationPersonalFiles.click(); - } else { - await this.locationFileLibraries.click(); - } - - await this.waitForDropDownToClose(); - } - - async selectDestination(folderName: string) { - const row = this.getRow(folderName); - await Utils.waitUntilElementClickable(row); - await row.click(); - await this.waitForRowToBeSelected(); - } -} diff --git a/e2e/suites/actions/copy.test.ts b/e2e/suites/actions/copy-move/copy.test.ts similarity index 98% rename from e2e/suites/actions/copy.test.ts rename to e2e/suites/actions/copy-move/copy.test.ts index 662c06560..ac421b607 100755 --- a/e2e/suites/actions/copy.test.ts +++ b/e2e/suites/actions/copy-move/copy.test.ts @@ -23,10 +23,10 @@ * along with Alfresco. If not, see . */ -import { LoginPage, BrowsingPage } from '../../pages/pages'; -import { CopyMoveDialog } from './../../components/dialog/copy-move-dialog'; -import { RepoClient } from '../../utilities/repo-client/repo-client'; -import { Utils } from '../../utilities/utils'; +import { LoginPage, BrowsingPage } from '../../../pages/pages'; +import { ContentNodeSelectorDialog } from '../../../components/dialog/content-node-selector-dialog'; +import { RepoClient } from '../../../utilities/repo-client/repo-client'; +import { Utils } from '../../../utilities/utils'; describe('Copy content', () => { const username = `user-${Utils.random()}`; @@ -86,7 +86,7 @@ describe('Copy content', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); const { dataTable, toolbar } = page; - const copyDialog = new CopyMoveDialog(); + const copyDialog = new ContentNodeSelectorDialog(); const { searchInput } = page.header; beforeAll(async (done) => { @@ -539,8 +539,8 @@ describe('Copy content', () => { await dataTable.selectMultipleItems(items, location); await toolbar.clickMoreActionsCopy(); await copyDialog.selectLocation('File Libraries'); - await copyDialog.doubleClickOnRow(siteName); - await copyDialog.doubleClickOnRow('documentLibrary'); + await copyDialog.dataTable.doubleClickOnRowByName(siteName); + await copyDialog.dataTable.doubleClickOnRowByName('documentLibrary'); await copyDialog.selectDestination(destination); await copyDialog.clickCopy(); const msg = await page.getSnackBarMessage(); @@ -665,7 +665,7 @@ describe('Copy content', () => { await dataTable.selectItem(fileName, location); await toolbar.clickMoreActionsCopy(); await copyDialog.selectLocation('Personal Files'); - await copyDialog.doubleClickOnRow(source); + await copyDialog.dataTable.doubleClickOnRowByName(source); await copyDialog.selectDestination(destination); await copyDialog.clickCopy(); const msg = await page.getSnackBarMessage(); @@ -692,7 +692,7 @@ describe('Copy content', () => { await dataTable.selectItem(folderName, location); await toolbar.clickMoreActionsCopy(); await copyDialog.selectLocation('Personal Files'); - await copyDialog.doubleClickOnRow(destination); + await copyDialog.dataTable.doubleClickOnRowByName(destination); await copyDialog.clickCopy(); const msg = await page.getSnackBarMessage(); expect(msg).toContain('Copied 1 item'); diff --git a/e2e/suites/actions/copy-move/destination-picker-dialog.test.ts b/e2e/suites/actions/copy-move/destination-picker-dialog.test.ts new file mode 100755 index 000000000..02c0e372e --- /dev/null +++ b/e2e/suites/actions/copy-move/destination-picker-dialog.test.ts @@ -0,0 +1,332 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { LoginPage, BrowsingPage } from '../../../pages/pages'; +import { ContentNodeSelectorDialog } from '../../../components/dialog/content-node-selector-dialog'; +import { RepoClient } from '../../../utilities/repo-client/repo-client'; +import { Utils } from '../../../utilities/utils'; +import { AdminActions } from '../../../utilities/admin-actions'; + +describe('Destination picker dialog : ', () => { + const random = Utils.random(); + + const username = `user-${random}`; + + const consumer = `consumer-${random}`; + const contributor = `contributor-${random}`; + const collaborator = `collaborator-${random}`; + + const file = `file-${random}.txt`; + let fileId: string; + let fileIdConsumer: string; + let fileIdContributor: string; + let fileIdCollaborator: string; + + const adminFolder = `admin-folder-${random}`; + let adminFolderId: string; + + const destination = `destination-folder-${random}`; + let destinationId: string; + const fileInDestination = `file-in-dest-${random}.txt`; + const folderInDestination = `folder-in-dest-${random}`; + const folder2InDestination = `folder2-in-dest-${random}`; + let folderLink: string; + + const searchFolder = `search-${random}`; + let searchFolderId: string; + let searchFolderSiteId: string; + const searchSubFolder1 = `sub-folder-${random}`; + let searchSubFolder1Id: string; + let searchSubFolder1SiteId: string; + const searchSubFolder2 = `sub-folder-${random}`; + + const site = `site-${random}`; + + const userApi = new RepoClient(username, username); + const consumerApi = new RepoClient(consumer, consumer); + const contributorApi = new RepoClient(contributor, contributor); + const collaboratorApi = new RepoClient(collaborator, collaborator); + const adminApiActions = new AdminActions(); + + const loginPage = new LoginPage(); + const page = new BrowsingPage(); + const { dataTable, toolbar } = page; + const contentNodeSelector = new ContentNodeSelectorDialog(); + + beforeAll(async () => { + await adminApiActions.createUser({ username }); + await adminApiActions.createUser({ username: consumer }); + await adminApiActions.createUser({ username: contributor }); + await adminApiActions.createUser({ username: collaborator }); + + fileId = (await userApi.nodes.createFile(file)).entry.id; + + destinationId = (await userApi.nodes.createFolder(destination)).entry.id; + await userApi.nodes.createFile(fileInDestination, destinationId); + await userApi.nodes.createFolder(folderInDestination, destinationId); + const folder2Id = (await userApi.nodes.createFolder(folder2InDestination, destinationId)).entry.id; + folderLink = (await userApi.nodes.createFolderLink(folder2Id, destinationId)).entry.name; + searchFolderId = (await userApi.nodes.createFolder(searchFolder, destinationId)).entry.id; + searchSubFolder1Id = (await userApi.nodes.createFolder(searchSubFolder1, searchFolderId)).entry.id; + await userApi.nodes.createFolder(searchSubFolder2, searchSubFolder1Id); + + await userApi.sites.createSitePrivate(site); + const docLibId = await userApi.sites.getDocLibId(site); + searchFolderSiteId = (await userApi.nodes.createFolder(searchFolder, docLibId)).entry.id; + searchSubFolder1SiteId = (await userApi.nodes.createFolder(searchSubFolder1, searchFolderSiteId)).entry.id; + await userApi.nodes.createFolder(searchSubFolder2, searchSubFolder1SiteId); + + await userApi.sites.addSiteConsumer(site, consumer); + await userApi.sites.addSiteContributor(site, contributor); + await userApi.sites.addSiteCollaborator(site, collaborator); + + fileIdConsumer = (await consumerApi.nodes.createFile(file)).entry.id; + fileIdContributor = (await contributorApi.nodes.createFile(file)).entry.id; + fileIdCollaborator = (await collaboratorApi.nodes.createFile(file)).entry.id; + + adminFolderId = (await adminApiActions.nodes.createFolder(adminFolder)).entry.id; + + await userApi.search.waitForNodes(searchFolder, { expect: 2 }); + }); + + afterAll(async () => { + await userApi.nodes.deleteNodeById(fileId); + await userApi.nodes.deleteNodeById(destinationId); + await userApi.sites.deleteSite(site); + + await consumerApi.nodes.deleteNodeById(fileIdConsumer); + await contributorApi.nodes.deleteNodeById(fileIdContributor); + await collaboratorApi.nodes.deleteNodeById(fileIdCollaborator); + + await adminApiActions.nodes.deleteNodeById(adminFolderId); + }); + + afterEach(async () => { + await page.closeOpenDialogs(); + }); + + describe('general', () => { + beforeAll(async () => { + await loginPage.loginWith(username); + }); + + beforeEach(async () => { + await dataTable.selectItem(file); + await toolbar.clickMoreActionsCopy(); + await contentNodeSelector.waitForDialogToOpen(); + }); + + it('Dialog UI - [C263875]', async () => { + expect(await contentNodeSelector.getTitle()).toEqual(`Copy '${file}' to...`); + expect(await contentNodeSelector.isSearchInputPresent()).toBe(true, 'Search input is not displayed'); + expect(await contentNodeSelector.isSelectLocationDropdownDisplayed()).toBe(true, 'Select Location dropdown not displayed'); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual('Personal Files'); + expect(await contentNodeSelector.dataTable.isItemPresent(destination)).toBe(true, 'Personal Files content not displayed'); + expect(await contentNodeSelector.isCopyButtonEnabled()).toBe(true, 'Copy button is not disabled'); + expect(await contentNodeSelector.isCancelButtonEnabled()).toBe(true, 'Cancel button is not enabled'); + }); + + it('Files are not displayed - [C263880]', async () => { + await contentNodeSelector.selectLocation('Personal Files'); + expect(await contentNodeSelector.dataTable.isItemPresent(destination)).toBe(true, 'destination folder not displayed'); + await contentNodeSelector.dataTable.doubleClickOnRowByName(destination); + expect(await contentNodeSelector.dataTable.isItemPresent(folderInDestination)).toBe(true, 'folder is not displayed'); + expect(await contentNodeSelector.dataTable.isItemPresent(fileInDestination)).toBe(false, 'file is displayed'); + }); + + it('Folder links are not displayed - [C263881]', async() => { + await contentNodeSelector.selectLocation('Personal Files'); + await contentNodeSelector.dataTable.doubleClickOnRowByName(destination); + + expect(await contentNodeSelector.dataTable.isItemPresent(folderInDestination)).toBe(true, `${folderInDestination} is not displayed`); + expect(await contentNodeSelector.dataTable.isItemPresent(folder2InDestination)).toBe(true, `${folder2InDestination} is not displayed`); + expect(await contentNodeSelector.dataTable.isItemPresent(folderLink)).toBe(false, 'Link to folder is displayed'); + }); + + it('User can see his Libraries - [C263885]', async () => { + await contentNodeSelector.selectLocation('File Libraries'); + expect(await contentNodeSelector.dataTable.isItemPresent(site)).toBe(true, 'user site is not displayed'); + }); + + it('Search - No results displayed - [C263889]', async () => { + await contentNodeSelector.searchFor('nonexistent-folder'); + expect(await contentNodeSelector.dataTable.isEmpty()).toBe(true, 'datatable not empty'); + expect(await contentNodeSelector.dataTable.getEmptyListText()).toEqual('No results found'); + }); + + it('Search - results found - [C263888]', async () => { + await contentNodeSelector.searchFor(searchFolder); + expect(await contentNodeSelector.dataTable.isItemPresent(searchFolder, username)).toBe(true, 'folder from Personal Files not displayed'); + expect(await contentNodeSelector.dataTable.isItemPresent(searchFolder, site)).toBe(true, 'folder from site not displayed'); + }); + }); + + describe('multiple selection', () => { + beforeAll(async () => { + await loginPage.loginWith(username); + }); + + beforeEach(async () => { + await dataTable.selectMultipleItems([file, destination]); + await toolbar.clickMoreActionsCopy(); + await contentNodeSelector.waitForDialogToOpen(); + }); + + it('Dialog title - multiple selection - [C263879]', async () => { + expect(await contentNodeSelector.getTitle()).toEqual(`Copy 2 items to...`); + }); + }); + + describe('breadcrumb', () => { + beforeAll(async () => { + await loginPage.loginWith(username); + }); + + beforeEach(async () => { + await dataTable.selectItem(file); + await toolbar.clickMoreActionsCopy(); + await contentNodeSelector.waitForDialogToOpen(); + }); + + it('Personal Files breadcrumb - main node - [C263890]', async () => { + await contentNodeSelector.selectLocation('Personal Files'); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual('Personal Files'); + }); + + it('File Libraries breadcrumb - main node - [C263891]', async () => { + await contentNodeSelector.selectLocation('File Libraries'); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual('File Libraries'); + }); + + it('Search results breadcrumb - [C263899]', async () => { + await contentNodeSelector.searchFor(searchFolder); + expect(await contentNodeSelector.getToolbarTitle()).toEqual('Search results'); + }); + + it('Search results breadcrumb when selecting a folder - [C263900]', async () => { + await contentNodeSelector.searchFor(searchFolder); + await contentNodeSelector.dataTable.selectItem(searchFolder, site); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual(searchFolder); + }); + + it('Personal Files breadcrumb - folder structure - [C263897]', async () => { + await contentNodeSelector.selectLocation('Personal Files'); + await contentNodeSelector.dataTable.doubleClickOnRowByName(destination); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual(destination); + await contentNodeSelector.dataTable.doubleClickOnRowByName(searchFolder); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual(searchFolder); + await contentNodeSelector.dataTable.doubleClickOnRowByName(searchSubFolder1); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual(searchSubFolder1); + await contentNodeSelector.dataTable.doubleClickOnRowByName(searchSubFolder2); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual(searchSubFolder2); + await contentNodeSelector.breadcrumb.openPath(); + expect(await contentNodeSelector.breadcrumb.getPathItems()).toEqual([searchSubFolder1, searchFolder, destination, 'Personal Files']); + }); + + it('File Libraries breadcrumb - folder structure - [C263898]', async () => { + await contentNodeSelector.selectLocation('File Libraries'); + await contentNodeSelector.dataTable.doubleClickOnRowByName(site); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual(site); + await contentNodeSelector.dataTable.doubleClickOnRowByName('documentLibrary'); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual(site); + await contentNodeSelector.dataTable.doubleClickOnRowByName(searchFolder); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual(searchFolder); + await contentNodeSelector.dataTable.doubleClickOnRowByName(searchSubFolder1); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual(searchSubFolder1); + await contentNodeSelector.dataTable.doubleClickOnRowByName(searchSubFolder2); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual(searchSubFolder2); + await contentNodeSelector.breadcrumb.openPath(); + expect(await contentNodeSelector.breadcrumb.getPathItems()).toEqual([searchSubFolder1, searchFolder, site, 'File Libraries']); + }); + + it('Select a node from the breadcrumb path - [C263895]', async () => { + await contentNodeSelector.selectLocation('Personal Files'); + await contentNodeSelector.dataTable.doubleClickOnRowByName(destination); + await contentNodeSelector.dataTable.doubleClickOnRowByName(searchFolder); + await contentNodeSelector.dataTable.doubleClickOnRowByName(searchSubFolder1); + await contentNodeSelector.dataTable.doubleClickOnRowByName(searchSubFolder2); + await contentNodeSelector.breadcrumb.openPath(); + + await contentNodeSelector.breadcrumb.clickPathItem(destination); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual(destination); + expect(await contentNodeSelector.dataTable.isItemPresent(searchFolder)).toBe(true, 'folder not displayed'); + }); + }); + + describe('Users with different permissions', () => { + + it('Consumer user cannot select the folder as destination - [C263876]', async () => { + await loginPage.loginWith(consumer); + await dataTable.selectItem(file); + await toolbar.clickMoreActionsCopy(); + await contentNodeSelector.waitForDialogToOpen(); + + await contentNodeSelector.selectLocation('File Libraries'); + await contentNodeSelector.dataTable.doubleClickOnRowByName(site); + await contentNodeSelector.dataTable.doubleClickOnRowByName('documentLibrary'); + await contentNodeSelector.dataTable.selectItem(searchFolder); + + expect(await contentNodeSelector.isCopyButtonEnabled()).toBe(false, 'Copy should be disabled'); + }); + + it('Contributor user can select the folder as destination - [C263877]', async () => { + await loginPage.loginWith(contributor); + await dataTable.selectItem(file); + await toolbar.clickMoreActionsCopy(); + await contentNodeSelector.waitForDialogToOpen(); + + await contentNodeSelector.selectLocation('File Libraries'); + await contentNodeSelector.dataTable.doubleClickOnRowByName(site); + await contentNodeSelector.dataTable.doubleClickOnRowByName('documentLibrary'); + await contentNodeSelector.dataTable.selectItem(searchFolder); + + expect(await contentNodeSelector.isCopyButtonEnabled()).toBe(true, 'Copy should be disabled'); + }); + + it('Collaborator user can select the folder as destination - [C263878]', async () => { + await loginPage.loginWith(collaborator); + await dataTable.selectItem(file); + await toolbar.clickMoreActionsCopy(); + await contentNodeSelector.waitForDialogToOpen(); + + await contentNodeSelector.selectLocation('File Libraries'); + await contentNodeSelector.dataTable.doubleClickOnRowByName(site); + await contentNodeSelector.dataTable.doubleClickOnRowByName('documentLibrary'); + await contentNodeSelector.dataTable.selectItem(searchFolder); + + expect(await contentNodeSelector.isCopyButtonEnabled()).toBe(true, 'Copy should be disabled'); + }); + + it('Admin user - Personal Files breadcrumb main node - [C263892]', async () => { + await loginPage.loginWithAdmin(); + await dataTable.selectItem(adminFolder); + await toolbar.clickMoreActionsCopy(); + await contentNodeSelector.waitForDialogToOpen(); + + await contentNodeSelector.selectLocation('Personal Files'); + expect(await contentNodeSelector.breadcrumb.getCurrentFolderName()).toEqual('Company Home'); + }); + }); +}); diff --git a/e2e/suites/actions/move.test.ts b/e2e/suites/actions/copy-move/move.test.ts similarity index 97% rename from e2e/suites/actions/move.test.ts rename to e2e/suites/actions/copy-move/move.test.ts index 721b3b76c..a6536e352 100755 --- a/e2e/suites/actions/move.test.ts +++ b/e2e/suites/actions/copy-move/move.test.ts @@ -23,10 +23,10 @@ * along with Alfresco. If not, see . */ -import { LoginPage, BrowsingPage } from '../../pages/pages'; -import { CopyMoveDialog } from './../../components/dialog/copy-move-dialog'; -import { RepoClient } from '../../utilities/repo-client/repo-client'; -import { Utils } from '../../utilities/utils'; +import { LoginPage, BrowsingPage } from '../../../pages/pages'; +import { ContentNodeSelectorDialog } from '../../../components/dialog/content-node-selector-dialog'; +import { RepoClient } from '../../../utilities/repo-client/repo-client'; +import { Utils } from '../../../utilities/utils'; describe('Move content', () => { const username = `user-${Utils.random()}`; @@ -57,7 +57,7 @@ describe('Move content', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); const { dataTable, toolbar } = page; - const moveDialog = new CopyMoveDialog(); + const moveDialog = new ContentNodeSelectorDialog(); beforeAll(async (done) => { await apis.admin.people.createUser({ username }); @@ -254,8 +254,8 @@ describe('Move content', () => { await dataTable.selectMultipleItems([file4, folder2]); await toolbar.clickMoreActionsMove(); await moveDialog.selectLocation('File Libraries'); - await moveDialog.doubleClickOnRow(siteName); - await moveDialog.doubleClickOnRow('documentLibrary'); + await moveDialog.dataTable.doubleClickOnRowByName(siteName); + await moveDialog.dataTable.doubleClickOnRowByName('documentLibrary'); await moveDialog.selectDestination(folderSitePF); await moveDialog.clickMove(); const msg = await page.getSnackBarMessage(); @@ -374,8 +374,8 @@ describe('Move content', () => { await dataTable.selectItem(file4, sourceRF); await toolbar.clickMoreActionsMove(); await moveDialog.selectLocation('File Libraries'); - await moveDialog.doubleClickOnRow(siteName); - await moveDialog.doubleClickOnRow('documentLibrary'); + await moveDialog.dataTable.doubleClickOnRowByName(siteName); + await moveDialog.dataTable.doubleClickOnRowByName('documentLibrary'); await moveDialog.selectDestination(folderSiteRF); await moveDialog.clickMove(); const msg = await page.getSnackBarMessage(); @@ -496,8 +496,8 @@ describe('Move content', () => { await dataTable.selectItem(file4, sourceSF); await toolbar.clickMoreActionsMove(); await moveDialog.selectLocation('File Libraries'); - await moveDialog.doubleClickOnRow(siteName); - await moveDialog.doubleClickOnRow('documentLibrary'); + await moveDialog.dataTable.doubleClickOnRowByName(siteName); + await moveDialog.dataTable.doubleClickOnRowByName('documentLibrary'); await moveDialog.selectDestination(folderSiteSF); await moveDialog.clickMove(); const msg = await page.getSnackBarMessage(); @@ -686,8 +686,8 @@ describe('Move content', () => { await dataTable.selectMultipleItems([file4, folder2], sourceFav); await toolbar.clickMoreActionsMove(); await moveDialog.selectLocation('File Libraries'); - await moveDialog.doubleClickOnRow(siteName); - await moveDialog.doubleClickOnRow('documentLibrary'); + await moveDialog.dataTable.doubleClickOnRowByName(siteName); + await moveDialog.dataTable.doubleClickOnRowByName('documentLibrary'); await moveDialog.selectDestination(folderSiteFav); await moveDialog.clickMove(); const msg = await page.getSnackBarMessage(); diff --git a/e2e/suites/viewer/viewer-actions.test.ts b/e2e/suites/viewer/viewer-actions.test.ts index 52f7d9c22..0c9801403 100755 --- a/e2e/suites/viewer/viewer-actions.test.ts +++ b/e2e/suites/viewer/viewer-actions.test.ts @@ -28,7 +28,7 @@ import { FILES } from '../../configs'; import { RepoClient } from '../../utilities/repo-client/repo-client'; import { Utils } from '../../utilities/utils'; import { Viewer } from '../../components/viewer/viewer'; -import { CopyMoveDialog } from './../../components/dialog/copy-move-dialog'; +import { ContentNodeSelectorDialog } from './../../components/dialog/content-node-selector-dialog'; import { ShareDialog } from './../../components/dialog/share-dialog'; import { ManageVersionsDialog } from './../../components/dialog/manage-versions-dialog'; import { UploadNewVersionDialog } from './../../components/dialog/upload-new-version-dialog'; @@ -51,7 +51,7 @@ describe('Viewer actions', () => { const dataTable = page.dataTable; const viewer = new Viewer(); const { toolbar } = viewer; - const copyMoveDialog = new CopyMoveDialog(); + const copyMoveDialog = new ContentNodeSelectorDialog(); const shareDialog = new ShareDialog(); const manageVersionsDialog = new ManageVersionsDialog(); const uploadNewVersionDialog = new UploadNewVersionDialog(); diff --git a/protractor.conf.js b/protractor.conf.js index 4e74a0823..9a233b22e 100755 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -52,7 +52,7 @@ exports.config = { './e2e/suites/pagination/*.test.ts', './e2e/suites/search/*.test.ts', './e2e/suites/actions-available/**/*.test.ts', - './e2e/suites/actions/*.test.ts', + './e2e/suites/actions/**/*.test.ts', './e2e/suites/viewer/*.test.ts', './e2e/suites/info-drawer/*.test.ts', './e2e/suites/extensions/*.test.ts' From 04cf47c7df0ff3e75bd73df25c747d28e263983a Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Mon, 10 Feb 2020 21:11:50 +0200 Subject: [PATCH 88/96] bump version (#1335) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3bcb32138..9a287ce71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9909,9 +9909,9 @@ } }, "pdfjs-dist": { - "version": "2.0.943", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.0.943.tgz", - "integrity": "sha512-iLhNcm4XceTHRaSU5o22ZGCm4YpuW5+rf4+BJFH/feBhMQLbCGBry+Jet8Q419QDI4qgARaIQzXuiNrsNWS8Yw==", + "version": "2.3.200", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.3.200.tgz", + "integrity": "sha512-+8wBjU5h8LPZOIvR9X2uCrp/8xWQG1DRDKMLg5lzGN1qyIAZlYUxA0KQyy12Nw5jN7ozulC6v97PMaDcLgAcFg==", "requires": { "node-ensure": "^0.0.0", "worker-loader": "^2.0.0" diff --git a/package.json b/package.json index d1ffe6dc4..9c226513e 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "minimatch-browser": "^1.0.0", "moment": "^2.24.0", "moment-es6": "1.0.0", - "pdfjs-dist": "2.0.943", + "pdfjs-dist": "2.3.200", "rxjs": "^6.5.2", "zone.js": "0.8.29" }, From d6a8075642ccce912b71beb5522b0beda74fefe1 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 13 Feb 2020 09:15:32 +0200 Subject: [PATCH 89/96] [ACA-2280] Favorite Libraries - Previous page is not loaded when deleting all items from current page (#1338) * pagination target * default pagination config * prevent ExpressionChangedAfterItHasBeenCheckedError --- .../favorite-libraries.component.html | 1 + .../favorite-libraries.component.ts | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/app/components/favorite-libraries/favorite-libraries.component.html b/src/app/components/favorite-libraries/favorite-libraries.component.html index 0e986ca6c..71e1257b7 100644 --- a/src/app/components/favorite-libraries/favorite-libraries.component.html +++ b/src/app/components/favorite-libraries/favorite-libraries.component.html @@ -79,6 +79,7 @@ { this.list = null; From f4cfc96849e6311313d8147f918a69a89dc14c7a Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 13 Feb 2020 17:36:36 +0200 Subject: [PATCH 90/96] hide floating label (#1339) --- src/app/ui/overrides/adf-style-fixes.theme.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/ui/overrides/adf-style-fixes.theme.scss b/src/app/ui/overrides/adf-style-fixes.theme.scss index 52383281a..b4229859d 100644 --- a/src/app/ui/overrides/adf-style-fixes.theme.scss +++ b/src/app/ui/overrides/adf-style-fixes.theme.scss @@ -13,4 +13,8 @@ display: none; } } + + adf-share-dialog .mat-form-field-label-wrapper label { + display: none !important; + } } From c37e5f431e04d5efce1ca83bbc32a7ddefddd561 Mon Sep 17 00:00:00 2001 From: Adina Parpalita Date: Thu, 13 Feb 2020 17:38:54 +0200 Subject: [PATCH 91/96] add TestRail IDs (#1340) --- .../files-folders/favorites.ts | 14 +- .../files-folders/personal-files.ts | 32 ++--- .../files-folders/recent-files.ts | 26 ++-- .../files-folders/search-results.ts | 30 ++--- .../files-folders/shared-files.ts | 14 +- .../actions-available/files-folders/viewer.ts | 96 +++++++------- .../libraries/library.test.ts | 124 +++++++----------- .../special-permissions/favorites.ts | 24 ++-- .../special-permissions/my-libraries.ts | 54 ++++---- .../special-permissions/search-results.ts | 40 +++--- .../special-permissions/shared-files.ts | 20 +-- .../special-permissions/viewer.ts | 72 +++++----- 12 files changed, 261 insertions(+), 285 deletions(-) diff --git a/e2e/suites/actions-available/files-folders/favorites.ts b/e2e/suites/actions-available/files-folders/favorites.ts index 81aa76110..bcda94375 100755 --- a/e2e/suites/actions-available/files-folders/favorites.ts +++ b/e2e/suites/actions-available/files-folders/favorites.ts @@ -43,39 +43,39 @@ export function favoritesTests() { describe('on a file', () => { - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C297618]', async () => { await testUtil.checkToolbarActions(testData.fileDocxFav.name, testData.fileDocxFav.toolbarPrimary, testData.fileDocxFav.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileDocxFav.name, testData.fileDocxFav.favoritesContextMenu); }); - it('File favorite - []', async () => { + it('File favorite - [C280461]', async () => { await testUtil.checkToolbarActions(testData.fileFav.name, testData.fileFav.toolbarPrimary, testData.fileFav.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileFav.name, testData.fileFav.favoritesContextMenu); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C297620]', async () => { await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.favoritesToolbarPrimary, testData.fileDocxSharedFav.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.favoritesContextMenu); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C280462]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.favoritesToolbarPrimary, testData.fileSharedFav.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileSharedFav.name, testData.fileSharedFav.favoritesContextMenu); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C280463]', async () => { await testUtil.checkToolbarActions(testData.fileFavLocked.name, testData.fileFavLocked.toolbarPrimary, testData.fileFavLocked.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileFavLocked.name, testData.fileFavLocked.favoritesContextMenu); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C280469]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.favoritesToolbarPrimary, testData.fileSharedFavLocked.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.favoritesContextMenu); }); }); describe('on a folder', () => { - it('Folder favorite - []', async () => { + it('Folder favorite - [C291817]', async () => { await testUtil.checkToolbarActions(testData.folderFav.name, testData.folderFav.toolbarPrimary, testData.folderFav.favoritesToolbarMore); await testUtil.checkContextMenu(testData.folderFav.name, testData.folderFav.favoritesContextMenu); }); diff --git a/e2e/suites/actions-available/files-folders/personal-files.ts b/e2e/suites/actions-available/files-folders/personal-files.ts index 0a059ac2f..b18256bdf 100755 --- a/e2e/suites/actions-available/files-folders/personal-files.ts +++ b/e2e/suites/actions-available/files-folders/personal-files.ts @@ -46,62 +46,62 @@ export function personalFilesTests(parentName?: string) { describe('on a file', () => { - it('File Office - []', async () => { + it('File Office - [C213122]', async () => { await testUtil.checkToolbarActions(testData.fileDocx.name, testData.fileDocx.toolbarPrimary, testData.fileDocx.toolbarMore); await testUtil.checkContextMenu(testData.fileDocx.name, testData.fileDocx.contextMenu); }); - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C297612]', async () => { await testUtil.checkToolbarActions(testData.fileDocxFav.name, testData.fileDocxFav.toolbarPrimary, testData.fileDocxFav.toolbarMore); await testUtil.checkContextMenu(testData.fileDocxFav.name, testData.fileDocxFav.contextMenu); }); - it('File simple - []', async () => { + it('File simple - [C286265]', async () => { await testUtil.checkToolbarActions(testData.file.name, testData.file.toolbarPrimary, testData.file.toolbarMore); await testUtil.checkContextMenu(testData.file.name, testData.file.contextMenu); }); - it('File favorite - []', async () => { + it('File favorite - [C297615]', async () => { await testUtil.checkToolbarActions(testData.fileFav.name, testData.fileFav.toolbarPrimary, testData.fileFav.toolbarMore); await testUtil.checkContextMenu(testData.fileFav.name, testData.fileFav.contextMenu); }); - it('File Office, shared - []', async () => { + it('File Office, shared - [C280448]', async () => { await testUtil.checkToolbarActions(testData.fileDocxShared.name, testData.fileDocxShared.toolbarPrimary, testData.fileDocxShared.toolbarMore); await testUtil.checkContextMenu(testData.fileDocxShared.name, testData.fileDocxShared.contextMenu); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C297616]', async () => { await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.toolbarPrimary, testData.fileDocxSharedFav.toolbarMore); await testUtil.checkContextMenu(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.contextMenu); }); - it('File shared - []', async () => { + it('File shared - [C286323]', async () => { await testUtil.checkToolbarActions(testData.fileShared.name, testData.fileShared.toolbarPrimary, testData.fileShared.toolbarMore); await testUtil.checkContextMenu(testData.fileShared.name, testData.fileShared.contextMenu); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C280450]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.toolbarPrimary, testData.fileSharedFav.toolbarMore); await testUtil.checkContextMenu(testData.fileSharedFav.name, testData.fileSharedFav.contextMenu); }); - it('File locked - []', async () => { + it('File locked - [C297617]', async () => { await testUtil.checkToolbarActions(testData.fileLocked.name, testData.fileLocked.toolbarPrimary, testData.fileLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileLocked.name, testData.fileLocked.contextMenu); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C291816]', async () => { await testUtil.checkToolbarActions(testData.fileFavLocked.name, testData.fileFavLocked.toolbarPrimary, testData.fileFavLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileFavLocked.name, testData.fileFavLocked.contextMenu); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C280453]', async () => { await testUtil.checkToolbarActions(testData.fileSharedLocked.name, testData.fileSharedLocked.toolbarPrimary, testData.fileSharedLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileSharedLocked.name, testData.fileSharedLocked.contextMenu); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C280454]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.toolbarPrimary, testData.fileSharedFavLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.contextMenu); }); @@ -109,12 +109,12 @@ export function personalFilesTests(parentName?: string) { describe('on a folder', () => { - it('Folder not favorite - []', async () => { + it('Folder not favorite - [C213123]', async () => { await testUtil.checkToolbarActions(testData.folder.name, testData.folder.toolbarPrimary, testData.folder.toolbarMore); await testUtil.checkContextMenu(testData.folder.name, testData.folder.contextMenu); }); - it('Folder favorite - []', async () => { + it('Folder favorite - [C280451]', async () => { await testUtil.checkToolbarActions(testData.folderFav.name, testData.folderFav.toolbarPrimary, testData.folderFav.toolbarMore); await testUtil.checkContextMenu(testData.folderFav.name, testData.folderFav.contextMenu); }); @@ -126,12 +126,12 @@ export function personalFilesTests(parentName?: string) { await testUtil.checkMultipleSelToolbarActions([ testData.fileDocx.name, testData.fileDocxSharedFav.name ], testData.multipleSel.toolbarPrimary, testData.multipleSel.toolbarMore); }); - it('multiple files - all favorite - []', async () => { + it('multiple files - all favorite - [C297619]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileDocxFav.name, testData.fileDocxSharedFav.name ], testData.multipleSelAllFav.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileDocxFav.name, testData.fileDocxSharedFav.name ], testData.multipleSel.toolbarPrimary, testData.multipleSelAllFav.toolbarMore); }); - it('multiple locked files - [C297619]', async () => { + it('multiple locked files - [C326688]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileLocked.name, testData.fileSharedFavLocked.name ], testData.multipleSel.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileLocked.name, testData.fileSharedFavLocked.name ], testData.multipleSel.toolbarPrimary, testData.multipleSel.toolbarMore); }); diff --git a/e2e/suites/actions-available/files-folders/recent-files.ts b/e2e/suites/actions-available/files-folders/recent-files.ts index e3a43d967..de1243444 100755 --- a/e2e/suites/actions-available/files-folders/recent-files.ts +++ b/e2e/suites/actions-available/files-folders/recent-files.ts @@ -42,62 +42,62 @@ export function recentFilesTests() { }); describe('on single selection', () => { - it('File Office - []', async () => { + it('File Office - [C297625]', async () => { await testUtil.checkToolbarActions(testData.fileDocx.name, testData.fileDocx.toolbarPrimary, testData.fileDocx.toolbarMore); await testUtil.checkContextMenu(testData.fileDocx.name, testData.fileDocx.contextMenu); }); - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C280470]', async () => { await testUtil.checkToolbarActions(testData.fileDocxFav.name, testData.fileDocxFav.toolbarPrimary, testData.fileDocxFav.toolbarMore); await testUtil.checkContextMenu(testData.fileDocxFav.name, testData.fileDocxFav.contextMenu); }); - it('File simple - []', async () => { + it('File simple - [C280471]', async () => { await testUtil.checkToolbarActions(testData.file.name, testData.file.toolbarPrimary, testData.file.toolbarMore); await testUtil.checkContextMenu(testData.file.name, testData.file.contextMenu); }); - it('File favorite - []', async () => { + it('File favorite - [C280615]', async () => { await testUtil.checkToolbarActions(testData.fileFav.name, testData.fileFav.toolbarPrimary, testData.fileFav.toolbarMore); await testUtil.checkContextMenu(testData.fileFav.name, testData.fileFav.contextMenu); }); - it('File Office, shared - []', async () => { + it('File Office, shared - [C297633]', async () => { await testUtil.checkToolbarActions(testData.fileDocxShared.name, testData.fileDocxShared.toolbarPrimary, testData.fileDocxShared.toolbarMore); await testUtil.checkContextMenu(testData.fileDocxShared.name, testData.fileDocxShared.contextMenu); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C280616]', async () => { await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.toolbarPrimary, testData.fileDocxSharedFav.toolbarMore); await testUtil.checkContextMenu(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.contextMenu); }); - it('File shared - []', async () => { + it('File shared - [C280601]', async () => { await testUtil.checkToolbarActions(testData.fileShared.name, testData.fileShared.toolbarPrimary, testData.fileShared.toolbarMore); await testUtil.checkContextMenu(testData.fileShared.name, testData.fileShared.contextMenu); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C297635]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.toolbarPrimary, testData.fileSharedFav.toolbarMore); await testUtil.checkContextMenu(testData.fileSharedFav.name, testData.fileSharedFav.contextMenu); }); - it('File locked - []', async () => { + it('File locked - [C280622]', async () => { await testUtil.checkToolbarActions(testData.fileLocked.name, testData.fileLocked.toolbarPrimary, testData.fileLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileLocked.name, testData.fileLocked.contextMenu); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C280608]', async () => { await testUtil.checkToolbarActions(testData.fileFavLocked.name, testData.fileFavLocked.toolbarPrimary, testData.fileFavLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileFavLocked.name, testData.fileFavLocked.contextMenu); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C297636]', async () => { await testUtil.checkToolbarActions(testData.fileSharedLocked.name, testData.fileSharedLocked.toolbarPrimary, testData.fileSharedLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileSharedLocked.name, testData.fileSharedLocked.contextMenu); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C286324]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.toolbarPrimary, testData.fileSharedFavLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.contextMenu); }); @@ -109,7 +109,7 @@ export function recentFilesTests() { await testUtil.checkMultipleSelToolbarActions([ testData.fileDocxFav.name, testData.fileLocked.name ], testData.multipleSel.toolbarPrimary, testData.multipleSel.toolbarMore); }); - it('multiple files - all favorite - []', async () => { + it('multiple files - all favorite - [C326689]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileDocxFav.name, testData.fileFav.name ], testData.multipleSelAllFav.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileDocxFav.name, testData.fileFav.name ], testData.multipleSel.toolbarPrimary, testData.multipleSelAllFav.toolbarMore); }); diff --git a/e2e/suites/actions-available/files-folders/search-results.ts b/e2e/suites/actions-available/files-folders/search-results.ts index 49b8e7a89..5a3ea878b 100755 --- a/e2e/suites/actions-available/files-folders/search-results.ts +++ b/e2e/suites/actions-available/files-folders/search-results.ts @@ -52,62 +52,62 @@ export function searchResultsTests() { await searchResultsPage.waitForResults(); }); - it('File Office - []', async () => { + it('File Office - [C297637]', async () => { await testUtil.checkToolbarActions(testData.fileDocx.name, testData.fileDocx.searchToolbarPrimary, testData.fileDocx.searchToolbarMore); await testUtil.checkContextMenu(testData.fileDocx.name, testData.fileDocx.searchContextMenu); }); - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C291827]', async () => { await testUtil.checkToolbarActions(testData.fileDocxFav.name, testData.fileDocxFav.searchToolbarPrimary, testData.fileDocxFav.searchToolbarMore); await testUtil.checkContextMenu(testData.fileDocxFav.name, testData.fileDocxFav.searchContextMenu); }); - it('File simple - []', async () => { + it('File simple - [C297638]', async () => { await testUtil.checkToolbarActions(testData.file.name, testData.file.searchToolbarPrimary, testData.file.searchToolbarMore); await testUtil.checkContextMenu(testData.file.name, testData.file.searchContextMenu); }); - it('File favorite - []', async () => { + it('File favorite - [C280661]', async () => { await testUtil.checkToolbarActions(testData.fileFav.name, testData.fileFav.searchToolbarPrimary, testData.fileFav.searchToolbarMore); await testUtil.checkContextMenu(testData.fileFav.name, testData.fileFav.searchContextMenu); }); - it('File Office, shared - []', async () => { + it('File Office, shared - [C297627]', async () => { await testUtil.checkToolbarActions(testData.fileDocxShared.name, testData.fileDocxShared.searchToolbarPrimary, testData.fileDocxShared.searchToolbarMore); await testUtil.checkContextMenu(testData.fileDocxShared.name, testData.fileDocxShared.searchContextMenu); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C280631]', async () => { await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.searchToolbarPrimary, testData.fileDocxSharedFav.searchToolbarMore); await testUtil.checkContextMenu(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.searchContextMenu); }); - it('File shared - []', async () => { + it('File shared - [C280632]', async () => { await testUtil.checkToolbarActions(testData.fileShared.name, testData.fileShared.searchToolbarPrimary, testData.fileShared.searchToolbarMore); await testUtil.checkContextMenu(testData.fileShared.name, testData.fileShared.searchContextMenu); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C280641]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.searchToolbarPrimary, testData.fileSharedFav.searchToolbarMore); await testUtil.checkContextMenu(testData.fileSharedFav.name, testData.fileSharedFav.searchContextMenu); }); - it('File locked - []', async () => { + it('File locked - [C297628]', async () => { await testUtil.checkToolbarActions(testData.fileLocked.name, testData.fileLocked.searchToolbarPrimary, testData.fileLocked.searchToolbarMore); await testUtil.checkContextMenu(testData.fileLocked.name, testData.fileLocked.searchContextMenu); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C280648]', async () => { await testUtil.checkToolbarActions(testData.fileFavLocked.name, testData.fileFavLocked.searchToolbarPrimary, testData.fileFavLocked.searchToolbarMore); await testUtil.checkContextMenu(testData.fileFavLocked.name, testData.fileFavLocked.searchContextMenu); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C280574]', async () => { await testUtil.checkToolbarActions(testData.fileSharedLocked.name, testData.fileSharedLocked.searchToolbarPrimary, testData.fileSharedLocked.searchToolbarMore); await testUtil.checkContextMenu(testData.fileSharedLocked.name, testData.fileSharedLocked.searchContextMenu); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C280642]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.searchToolbarPrimary, testData.fileSharedFavLocked.searchToolbarMore); await testUtil.checkContextMenu(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.searchContextMenu); }); @@ -122,12 +122,12 @@ export function searchResultsTests() { await searchResultsPage.waitForResults(); }); - it('Folder not favorite - []', async () => { + it('Folder not favorite - [C280609]', async () => { await testUtil.checkToolbarActions(testData.folder.name, testData.folder.searchToolbarPrimary, testData.folder.searchToolbarMore); await testUtil.checkContextMenu(testData.folder.name, testData.folder.searchContextMenu); }); - it('Folder favorite - []', async () => { + it('Folder favorite - [C291828]', async () => { await testUtil.checkToolbarActions(testData.folderFav.name, testData.folderFav.searchToolbarPrimary, testData.folderFav.searchToolbarMore); await testUtil.checkContextMenu(testData.folderFav.name, testData.folderFav.searchContextMenu); }); @@ -147,7 +147,7 @@ export function searchResultsTests() { await testUtil.checkMultipleSelToolbarActions([ testData.file.name, testData.fileDocxShared.name ], testData.multipleSel.searchToolbarPrimary, testData.multipleSel.searchToolbarMore); }); - it('multiple files - all favorite - []', async () => { + it('multiple files - all favorite - [C326690]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileDocxFav.name, testData.fileSharedFav.name ], testData.multipleSelAllFav.searchContextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileDocxFav.name, testData.fileSharedFav.name ], testData.multipleSelAllFav.searchToolbarPrimary, testData.multipleSelAllFav.searchToolbarMore); }); diff --git a/e2e/suites/actions-available/files-folders/shared-files.ts b/e2e/suites/actions-available/files-folders/shared-files.ts index 0aacda0dd..afcb4925e 100755 --- a/e2e/suites/actions-available/files-folders/shared-files.ts +++ b/e2e/suites/actions-available/files-folders/shared-files.ts @@ -42,32 +42,32 @@ export function sharedFilesTests() { }); describe('single selection', () => { - it('File Office, shared - []', async () => { + it('File Office, shared - [C297629]', async () => { await testUtil.checkToolbarActions(testData.fileDocxShared.name, testData.fileDocxShared.toolbarPrimary, testData.fileDocxShared.sharedToolbarMore); await testUtil.checkContextMenu(testData.fileDocxShared.name, testData.fileDocxShared.sharedContextMenu); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C280652]', async () => { await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.toolbarPrimary, testData.fileDocxSharedFav.sharedToolbarMore); await testUtil.checkContextMenu(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.sharedContextMenu); }); - it('File shared - []', async () => { + it('File shared - [C297630]', async () => { await testUtil.checkToolbarActions(testData.fileShared.name, testData.fileShared.toolbarPrimary, testData.fileShared.sharedToolbarMore); await testUtil.checkContextMenu(testData.fileShared.name, testData.fileShared.sharedContextMenu); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C286273]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.toolbarPrimary, testData.fileSharedFav.sharedToolbarMore); await testUtil.checkContextMenu(testData.fileSharedFav.name, testData.fileSharedFav.sharedContextMenu); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C286274]', async () => { await testUtil.checkToolbarActions(testData.fileSharedLocked.name, testData.fileSharedLocked.toolbarPrimary, testData.fileSharedLocked.sharedToolbarMore); await testUtil.checkContextMenu(testData.fileSharedLocked.name, testData.fileSharedLocked.sharedContextMenu); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C286275]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.toolbarPrimary, testData.fileSharedFavLocked.sharedToolbarMore); await testUtil.checkContextMenu(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.sharedContextMenu); }); @@ -79,7 +79,7 @@ export function sharedFilesTests() { await testUtil.checkMultipleSelToolbarActions([ testData.fileShared.name, testData.fileSharedFav.name ], testData.multipleSel.toolbarPrimary, testData.multipleSel.toolbarMore); }); - it('multiple files - all favorite - []', async () => { + it('multiple files - all favorite - [C326691]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileSharedFav.name, testData.fileSharedFavLocked.name ], testData.multipleSelAllFav.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileSharedFav.name, testData.fileSharedFavLocked.name ], testData.multipleSelAllFav.toolbarPrimary, testData.multipleSelAllFav.toolbarMore); }); diff --git a/e2e/suites/actions-available/files-folders/viewer.ts b/e2e/suites/actions-available/files-folders/viewer.ts index a03f0455b..9c6a9babc 100755 --- a/e2e/suites/actions-available/files-folders/viewer.ts +++ b/e2e/suites/actions-available/files-folders/viewer.ts @@ -56,51 +56,51 @@ export function viewerTests(parentName?: string) { await dataTable.waitForHeader(); }); - it('File Office - []', async () => { + it('File Office - [C282025]', async () => { await testUtil.checkViewerActions(testData.fileDocx.name, testData.fileDocx.viewerToolbarPrimary, testData.fileDocx.viewerToolbarMore); }); - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C297583]', async () => { await testUtil.checkViewerActions(testData.fileDocxFav.name, testData.fileDocxFav.viewerToolbarPrimary, testData.fileDocxFav.viewerToolbarMore); }); - it('File simple - []', async () => { + it('File simple - [C297587]', async () => { await testUtil.checkViewerActions(testData.file.name, testData.file.viewerToolbarPrimary, testData.file.viewerToolbarMore); }); - it('File favorite - []', async () => { + it('File favorite - [C297588]', async () => { await testUtil.checkViewerActions(testData.fileFav.name, testData.fileFav.viewerToolbarPrimary, testData.fileFav.viewerToolbarMore); }); - it('File Office, shared - []', async () => { + it('File Office, shared - [C297597]', async () => { await testUtil.checkViewerActions(testData.fileDocxShared.name, testData.fileDocxShared.viewerToolbarPrimary, testData.fileDocxShared.viewerToolbarMore); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C297598]', async () => { await testUtil.checkViewerActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.viewerToolbarPrimary, testData.fileDocxSharedFav.viewerToolbarMore); }); - it('File shared - []', async () => { + it('File shared - [C291831]', async () => { await testUtil.checkViewerActions(testData.fileShared.name, testData.fileShared.viewerToolbarPrimary, testData.fileShared.viewerToolbarMore); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C297632]', async () => { await testUtil.checkViewerActions(testData.fileSharedFav.name, testData.fileSharedFav.viewerToolbarPrimary, testData.fileSharedFav.viewerToolbarMore); }); - it('File locked - []', async () => { + it('File locked - [C291832]', async () => { await testUtil.checkViewerActions(testData.fileLocked.name, testData.fileLocked.viewerToolbarPrimary, testData.fileLocked.viewerToolbarMore); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C297593]', async () => { await testUtil.checkViewerActions(testData.fileFavLocked.name, testData.fileFavLocked.viewerToolbarPrimary, testData.fileFavLocked.viewerToolbarMore); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C291833]', async () => { await testUtil.checkViewerActions(testData.fileSharedLocked.name, testData.fileSharedLocked.viewerToolbarPrimary, testData.fileSharedLocked.viewerToolbarMore); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C297592]', async () => { await testUtil.checkViewerActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.viewerToolbarPrimary, testData.fileSharedFavLocked.viewerToolbarMore); }); }); @@ -111,51 +111,51 @@ export function viewerTests(parentName?: string) { await page.clickRecentFilesAndWait(); }); - it('File Office - []', async () => { + it('File Office - [C297599]', async () => { await testUtil.checkViewerActions(testData.fileDocx.name, testData.fileDocx.viewerToolbarPrimary, testData.fileDocx.viewerToolbarMore); }); - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C297600]', async () => { await testUtil.checkViewerActions(testData.fileDocxFav.name, testData.fileDocxFav.viewerToolbarPrimary, testData.fileDocxFav.viewerToolbarMore); }); - it('File simple - []', async () => { + it('File simple - [C326692]', async () => { await testUtil.checkViewerActions(testData.file.name, testData.file.viewerToolbarPrimary, testData.file.viewerToolbarMore); }); - it('File favorite - []', async () => { + it('File favorite - [C326693]', async () => { await testUtil.checkViewerActions(testData.fileFav.name, testData.fileFav.viewerToolbarPrimary, testData.fileFav.viewerToolbarMore); }); - it('File Office, shared - []', async () => { + it('File Office, shared - [C326694]', async () => { await testUtil.checkViewerActions(testData.fileDocxShared.name, testData.fileDocxShared.viewerToolbarPrimary, testData.fileDocxShared.viewerToolbarMore); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C326695]', async () => { await testUtil.checkViewerActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.viewerToolbarPrimary, testData.fileDocxSharedFav.viewerToolbarMore); }); - it('File shared - []', async () => { + it('File shared - [C326696]', async () => { await testUtil.checkViewerActions(testData.fileShared.name, testData.fileShared.viewerToolbarPrimary, testData.fileShared.viewerToolbarMore); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C326697]', async () => { await testUtil.checkViewerActions(testData.fileSharedFav.name, testData.fileSharedFav.viewerToolbarPrimary, testData.fileSharedFav.viewerToolbarMore); }); - it('File locked - []', async () => { + it('File locked - [C326698]', async () => { await testUtil.checkViewerActions(testData.fileLocked.name, testData.fileLocked.viewerToolbarPrimary, testData.fileLocked.viewerToolbarMore); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C326701]', async () => { await testUtil.checkViewerActions(testData.fileFavLocked.name, testData.fileFavLocked.viewerToolbarPrimary, testData.fileFavLocked.viewerToolbarMore); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C326699]', async () => { await testUtil.checkViewerActions(testData.fileSharedLocked.name, testData.fileSharedLocked.viewerToolbarPrimary, testData.fileSharedLocked.viewerToolbarMore); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C326700]', async () => { await testUtil.checkViewerActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.viewerToolbarPrimary, testData.fileSharedFavLocked.viewerToolbarMore); }); }); @@ -166,27 +166,27 @@ export function viewerTests(parentName?: string) { await page.clickFavoritesAndWait(); }); - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C326702]', async () => { await testUtil.checkViewerActions(testData.fileDocxFav.name, testData.fileDocxFav.viewerToolbarPrimary, testData.fileDocxFav.viewerToolbarMore); }); - it('File favorite - []', async () => { + it('File favorite - [C326703]', async () => { await testUtil.checkViewerActions(testData.fileFav.name, testData.fileFav.viewerToolbarPrimary, testData.fileFav.viewerToolbarMore); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C326704]', async () => { await testUtil.checkViewerActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.viewerToolbarPrimary, testData.fileDocxSharedFav.viewerToolbarMore); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C326705]', async () => { await testUtil.checkViewerActions(testData.fileSharedFav.name, testData.fileSharedFav.viewerToolbarPrimary, testData.fileSharedFav.viewerToolbarMore); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C326707]', async () => { await testUtil.checkViewerActions(testData.fileFavLocked.name, testData.fileFavLocked.viewerToolbarPrimary, testData.fileFavLocked.viewerToolbarMore); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C326706]', async () => { await testUtil.checkViewerActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.viewerToolbarPrimary, testData.fileSharedFavLocked.viewerToolbarMore); }); }); @@ -197,27 +197,27 @@ export function viewerTests(parentName?: string) { await page.clickSharedFilesAndWait(); }); - it('File Office, shared - []', async () => { + it('File Office, shared - [C326708]', async () => { await testUtil.checkViewerActions(testData.fileDocxShared.name, testData.fileDocxShared.viewerToolbarPrimary, testData.fileDocxShared.viewerToolbarMore); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C326709]', async () => { await testUtil.checkViewerActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.viewerToolbarPrimary, testData.fileDocxSharedFav.viewerToolbarMore); }); - it('File shared - []', async () => { + it('File shared - [C326710]', async () => { await testUtil.checkViewerActions(testData.fileShared.name, testData.fileShared.viewerToolbarPrimary, testData.fileShared.viewerToolbarMore); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C326711]', async () => { await testUtil.checkViewerActions(testData.fileSharedFav.name, testData.fileSharedFav.viewerToolbarPrimary, testData.fileSharedFav.viewerToolbarMore); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C326712]', async () => { await testUtil.checkViewerActions(testData.fileSharedLocked.name, testData.fileSharedLocked.viewerToolbarPrimary, testData.fileSharedLocked.viewerToolbarMore); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C326713]', async () => { await testUtil.checkViewerActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.viewerToolbarPrimary, testData.fileSharedFavLocked.viewerToolbarMore); }); }); @@ -230,51 +230,51 @@ export function viewerTests(parentName?: string) { await searchResultsPage.waitForResults(); }); - it('File Office - []', async () => { + it('File Office - [C326714]', async () => { await testUtil.checkViewerActions(testData.fileDocx.name, testData.fileDocx.viewerToolbarPrimary, testData.fileDocx.searchViewerToolbarMore); }); - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C326715]', async () => { await testUtil.checkViewerActions(testData.fileDocxFav.name, testData.fileDocxFav.viewerToolbarPrimary, testData.fileDocxFav.searchViewerToolbarMore); }); - it('File simple - []', async () => { + it('File simple - [C326716]', async () => { await testUtil.checkViewerActions(testData.file.name, testData.file.viewerToolbarPrimary, testData.file.searchViewerToolbarMore); }); - it('File favorite - []', async () => { + it('File favorite - [C326717]', async () => { await testUtil.checkViewerActions(testData.fileFav.name, testData.fileFav.viewerToolbarPrimary, testData.fileFav.searchViewerToolbarMore); }); - it('File Office, shared - []', async () => { + it('File Office, shared - [C326718]', async () => { await testUtil.checkViewerActions(testData.fileDocxShared.name, testData.fileDocxShared.viewerToolbarPrimary, testData.fileDocxShared.searchViewerToolbarMore); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C326719]', async () => { await testUtil.checkViewerActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.viewerToolbarPrimary, testData.fileDocxSharedFav.searchViewerToolbarMore); }); - it('File shared - []', async () => { + it('File shared - [C326720]', async () => { await testUtil.checkViewerActions(testData.fileShared.name, testData.fileShared.viewerToolbarPrimary, testData.fileShared.searchViewerToolbarMore); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C326721]', async () => { await testUtil.checkViewerActions(testData.fileSharedFav.name, testData.fileSharedFav.viewerToolbarPrimary, testData.fileSharedFav.searchViewerToolbarMore); }); - it('File locked - []', async () => { + it('File locked - [C326722]', async () => { await testUtil.checkViewerActions(testData.fileLocked.name, testData.fileLocked.viewerToolbarPrimary, testData.fileLocked.searchViewerToolbarMore); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C326725]', async () => { await testUtil.checkViewerActions(testData.fileFavLocked.name, testData.fileFavLocked.viewerToolbarPrimary, testData.fileFavLocked.searchViewerToolbarMore); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C326723]', async () => { await testUtil.checkViewerActions(testData.fileSharedLocked.name, testData.fileSharedLocked.viewerToolbarPrimary, testData.fileSharedLocked.searchViewerToolbarMore); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C326724]', async () => { await testUtil.checkViewerActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.viewerToolbarPrimary, testData.fileSharedFavLocked.searchViewerToolbarMore); }); }); diff --git a/e2e/suites/actions-available/libraries/library.test.ts b/e2e/suites/actions-available/libraries/library.test.ts index a6004e9db..d650b5056 100755 --- a/e2e/suites/actions-available/libraries/library.test.ts +++ b/e2e/suites/actions-available/libraries/library.test.ts @@ -120,39 +120,33 @@ describe('Library actions : ', () => { await Utils.pressEscape(); }); - it('Public library, user is a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.publicUserMemberFav.name, testData.publicUserMemberFav.toolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.publicUserMemberFav.name, testData.publicUserMemberFav.toolbarMore); + it('Public library, user is a member, favorite - [C213135]', async () => { + await testUtil.checkToolbarActions(testData.publicUserMemberFav.name, testData.publicUserMemberFav.toolbarPrimary, testData.publicUserMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.publicUserMemberFav.name, testData.publicUserMemberFav.contextMenu); }); - it('Private library, user is a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.privateUserMemberFav.name, testData.privateUserMemberFav.toolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.privateUserMemberFav.name, testData.privateUserMemberFav.toolbarMore); + it('Private library, user is a member, favorite - [C290080]', async () => { + await testUtil.checkToolbarActions(testData.privateUserMemberFav.name, testData.privateUserMemberFav.toolbarPrimary, testData.privateUserMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.privateUserMemberFav.name, testData.privateUserMemberFav.contextMenu); }); - it('Moderated library, user is a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.moderatedUserMemberFav.name, testData.moderatedUserMemberFav.toolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.moderatedUserMemberFav.name, testData.moderatedUserMemberFav.toolbarMore); + it('Moderated library, user is a member, favorite - [C326676]', async () => { + await testUtil.checkToolbarActions(testData.moderatedUserMemberFav.name, testData.moderatedUserMemberFav.toolbarPrimary, testData.moderatedUserMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.moderatedUserMemberFav.name, testData.moderatedUserMemberFav.contextMenu); }); - it('Public library, user is a member, not favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.publicUserMemberNotFav.name, testData.publicUserMemberNotFav.toolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.publicUserMemberNotFav.name, testData.publicUserMemberNotFav.toolbarMore); + it('Public library, user is a member, not favorite - [C326677]', async () => { + await testUtil.checkToolbarActions(testData.publicUserMemberNotFav.name, testData.publicUserMemberNotFav.toolbarPrimary, testData.publicUserMemberNotFav.toolbarMore); await testUtil.checkContextMenu(testData.publicUserMemberNotFav.name, testData.publicUserMemberNotFav.contextMenu); }); - it('Private library, user is a member, not favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.privateUserMemberNotFav.name, testData.privateUserMemberNotFav.toolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.privateUserMemberNotFav.name, testData.privateUserMemberNotFav.toolbarMore); + it('Private library, user is a member, not favorite - [C326678]', async () => { + await testUtil.checkToolbarActions(testData.privateUserMemberNotFav.name, testData.privateUserMemberNotFav.toolbarPrimary, testData.privateUserMemberNotFav.toolbarMore); await testUtil.checkContextMenu(testData.privateUserMemberNotFav.name, testData.privateUserMemberNotFav.contextMenu); }); - it('Moderated library, user is a member, not favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.moderatedUserMemberNotFav.name, testData.moderatedUserMemberNotFav.toolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.moderatedUserMemberNotFav.name, testData.moderatedUserMemberNotFav.toolbarMore); + it('Moderated library, user is a member, not favorite - [C326679]', async () => { + await testUtil.checkToolbarActions(testData.moderatedUserMemberNotFav.name, testData.moderatedUserMemberNotFav.toolbarPrimary, testData.moderatedUserMemberNotFav.toolbarMore); await testUtil.checkContextMenu(testData.moderatedUserMemberNotFav.name, testData.moderatedUserMemberNotFav.contextMenu); }); @@ -169,39 +163,33 @@ describe('Library actions : ', () => { await Utils.pressEscape(); }); - it('Public library, user is a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.publicUserMemberFav.name, testData.publicUserMemberFav.toolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.publicUserMemberFav.name, testData.publicUserMemberFav.toolbarMore); + it('Public library, user is a member, favorite - [C289892]', async () => { + await testUtil.checkToolbarActions(testData.publicUserMemberFav.name, testData.publicUserMemberFav.toolbarPrimary, testData.publicUserMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.publicUserMemberFav.name, testData.publicUserMemberFav.contextMenu); }); - it('Private library, user is a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.privateUserMemberFav.name, testData.privateUserMemberFav.toolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.privateUserMemberFav.name, testData.privateUserMemberFav.toolbarMore); + it('Private library, user is a member, favorite - [C290090]', async () => { + await testUtil.checkToolbarActions(testData.privateUserMemberFav.name, testData.privateUserMemberFav.toolbarPrimary, testData.privateUserMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.privateUserMemberFav.name, testData.privateUserMemberFav.contextMenu); }); - it('Moderated library, user is a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.moderatedUserMemberFav.name, testData.moderatedUserMemberFav.toolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.moderatedUserMemberFav.name, testData.moderatedUserMemberFav.toolbarMore); + it('Moderated library, user is a member, favorite - [C290091]', async () => { + await testUtil.checkToolbarActions(testData.moderatedUserMemberFav.name, testData.moderatedUserMemberFav.toolbarPrimary, testData.moderatedUserMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.moderatedUserMemberFav.name, testData.moderatedUserMemberFav.contextMenu); }); - it('Public library, user not a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.publicNotMemberFav.name, testData.publicNotMemberFav.toolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.publicNotMemberFav.name, testData.publicNotMemberFav.toolbarMore); + it('Public library, user not a member, favorite - [C290081]', async () => { + await testUtil.checkToolbarActions(testData.publicNotMemberFav.name, testData.publicNotMemberFav.toolbarPrimary, testData.publicNotMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.publicNotMemberFav.name, testData.publicNotMemberFav.contextMenu); }); - it('Moderated library, user not a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.moderatedNotMemberFav.name, testData.moderatedNotMemberFav.toolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.moderatedNotMemberFav.name, testData.moderatedNotMemberFav.toolbarMore); + it('Moderated library, user not a member, favorite - [C290082]', async () => { + await testUtil.checkToolbarActions(testData.moderatedNotMemberFav.name, testData.moderatedNotMemberFav.toolbarPrimary, testData.moderatedNotMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.moderatedNotMemberFav.name, testData.moderatedNotMemberFav.contextMenu); }); - it('Moderated library, user requested to join, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.moderatedRequestedJoinFav.name, testData.moderatedRequestedJoinFav.toolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.moderatedRequestedJoinFav.name, testData.moderatedRequestedJoinFav.toolbarMore); + it('Moderated library, user requested to join, favorite - [C290089]', async () => { + await testUtil.checkToolbarActions(testData.moderatedRequestedJoinFav.name, testData.moderatedRequestedJoinFav.toolbarPrimary, testData.moderatedRequestedJoinFav.toolbarMore); await testUtil.checkContextMenu(testData.moderatedRequestedJoinFav.name, testData.moderatedRequestedJoinFav.contextMenu); }); }); @@ -220,75 +208,63 @@ describe('Library actions : ', () => { await Utils.pressEscape(); }); - it('Public library, user is a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.publicUserMemberFav.name, testData.publicUserMemberFav.searchToolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.publicUserMemberFav.name, testData.publicUserMemberFav.toolbarMore); + it('Public library, user is a member, favorite - [C290084]', async () => { + await testUtil.checkToolbarActions(testData.publicUserMemberFav.name, testData.publicUserMemberFav.searchToolbarPrimary, testData.publicUserMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.publicUserMemberFav.name, testData.publicUserMemberFav.contextMenu); }); - it('Private library, user is a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.privateUserMemberFav.name, testData.privateUserMemberFav.searchToolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.privateUserMemberFav.name, testData.privateUserMemberFav.toolbarMore); + it('Private library, user is a member, favorite - [C290085]', async () => { + await testUtil.checkToolbarActions(testData.privateUserMemberFav.name, testData.privateUserMemberFav.searchToolbarPrimary, testData.privateUserMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.privateUserMemberFav.name, testData.privateUserMemberFav.contextMenu); }); - it('Moderated library, user is a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.moderatedUserMemberFav.name, testData.moderatedUserMemberFav.searchToolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.moderatedUserMemberFav.name, testData.moderatedUserMemberFav.toolbarMore); + it('Moderated library, user is a member, favorite - [C290086]', async () => { + await testUtil.checkToolbarActions(testData.moderatedUserMemberFav.name, testData.moderatedUserMemberFav.searchToolbarPrimary, testData.moderatedUserMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.moderatedUserMemberFav.name, testData.moderatedUserMemberFav.contextMenu); }); - it('Public library, user is a member, not favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.publicUserMemberNotFav.name, testData.publicUserMemberNotFav.searchToolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.publicUserMemberNotFav.name, testData.publicUserMemberNotFav.toolbarMore); + it('Public library, user is a member, not favorite - [C291812]', async () => { + await testUtil.checkToolbarActions(testData.publicUserMemberNotFav.name, testData.publicUserMemberNotFav.searchToolbarPrimary, testData.publicUserMemberNotFav.toolbarMore); await testUtil.checkContextMenu(testData.publicUserMemberNotFav.name, testData.publicUserMemberNotFav.contextMenu); }); - it('Private library, user is a member, not favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.privateUserMemberNotFav.name, testData.privateUserMemberNotFav.searchToolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.privateUserMemberNotFav.name, testData.privateUserMemberNotFav.toolbarMore); + it('Private library, user is a member, not favorite - [C291813]', async () => { + await testUtil.checkToolbarActions(testData.privateUserMemberNotFav.name, testData.privateUserMemberNotFav.searchToolbarPrimary, testData.privateUserMemberNotFav.toolbarMore); await testUtil.checkContextMenu(testData.privateUserMemberNotFav.name, testData.privateUserMemberNotFav.contextMenu); }); - it('Moderated library, user is a member, not favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.moderatedUserMemberNotFav.name, testData.moderatedUserMemberNotFav.searchToolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.moderatedUserMemberNotFav.name, testData.moderatedUserMemberNotFav.toolbarMore); + it('Moderated library, user is a member, not favorite - [C291814]', async () => { + await testUtil.checkToolbarActions(testData.moderatedUserMemberNotFav.name, testData.moderatedUserMemberNotFav.searchToolbarPrimary, testData.moderatedUserMemberNotFav.toolbarMore); await testUtil.checkContextMenu(testData.moderatedUserMemberNotFav.name, testData.moderatedUserMemberNotFav.contextMenu); }); - it('Public library, user not a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.publicNotMemberFav.name, testData.publicNotMemberFav.searchToolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.publicNotMemberFav.name, testData.publicNotMemberFav.toolbarMore); + it('Public library, user not a member, favorite - [C326680]', async () => { + await testUtil.checkToolbarActions(testData.publicNotMemberFav.name, testData.publicNotMemberFav.searchToolbarPrimary, testData.publicNotMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.publicNotMemberFav.name, testData.publicNotMemberFav.contextMenu); }); - it('Moderated library, user not a member, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.moderatedNotMemberFav.name, testData.moderatedNotMemberFav.searchToolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.moderatedNotMemberFav.name, testData.moderatedNotMemberFav.toolbarMore); + it('Moderated library, user not a member, favorite - [C326681]', async () => { + await testUtil.checkToolbarActions(testData.moderatedNotMemberFav.name, testData.moderatedNotMemberFav.searchToolbarPrimary, testData.moderatedNotMemberFav.toolbarMore); await testUtil.checkContextMenu(testData.moderatedNotMemberFav.name, testData.moderatedNotMemberFav.contextMenu); }); - it('Public library, user not a member, not favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.publicNotMemberNotFav.name, testData.publicNotMemberNotFav.searchToolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.publicNotMemberNotFav.name, testData.publicNotMemberNotFav.toolbarMore); + it('Public library, user not a member, not favorite - [C326682]', async () => { + await testUtil.checkToolbarActions(testData.publicNotMemberNotFav.name, testData.publicNotMemberNotFav.searchToolbarPrimary, testData.publicNotMemberNotFav.toolbarMore); await testUtil.checkContextMenu(testData.publicNotMemberNotFav.name, testData.publicNotMemberNotFav.contextMenu); }); - it('Moderated library, user not a member, not favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.moderatedNotMemberNotFav.name, testData.moderatedNotMemberNotFav.searchToolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.moderatedNotMemberNotFav.name, testData.moderatedNotMemberNotFav.toolbarMore); + it('Moderated library, user not a member, not favorite - [C326683]', async () => { + await testUtil.checkToolbarActions(testData.moderatedNotMemberNotFav.name, testData.moderatedNotMemberNotFav.searchToolbarPrimary, testData.moderatedNotMemberNotFav.toolbarMore); await testUtil.checkContextMenu(testData.moderatedNotMemberNotFav.name, testData.moderatedNotMemberNotFav.contextMenu); }); - it('Moderated library, user requested to join, favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.moderatedRequestedJoinFav.name, testData.moderatedRequestedJoinFav.searchToolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.moderatedRequestedJoinFav.name, testData.moderatedRequestedJoinFav.toolbarMore); + it('Moderated library, user requested to join, favorite - [C326685]', async () => { + await testUtil.checkToolbarActions(testData.moderatedRequestedJoinFav.name, testData.moderatedRequestedJoinFav.searchToolbarPrimary, testData.moderatedRequestedJoinFav.toolbarMore); await testUtil.checkContextMenu(testData.moderatedRequestedJoinFav.name, testData.moderatedRequestedJoinFav.contextMenu); }); - it('Moderated library, user requested to join, not favorite - []', async () => { - await testUtil.checkToolbarPrimary(testData.moderatedRequestedJoinNotFav.name, testData.moderatedRequestedJoinNotFav.searchToolbarPrimary); - await testUtil.checkToolbarMoreActions(testData.moderatedRequestedJoinNotFav.name, testData.moderatedRequestedJoinNotFav.toolbarMore); + it('Moderated library, user requested to join, not favorite - [C326684]', async () => { + await testUtil.checkToolbarActions(testData.moderatedRequestedJoinNotFav.name, testData.moderatedRequestedJoinNotFav.searchToolbarPrimary, testData.moderatedRequestedJoinNotFav.toolbarMore); await testUtil.checkContextMenu(testData.moderatedRequestedJoinNotFav.name, testData.moderatedRequestedJoinNotFav.contextMenu); }); }); @@ -303,12 +279,12 @@ describe('Library actions : ', () => { await Utils.pressEscape(); }); - it('single library - []', async () => { + it('single library - [C326686]', async () => { await testUtil.checkToolbarPrimary(testData.siteInTrash.name, testData.siteInTrash.trashActions); await testUtil.checkContextMenu(testData.siteInTrash.name, testData.siteInTrash.trashActions); }); - it('multiple libraries - []', async () => { + it('multiple libraries - [C326687]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.siteInTrash.name, testData.site2InTrash.name ], testData.trashActions); await testUtil.checkMultipleSelToolbarPrimary([ testData.siteInTrash.name, testData.site2InTrash.name ], testData.trashActions); }); diff --git a/e2e/suites/actions-available/special-permissions/favorites.ts b/e2e/suites/actions-available/special-permissions/favorites.ts index 88c669828..f0ca7949c 100755 --- a/e2e/suites/actions-available/special-permissions/favorites.ts +++ b/e2e/suites/actions-available/special-permissions/favorites.ts @@ -47,32 +47,32 @@ export function favoritesTests() { describe('on a file', () => { - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C286311]', async () => { await testUtil.checkToolbarActions(testData.fileDocxFav.name, testData.fileDocxFav.toolbarPrimary, testData.fileDocxFav.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileDocxFav.name, testData.fileDocxFav.favoritesContextMenu); }); - it('File favorite - []', async () => { + it('File favorite - [C306991]', async () => { await testUtil.checkToolbarActions(testData.fileFav.name, testData.fileFav.toolbarPrimary, testData.fileFav.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileFav.name, testData.fileFav.favoritesContextMenu); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C279187]', async () => { await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.favoritesToolbarPrimary, testData.fileDocxSharedFav.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.favoritesContextMenu); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C280053]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.favoritesToolbarPrimary, testData.fileSharedFav.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileSharedFav.name, testData.fileSharedFav.favoritesContextMenu); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C280050]', async () => { await testUtil.checkToolbarActions(testData.fileFavLocked.name, testData.fileFavLocked.toolbarPrimary, testData.fileFavLocked.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileFavLocked.name, testData.fileFavLocked.favoritesContextMenu); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C325011]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.favoritesToolbarPrimary, testData.fileSharedFavLocked.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.favoritesContextMenu); }); @@ -81,7 +81,7 @@ export function favoritesTests() { describe('on a folder', () => { - it('Folder favorite - []', async () => { + it('Folder favorite - [C325012]', async () => { await testUtil.checkToolbarActions(testData.folderFav.name, testData.folderFav.toolbarPrimary, testData.folderFav.favoritesToolbarMore); await testUtil.checkContextMenu(testData.folderFav.name, testData.folderFav.favoritesContextMenu); }); @@ -90,27 +90,27 @@ export function favoritesTests() { describe('on multiple selection', () => { - it('multiple files - []', async () => { + it('multiple files - [C325046]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileDocxFav.name, testData.fileDocxSharedFav.name ], testData.multipleSelAllFav.favoritesContextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileDocxFav.name, testData.fileDocxSharedFav.name ], testData.multipleSelAllFav.toolbarPrimary, testData.multipleSelAllFav.favoritesToolbarMore); }); - it('multiple locked files - []', async () => { + it('multiple locked files - [C217145]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileFavLocked.name, testData.fileSharedFavLocked.name ], testData.multipleSelAllFav.favoritesContextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileFavLocked.name, testData.fileSharedFavLocked.name ], testData.multipleSelAllFav.toolbarPrimary, testData.multipleSelAllFav.favoritesToolbarMore); }); - it('multiple folders - []', async () => { + it('multiple folders - [C213196]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.folderFav.name, testData.folderFav2.name ], testData.multipleSelAllFav.favoritesContextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.folderFav.name, testData.folderFav2.name ], testData.multipleSelAllFav.toolbarPrimary, testData.multipleSelAllFav.favoritesToolbarMore); }); - it('both files and folders - []', async () => { + it('both files and folders - [C217146]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileFav.name, testData.folderFav.name ], testData.multipleSelAllFav.favoritesContextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileFav.name, testData.folderFav.name ], testData.multipleSelAllFav.toolbarPrimary, testData.multipleSelAllFav.favoritesToolbarMore); }); - it('multiple files with different granular permissions - []', async () => { + it('multiple files with different granular permissions - [C213193]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileFav.name, testData.fileGranularPermission ], testData.multipleSelAllFav.favoritesContextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileFav.name, testData.fileGranularPermission ], testData.multipleSelAllFav.toolbarPrimary, testData.multipleSelAllFav.favoritesToolbarMore); }); diff --git a/e2e/suites/actions-available/special-permissions/my-libraries.ts b/e2e/suites/actions-available/special-permissions/my-libraries.ts index ad8cf6bd5..9f04dc589 100755 --- a/e2e/suites/actions-available/special-permissions/my-libraries.ts +++ b/e2e/suites/actions-available/special-permissions/my-libraries.ts @@ -50,62 +50,62 @@ export function librariesTests(siteName?: string) { describe('on a file', () => { - it('File Office - []', async () => { + it('File Office - [C280476]', async () => { await testUtil.checkToolbarActions(testData.fileDocx.name, testData.fileDocx.toolbarPrimary, testData.fileDocx.toolbarMore); await testUtil.checkContextMenu(testData.fileDocx.name, testData.fileDocx.contextMenu); }); - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C280455]', async () => { await testUtil.checkToolbarActions(testData.fileDocxFav.name, testData.fileDocxFav.toolbarPrimary, testData.fileDocxFav.toolbarMore); await testUtil.checkContextMenu(testData.fileDocxFav.name, testData.fileDocxFav.contextMenu); - }); + }); - it('File simple - []', async () => { + it('File simple - [C280444]', async () => { await testUtil.checkToolbarActions(testData.file.name, testData.file.toolbarPrimary, testData.file.toolbarMore); await testUtil.checkContextMenu(testData.file.name, testData.file.contextMenu); - }); + }); - it('File favorite - []', async () => { + it('File favorite - [C280464]', async () => { await testUtil.checkToolbarActions(testData.fileFav.name, testData.fileFav.toolbarPrimary, testData.fileFav.toolbarMore); await testUtil.checkContextMenu(testData.fileFav.name, testData.fileFav.contextMenu); - }); + }); - it('File Office, shared - []', async () => { + it('File Office, shared - [C280465]', async () => { await testUtil.checkToolbarActions(testData.fileDocxShared.name, testData.fileDocxShared.toolbarPrimary, testData.fileDocxShared.toolbarMore); await testUtil.checkContextMenu(testData.fileDocxShared.name, testData.fileDocxShared.contextMenu); - }); + }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C280466]', async () => { await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.toolbarPrimary, testData.fileDocxSharedFav.toolbarMore); await testUtil.checkContextMenu(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.contextMenu); }); - it('File shared - []', async () => { + it('File shared - [C280599]', async () => { await testUtil.checkToolbarActions(testData.fileShared.name, testData.fileShared.toolbarPrimary, testData.fileShared.toolbarMore); await testUtil.checkContextMenu(testData.fileShared.name, testData.fileShared.contextMenu); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C280600]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.toolbarPrimary, testData.fileSharedFav.toolbarMore); await testUtil.checkContextMenu(testData.fileSharedFav.name, testData.fileSharedFav.contextMenu); - }); + }); - it('File locked - []', async () => { + it('File locked - [C280647]', async () => { await testUtil.checkToolbarActions(testData.fileLocked.name, testData.fileLocked.toolbarPrimary, testData.fileLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileLocked.name, testData.fileLocked.contextMenu); - }); + }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C280477]', async () => { await testUtil.checkToolbarActions(testData.fileFavLocked.name, testData.fileFavLocked.toolbarPrimary, testData.fileFavLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileFavLocked.name, testData.fileFavLocked.contextMenu); - }); + }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C280666]', async () => { await testUtil.checkToolbarActions(testData.fileSharedLocked.name, testData.fileSharedLocked.toolbarPrimary, testData.fileSharedLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileSharedLocked.name, testData.fileSharedLocked.contextMenu); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C280669]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.toolbarPrimary, testData.fileSharedFavLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.contextMenu); }); @@ -114,12 +114,12 @@ export function librariesTests(siteName?: string) { describe('on a folder', () => { - it('Folder not favorite - []', async () => { + it('Folder not favorite - [C280456]', async () => { await testUtil.checkToolbarActions(testData.folder.name, testData.folder.toolbarPrimary, testData.folder.toolbarMore); await testUtil.checkContextMenu(testData.folder.name, testData.folder.contextMenu); }); - it('Folder favorite - []', async () => { + it('Folder favorite - [C286284]', async () => { await testUtil.checkToolbarActions(testData.folderFav.name, testData.folderFav.toolbarPrimary, testData.folderFav.toolbarMore); await testUtil.checkContextMenu(testData.folderFav.name, testData.folderFav.contextMenu); }); @@ -127,32 +127,32 @@ export function librariesTests(siteName?: string) { describe('on multiple selection', () => { - it('multiple files - []', async () => { + it('multiple files - [C286264]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileDocx.name, testData.fileDocxSharedFav.name ], testData.multipleSel.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileDocx.name, testData.fileDocxSharedFav.name ], testData.multipleSel.toolbarPrimary, testData.multipleSel.toolbarMore); }); - it('multiple files - all favorite - []', async () => { + it('multiple files - all favorite - [C286283]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileDocxFav.name, testData.fileDocxSharedFav.name ], testData.multipleSelAllFav.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileDocxFav.name, testData.fileDocxSharedFav.name ], testData.multipleSel.toolbarPrimary, testData.multipleSelAllFav.toolbarMore); }); - it('multiple locked files - []', async () => { + it('multiple locked files - [C280478]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileLocked.name, testData.fileSharedFavLocked.name ], testData.multipleSel.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileLocked.name, testData.fileSharedFavLocked.name ], testData.multipleSel.toolbarPrimary, testData.multipleSel.toolbarMore); }); - it('multiple folders - []', async () => { + it('multiple folders - [C213121]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.folderFav.name, testData.folder.name ], testData.multipleSel.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.folderFav.name, testData.folder.name ], testData.multipleSel.toolbarPrimary, testData.multipleSel.toolbarMore); }); - it('both files and folders - []', async () => { + it('both files and folders - [C286266]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.file.name, testData.folder.name ], testData.multipleSel.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.file.name, testData.folder.name ], testData.multipleSel.toolbarPrimary, testData.multipleSel.toolbarMore); }); - it('multiple files with different granular permissions - []', async () => { + it('multiple files with different granular permissions - [C286285]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileDocxFav.name, testData.fileGranularPermission ], testData.multipleSelAllFav.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileDocxFav.name, testData.fileGranularPermission ], testData.multipleSel.toolbarPrimary, testData.multipleSelAllFav.toolbarMore); }); diff --git a/e2e/suites/actions-available/special-permissions/search-results.ts b/e2e/suites/actions-available/special-permissions/search-results.ts index 1c2920044..99e601456 100755 --- a/e2e/suites/actions-available/special-permissions/search-results.ts +++ b/e2e/suites/actions-available/special-permissions/search-results.ts @@ -52,62 +52,62 @@ export function searchResultsTests() { await searchResultsPage.waitForResults(); }); - it('File Office - []', async () => { + it('File Office - [C286286]', async () => { await testUtil.checkToolbarActions(testData.fileDocx.name, testData.fileDocx.searchToolbarPrimary, testData.fileDocx.toolbarMore); await testUtil.checkContextMenu(testData.fileDocx.name, testData.fileDocx.contextMenu); }); - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C286287]', async () => { await testUtil.checkToolbarActions(testData.fileDocxFav.name, testData.fileDocxFav.searchToolbarPrimary, testData.fileDocxFav.toolbarMore); await testUtil.checkContextMenu(testData.fileDocxFav.name, testData.fileDocxFav.contextMenu); }); - it('File simple - []', async () => { + it('File simple - [C286262]', async () => { await testUtil.checkToolbarActions(testData.file.name, testData.file.searchToolbarPrimary, testData.file.toolbarMore); await testUtil.checkContextMenu(testData.file.name, testData.file.contextMenu); }); - it('File favorite - []', async () => { + it('File favorite - [C286263]', async () => { await testUtil.checkToolbarActions(testData.fileFav.name, testData.fileFav.searchToolbarPrimary, testData.fileFav.toolbarMore); await testUtil.checkContextMenu(testData.fileFav.name, testData.fileFav.contextMenu); }); - it('File Office, shared - []', async () => { + it('File Office, shared - [C286280]', async () => { await testUtil.checkToolbarActions(testData.fileDocxShared.name, testData.fileDocxShared.searchToolbarPrimary, testData.fileDocxShared.toolbarMore); await testUtil.checkContextMenu(testData.fileDocxShared.name, testData.fileDocxShared.contextMenu); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C286281]', async () => { await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.searchToolbarPrimary, testData.fileDocxSharedFav.toolbarMore); await testUtil.checkContextMenu(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.contextMenu); }); - it('File shared - []', async () => { + it('File shared - [C286282]', async () => { await testUtil.checkToolbarActions(testData.fileShared.name, testData.fileShared.searchToolbarPrimary, testData.fileShared.toolbarMore); await testUtil.checkContextMenu(testData.fileShared.name, testData.fileShared.contextMenu); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C291823]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.searchToolbarPrimary, testData.fileSharedFav.toolbarMore); await testUtil.checkContextMenu(testData.fileSharedFav.name, testData.fileSharedFav.contextMenu); }); - it('File locked - []', async () => { + it('File locked - [C291818]', async () => { await testUtil.checkToolbarActions(testData.fileLocked.name, testData.fileLocked.searchToolbarPrimary, testData.fileLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileLocked.name, testData.fileLocked.contextMenu); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C291819]', async () => { await testUtil.checkToolbarActions(testData.fileFavLocked.name, testData.fileFavLocked.searchToolbarPrimary, testData.fileFavLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileFavLocked.name, testData.fileFavLocked.contextMenu); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C291824]', async () => { await testUtil.checkToolbarActions(testData.fileSharedLocked.name, testData.fileSharedLocked.searchToolbarPrimary, testData.fileSharedLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileSharedLocked.name, testData.fileSharedLocked.contextMenu); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C291825]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.searchToolbarPrimary, testData.fileSharedFavLocked.toolbarMore); await testUtil.checkContextMenu(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.contextMenu); }); @@ -123,12 +123,12 @@ export function searchResultsTests() { await searchResultsPage.waitForResults(); }); - it('Folder not favorite - []', async () => { + it('Folder not favorite - [C291826]', async () => { await testUtil.checkToolbarActions(testData.folder.name, testData.folder.searchToolbarPrimary, testData.folder.toolbarMore); await testUtil.checkContextMenu(testData.folder.name, testData.folder.contextMenu); }); - it('Folder favorite - []', async () => { + it('Folder favorite - [C291829]', async () => { await testUtil.checkToolbarActions(testData.folderFav.name, testData.folderFav.searchToolbarPrimary, testData.folderFav.toolbarMore); await testUtil.checkContextMenu(testData.folderFav.name, testData.folderFav.contextMenu); }); @@ -146,28 +146,28 @@ export function searchResultsTests() { await searchResultsPage.waitForResults(); }); - it('multiple files - []', async () => { + it('multiple files - [C291830]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.file.name, testData.fileDocxShared.name ], testData.multipleSel.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.file.name, testData.fileDocxShared.name ], testData.multipleSel.searchToolbarPrimary, testData.multipleSel.toolbarMore); }); - it('multiple files - all favorite - []', async () => { + it('multiple files - all favorite - [C291834]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileDocxFav.name, testData.fileSharedFav.name ], testData.multipleSelAllFav.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileDocxFav.name, testData.fileSharedFav.name ], testData.multipleSel.searchToolbarPrimary, testData.multipleSelAllFav.toolbarMore); }); - it('multiple locked files - []', async () => { + it('multiple locked files - [C291835]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileLocked.name, testData.fileSharedFavLocked.name ], testData.multipleSel.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileLocked.name, testData.fileSharedFavLocked.name ], testData.multipleSel.searchToolbarPrimary, testData.multipleSel.toolbarMore); }); - it('multiple files with different granular permissions - []', async () => { + it('multiple files with different granular permissions - [C286310]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileDocxFav.name, testData.fileGranularPermission ], testData.multipleSelAllFav.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileDocxFav.name, testData.fileGranularPermission ], testData.multipleSel.searchToolbarPrimary, testData.multipleSelAllFav.toolbarMore); }); }); - it('multiple folders - []', async () => { + it('multiple folders - [C291836]', async () => { await page.clickPersonalFiles(); await searchInput.clickSearchButton(); await searchInput.searchFor('folder-'); @@ -176,7 +176,7 @@ export function searchResultsTests() { await testUtil.checkMultipleSelToolbarActions([ testData.folder.name, testData.folderFav.name ], testData.multipleSel.searchToolbarPrimary, testData.multipleSel.toolbarMore); }); - it('both files and folders - []', async () => { + it('both files and folders - [C268128]', async () => { await page.clickPersonalFiles(); await searchInput.clickSearchButton(); await searchInput.searchFor(`=${testData.file.name} or =${testData.folderFav.name}`); diff --git a/e2e/suites/actions-available/special-permissions/shared-files.ts b/e2e/suites/actions-available/special-permissions/shared-files.ts index 0c4b77658..452306681 100755 --- a/e2e/suites/actions-available/special-permissions/shared-files.ts +++ b/e2e/suites/actions-available/special-permissions/shared-files.ts @@ -47,32 +47,32 @@ export function sharedFilesTests() { describe('single selection', () => { - it('File Office, shared - []', async () => { + it('File Office, shared - [C326626]', async () => { await testUtil.checkToolbarActions(testData.fileDocxShared.name, testData.fileDocxShared.toolbarPrimary, testData.fileDocxShared.sharedToolbarMore); await testUtil.checkContextMenu(testData.fileDocxShared.name, testData.fileDocxShared.sharedContextMenu); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C326627]', async () => { await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.toolbarPrimary, testData.fileDocxSharedFav.sharedToolbarMore); await testUtil.checkContextMenu(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.sharedContextMenu); }); - it('File shared - []', async () => { + it('File shared - [C326628]', async () => { await testUtil.checkToolbarActions(testData.fileShared.name, testData.fileShared.toolbarPrimary, testData.fileShared.sharedToolbarMore); await testUtil.checkContextMenu(testData.fileShared.name, testData.fileShared.sharedContextMenu); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C326629]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.toolbarPrimary, testData.fileSharedFav.sharedToolbarMore); await testUtil.checkContextMenu(testData.fileSharedFav.name, testData.fileSharedFav.sharedContextMenu); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C326631]', async () => { await testUtil.checkToolbarActions(testData.fileSharedLocked.name, testData.fileSharedLocked.toolbarPrimary, testData.fileSharedLocked.sharedToolbarMore); await testUtil.checkContextMenu(testData.fileSharedLocked.name, testData.fileSharedLocked.sharedContextMenu); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C326632]', async () => { await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.toolbarPrimary, testData.fileSharedFavLocked.sharedToolbarMore); await testUtil.checkContextMenu(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.sharedContextMenu); }); @@ -81,22 +81,22 @@ export function sharedFilesTests() { describe('multiple selection', () => { - it('multiple files - []', async () => { + it('multiple files - [C326634]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileShared.name, testData.fileSharedFav.name ], testData.multipleSel.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileShared.name, testData.fileSharedFav.name ], testData.multipleSel.toolbarPrimary, testData.multipleSel.toolbarMore); }); - it('multiple files - all favorite - []', async () => { + it('multiple files - all favorite - [C326635]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileSharedFav.name, testData.fileSharedFavLocked.name ], testData.multipleSelAllFav.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileSharedFav.name, testData.fileSharedFavLocked.name ], testData.multipleSel.toolbarPrimary, testData.multipleSelAllFav.toolbarMore); }); - it('multiple locked files - []', async () => { + it('multiple locked files - [C326636]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileSharedLocked.name, testData.fileSharedFavLocked.name ], testData.multipleSel.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileSharedLocked.name, testData.fileSharedFavLocked.name ], testData.multipleSel.toolbarPrimary, testData.multipleSel.toolbarMore); }); - it('multiple files with different granular permissions - []', async () => { + it('multiple files with different granular permissions - [C326639]', async () => { await testUtil.checkMultipleSelContextMenu([ testData.fileSharedFav.name, testData.fileGranularPermission ], testData.multipleSelAllFav.contextMenu); await testUtil.checkMultipleSelToolbarActions([ testData.fileSharedFav.name, testData.fileGranularPermission ], testData.multipleSel.toolbarPrimary, testData.multipleSelAllFav.toolbarMore); }); diff --git a/e2e/suites/actions-available/special-permissions/viewer.ts b/e2e/suites/actions-available/special-permissions/viewer.ts index 445cc0efa..e6ec6b0b0 100755 --- a/e2e/suites/actions-available/special-permissions/viewer.ts +++ b/e2e/suites/actions-available/special-permissions/viewer.ts @@ -52,51 +52,51 @@ export function viewerTests(siteName?: string) { await dataTable.waitForHeader(); }); - it('File Office - []', async () => { + it('File Office - [C326622]', async () => { await testUtil.checkViewerActions(testData.fileDocx.name, testData.fileDocx.viewerToolbarPrimary, testData.fileDocx.viewerToolbarMore); }); - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C326623]', async () => { await testUtil.checkViewerActions(testData.fileDocxFav.name, testData.fileDocxFav.viewerToolbarPrimary, testData.fileDocxFav.viewerToolbarMore); }); - it('File simple - []', async () => { + it('File simple - [C326624]', async () => { await testUtil.checkViewerActions(testData.file.name, testData.file.viewerToolbarPrimary, testData.file.viewerToolbarMore); }); - it('File favorite - []', async () => { + it('File favorite - [C326625]', async () => { await testUtil.checkViewerActions(testData.fileFav.name, testData.fileFav.viewerToolbarPrimary, testData.fileFav.viewerToolbarMore); }); - it('File Office, shared - []', async () => { + it('File Office, shared - [C326637]', async () => { await testUtil.checkViewerActions(testData.fileDocxShared.name, testData.fileDocxShared.viewerToolbarPrimary, testData.fileDocxShared.viewerToolbarMore); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C326638]', async () => { await testUtil.checkViewerActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.viewerToolbarPrimary, testData.fileDocxSharedFav.viewerToolbarMore); }); - it('File shared - []', async () => { + it('File shared - [C326648]', async () => { await testUtil.checkViewerActions(testData.fileShared.name, testData.fileShared.viewerToolbarPrimary, testData.fileShared.viewerToolbarMore); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C326649]', async () => { await testUtil.checkViewerActions(testData.fileSharedFav.name, testData.fileSharedFav.viewerToolbarPrimary, testData.fileSharedFav.viewerToolbarMore); }); - it('File locked - []', async () => { + it('File locked - [C326630]', async () => { await testUtil.checkViewerActions(testData.fileLocked.name, testData.fileLocked.viewerToolbarPrimary, testData.fileLocked.viewerToolbarMore); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C326633]', async () => { await testUtil.checkViewerActions(testData.fileFavLocked.name, testData.fileFavLocked.viewerToolbarPrimary, testData.fileFavLocked.viewerToolbarMore); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C326650]', async () => { await testUtil.checkViewerActions(testData.fileSharedLocked.name, testData.fileSharedLocked.viewerToolbarPrimary, testData.fileSharedLocked.viewerToolbarMore); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C326651]', async () => { await testUtil.checkViewerActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.viewerToolbarPrimary, testData.fileSharedFavLocked.viewerToolbarMore); }); @@ -108,27 +108,27 @@ export function viewerTests(siteName?: string) { await page.clickFavoritesAndWait(); }); - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C326652]', async () => { await testUtil.checkViewerActions(testData.fileDocxFav.name, testData.fileDocxFav.viewerToolbarPrimary, testData.fileDocxFav.viewerToolbarMore); }); - it('File favorite - []', async () => { + it('File favorite - [C326653]', async () => { await testUtil.checkViewerActions(testData.fileFav.name, testData.fileFav.viewerToolbarPrimary, testData.fileFav.viewerToolbarMore); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C326655]', async () => { await testUtil.checkViewerActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.viewerToolbarPrimary, testData.fileDocxSharedFav.viewerToolbarMore); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C326656]', async () => { await testUtil.checkViewerActions(testData.fileSharedFav.name, testData.fileSharedFav.viewerToolbarPrimary, testData.fileSharedFav.viewerToolbarMore); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C326654]', async () => { await testUtil.checkViewerActions(testData.fileFavLocked.name, testData.fileFavLocked.viewerToolbarPrimary, testData.fileFavLocked.viewerToolbarMore); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C326657]', async () => { await testUtil.checkViewerActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.viewerToolbarPrimary, testData.fileSharedFavLocked.viewerToolbarMore); }); @@ -140,27 +140,27 @@ export function viewerTests(siteName?: string) { await page.clickSharedFilesAndWait(); }); - it('File Office, shared - []', async () => { + it('File Office, shared - [C326658]', async () => { await testUtil.checkViewerActions(testData.fileDocxShared.name, testData.fileDocxShared.viewerToolbarPrimary, testData.fileDocxShared.viewerToolbarMore); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C326659]', async () => { await testUtil.checkViewerActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.viewerToolbarPrimary, testData.fileDocxSharedFav.viewerToolbarMore); }); - it('File shared - []', async () => { + it('File shared - [C326660]', async () => { await testUtil.checkViewerActions(testData.fileShared.name, testData.fileShared.viewerToolbarPrimary, testData.fileShared.viewerToolbarMore); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C326661]', async () => { await testUtil.checkViewerActions(testData.fileSharedFav.name, testData.fileSharedFav.viewerToolbarPrimary, testData.fileSharedFav.viewerToolbarMore); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C326662]', async () => { await testUtil.checkViewerActions(testData.fileSharedLocked.name, testData.fileSharedLocked.viewerToolbarPrimary, testData.fileSharedLocked.viewerToolbarMore); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C326663]', async () => { await testUtil.checkViewerActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.viewerToolbarPrimary, testData.fileSharedFavLocked.viewerToolbarMore); }); @@ -174,51 +174,51 @@ export function viewerTests(siteName?: string) { await searchResultsPage.waitForResults(); }); - it('File Office - []', async () => { + it('File Office - [C326664]', async () => { await testUtil.checkViewerActions(testData.fileDocx.name, testData.fileDocx.viewerToolbarPrimary, testData.fileDocx.viewerToolbarMore); }); - it('File Office, favorite - []', async () => { + it('File Office, favorite - [C326665]', async () => { await testUtil.checkViewerActions(testData.fileDocxFav.name, testData.fileDocxFav.viewerToolbarPrimary, testData.fileDocxFav.viewerToolbarMore); }); - it('File simple - []', async () => { + it('File simple - [C326666]', async () => { await testUtil.checkViewerActions(testData.file.name, testData.file.viewerToolbarPrimary, testData.file.viewerToolbarMore); }); - it('File favorite - []', async () => { + it('File favorite - [C326667]', async () => { await testUtil.checkViewerActions(testData.fileFav.name, testData.fileFav.viewerToolbarPrimary, testData.fileFav.viewerToolbarMore); }); - it('File Office, shared - []', async () => { + it('File Office, shared - [C326670]', async () => { await testUtil.checkViewerActions(testData.fileDocxShared.name, testData.fileDocxShared.viewerToolbarPrimary, testData.fileDocxShared.viewerToolbarMore); }); - it('File Office, shared, favorite - []', async () => { + it('File Office, shared, favorite - [C326671]', async () => { await testUtil.checkViewerActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.viewerToolbarPrimary, testData.fileDocxSharedFav.viewerToolbarMore); }); - it('File shared - []', async () => { + it('File shared - [C326672]', async () => { await testUtil.checkViewerActions(testData.fileShared.name, testData.fileShared.viewerToolbarPrimary, testData.fileShared.viewerToolbarMore); }); - it('File shared, favorite - []', async () => { + it('File shared, favorite - [C326673]', async () => { await testUtil.checkViewerActions(testData.fileSharedFav.name, testData.fileSharedFav.viewerToolbarPrimary, testData.fileSharedFav.viewerToolbarMore); }); - it('File locked - []', async () => { + it('File locked - [C326668]', async () => { await testUtil.checkViewerActions(testData.fileLocked.name, testData.fileLocked.viewerToolbarPrimary, testData.fileLocked.viewerToolbarMore); }); - it('File favorite, locked - []', async () => { + it('File favorite, locked - [C326669]', async () => { await testUtil.checkViewerActions(testData.fileFavLocked.name, testData.fileFavLocked.viewerToolbarPrimary, testData.fileFavLocked.viewerToolbarMore); }); - it('File shared, locked - []', async () => { + it('File shared, locked - [C326674]', async () => { await testUtil.checkViewerActions(testData.fileSharedLocked.name, testData.fileSharedLocked.viewerToolbarPrimary, testData.fileSharedLocked.viewerToolbarMore); }); - it('File shared, favorite, locked - []', async () => { + it('File shared, favorite, locked - [C326675]', async () => { await testUtil.checkViewerActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.viewerToolbarPrimary, testData.fileSharedFavLocked.viewerToolbarMore); }); From 1a16d74b625ed87700be2e35390e480c10f5ab9a Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Mon, 17 Feb 2020 16:02:25 +0200 Subject: [PATCH 92/96] [ACA-2174][ACA-2173] Shared / Favorites - edit offline (#1341) * edit offline * try to fix test for viewer - password protected file * bug: Edit in Microsoft Office action is displayed in Shared Files for a locked file move Shared Files workaround down in the file to fix this * remove some workarounds, update some comments * remove other workarounds, make some tests independent, enable lock icon on Search results * forgotten change * remove another workaround Co-authored-by: Adina Parpalita --- e2e/components/data-table/data-table.ts | 13 ++ e2e/components/dialog/password-dialog.ts | 8 +- .../files-folders/shared-files.ts | 24 ++-- .../files-folders/test-data.ts | 82 +++-------- .../special-permissions/favorites.ts | 6 +- .../special-permissions/other-permissions.ts | 27 ++-- .../test-data-permissions.ts | 38 +++-- e2e/suites/actions/edit-offline.test.ts | 135 +++++++++--------- e2e/suites/actions/unshare-file.test.ts | 10 +- .../viewer/viewer-protected-file.test.ts | 16 +-- projects/aca-shared/rules/src/app.rules.ts | 7 +- .../src/lib/evaluators.ts | 26 ++-- .../favorites/favorites.component.html | 1 + .../search-results.component.html | 1 + .../shared-files/shared-files.component.html | 1 + 15 files changed, 180 insertions(+), 215 deletions(-) diff --git a/e2e/components/data-table/data-table.ts b/e2e/components/data-table/data-table.ts index d383f075d..054bb1c73 100755 --- a/e2e/components/data-table/data-table.ts +++ b/e2e/components/data-table/data-table.ts @@ -264,6 +264,19 @@ export class DataTable extends Component { } } + async unselectItem(name: string, location: string = ''): Promise { + const isSelected = await this.hasCheckMarkIcon(name, location); + if (isSelected) { + try { + const item = this.getRowFirstCell(name, location); + await item.click(); + + } catch (e) { + console.log('--- unselect item catch : ', e); + } + } + } + async clickItem(name: string, location: string = ''): Promise { const item = this.getRowFirstCell(name, location); await item.click(); diff --git a/e2e/components/dialog/password-dialog.ts b/e2e/components/dialog/password-dialog.ts index 440193b50..2ab7ce5e7 100755 --- a/e2e/components/dialog/password-dialog.ts +++ b/e2e/components/dialog/password-dialog.ts @@ -58,7 +58,13 @@ export class PasswordDialog extends Component { } async isDialogOpen() { - return browser.isElementPresent(by.css(PasswordDialog.selectors.root)); + try { + const dialog = await browser.wait(until.elementLocated(by.css(PasswordDialog.selectors.root)), BROWSER_WAIT_TIMEOUT, '------- timeout waiting for dialog') + return dialog.isDisplayed(); + } catch (error) { + return false; + } + } async getTitle() { diff --git a/e2e/suites/actions-available/files-folders/shared-files.ts b/e2e/suites/actions-available/files-folders/shared-files.ts index afcb4925e..aa94eee39 100755 --- a/e2e/suites/actions-available/files-folders/shared-files.ts +++ b/e2e/suites/actions-available/files-folders/shared-files.ts @@ -43,33 +43,33 @@ export function sharedFilesTests() { describe('single selection', () => { it('File Office, shared - [C297629]', async () => { - await testUtil.checkToolbarActions(testData.fileDocxShared.name, testData.fileDocxShared.toolbarPrimary, testData.fileDocxShared.sharedToolbarMore); - await testUtil.checkContextMenu(testData.fileDocxShared.name, testData.fileDocxShared.sharedContextMenu); + await testUtil.checkToolbarActions(testData.fileDocxShared.name, testData.fileDocxShared.toolbarPrimary, testData.fileDocxShared.toolbarMore); + await testUtil.checkContextMenu(testData.fileDocxShared.name, testData.fileDocxShared.contextMenu); }); it('File Office, shared, favorite - [C280652]', async () => { - await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.toolbarPrimary, testData.fileDocxSharedFav.sharedToolbarMore); - await testUtil.checkContextMenu(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.sharedContextMenu); + await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.toolbarPrimary, testData.fileDocxSharedFav.toolbarMore); + await testUtil.checkContextMenu(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.contextMenu); }); it('File shared - [C297630]', async () => { - await testUtil.checkToolbarActions(testData.fileShared.name, testData.fileShared.toolbarPrimary, testData.fileShared.sharedToolbarMore); - await testUtil.checkContextMenu(testData.fileShared.name, testData.fileShared.sharedContextMenu); + await testUtil.checkToolbarActions(testData.fileShared.name, testData.fileShared.toolbarPrimary, testData.fileShared.toolbarMore); + await testUtil.checkContextMenu(testData.fileShared.name, testData.fileShared.contextMenu); }); it('File shared, favorite - [C286273]', async () => { - await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.toolbarPrimary, testData.fileSharedFav.sharedToolbarMore); - await testUtil.checkContextMenu(testData.fileSharedFav.name, testData.fileSharedFav.sharedContextMenu); + await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.toolbarPrimary, testData.fileSharedFav.toolbarMore); + await testUtil.checkContextMenu(testData.fileSharedFav.name, testData.fileSharedFav.contextMenu); }); it('File shared, locked - [C286274]', async () => { - await testUtil.checkToolbarActions(testData.fileSharedLocked.name, testData.fileSharedLocked.toolbarPrimary, testData.fileSharedLocked.sharedToolbarMore); - await testUtil.checkContextMenu(testData.fileSharedLocked.name, testData.fileSharedLocked.sharedContextMenu); + await testUtil.checkToolbarActions(testData.fileSharedLocked.name, testData.fileSharedLocked.toolbarPrimary, testData.fileSharedLocked.toolbarMore); + await testUtil.checkContextMenu(testData.fileSharedLocked.name, testData.fileSharedLocked.contextMenu); }); it('File shared, favorite, locked - [C286275]', async () => { - await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.toolbarPrimary, testData.fileSharedFavLocked.sharedToolbarMore); - await testUtil.checkContextMenu(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.sharedContextMenu); + await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.toolbarPrimary, testData.fileSharedFavLocked.toolbarMore); + await testUtil.checkContextMenu(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.contextMenu); }); }); diff --git a/e2e/suites/actions-available/files-folders/test-data.ts b/e2e/suites/actions-available/files-folders/test-data.ts index 2eb081344..10cb960af 100644 --- a/e2e/suites/actions-available/files-folders/test-data.ts +++ b/e2e/suites/actions-available/files-folders/test-data.ts @@ -64,18 +64,18 @@ const viewerLockedToolbarMore = ['Cancel Editing', 'Upload New Version', 'Favori // ---- FAVORITES workarounds ---- -// TODO: add Edit Offline when ACA-2174 is fixed -// TODO: investigate why 'Edit in Microsoft Office™' and 'Permissions' are not displayed and raise issue -const favoritesSharedToolbarPrimary = ['Shared Link Settings', 'Download', 'View', 'View Details', 'More Actions']; -// TODO: add Edit Offline when ACA-2174 is fixed -// TODO: investigate why 'Edit in Microsoft Office™' and 'Permissions' are not displayed and raise issue +// TODO: investigate why 'Edit Offline', 'Edit in Microsoft Office™' and 'Permissions' are not displayed and raise issue const favoritesContextMenu = ['Share', 'Download', 'View', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; -// TODO: add Edit Offline when ACA-2174 is fixed -// TODO: investigate why 'Edit in Microsoft Office™' and 'Permissions' are not displayed and raise issue +// TODO: investigate why 'Permissions' is not displayed and raise issue +const favoritesLockedContextMenu = ['Share', 'Download', 'View', 'Cancel Editing', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; +// TODO: investigate why 'Edit Offline', 'Edit in Microsoft Office™' and 'Permissions' are not displayed and raise issue const favoritesToolbarMore = ['Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; -// TODO: add Edit Offline when ACA-2174 is fixed -// TODO: investigate why 'Edit in Microsoft Office™' and 'Permissions' are not displayed and raise issue +// TODO: investigate why 'Permissions' is not displayed and raise issue +const favoritesLockedToolbarMore = ['Cancel Editing', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; +// TODO: investigate why 'Edit Offline', 'Edit in Microsoft Office™' and 'Permissions' are not displayed and raise issue const favoritesSharedContextMenu = ['Shared Link Settings', 'Download', 'View', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; +// TODO: investigate why 'Permissions' is not displayed and raise issue +const favoritesSharedLockedContextMenu = ['Shared Link Settings', 'Download', 'View', 'Cancel Editing', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; // ---- SEARCH workarounds ---- @@ -107,26 +107,6 @@ const searchViewerFavLockedToolbarMore = ['Cancel Editing', 'Upload New Version' const searchViewerDocxFavToolbarMore = ['Edit in Microsoft Office™', 'Edit Offline', 'Upload New Version', 'Remove Favorite', 'Copy', 'Manage Versions', 'Permissions']; const searchViewerLockedToolbarMore = ['Cancel Editing', 'Upload New Version', 'Favorite', 'Copy', 'Manage Versions', 'Permissions']; -// ---- SHARED workarounds ---- - -// TODO: add Edit Offline to expectedContextMenu when ACA-2173 is fixed -const sharedFilesDocxContextMenu = ['Shared Link Settings', 'Download', 'View', 'Edit in Microsoft Office™', 'Upload New Version', 'Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions', 'Permissions']; -// TODO: add Edit Offline to expectedToolbarMore when ACA-2173 is fixed -const sharedFilesDocxToolbarMore = ['Edit in Microsoft Office™', 'Upload New Version', 'Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions', 'Permissions']; -// TODO: add Edit Offline to expectedContextMenu when ACA-2173 is fixed -const sharedFilesDocxSharedFavContextMenu = ['Shared Link Settings', 'Download', 'View', 'Edit in Microsoft Office™', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions', 'Permissions']; -// TODO: add Edit Offline to expectedToolbarMore when ACA-2173 is fixed -const sharedFilesDocxSharedFavToolbarMore = ['Edit in Microsoft Office™', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions', 'Permissions']; -// TODO: add Cancel Editing to expectedContextMenu when ACA-2173 is fixed -const sharedFilesSharedContextMenu = ['Shared Link Settings', 'Download', 'View', 'Upload New Version', 'Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions', 'Permissions']; -// TODO: add Cancel Editing to expectedToolbarMore when ACA-2173 is fixed -const sharedFilesSharedToolbarMore = ['Upload New Version', 'Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions', 'Permissions']; -// TODO: add Edit Offline to expectedToolbarMore when ACA-2173 is fixed -const sharedFilesFavSharedContextMenu = ['Shared Link Settings', 'Download', 'View', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions', 'Permissions']; -// TODO: add Cancel Editing to expectedToolbarMore when ACA-2173 is fixed -const sharedFilesSharedFavToolbarMore = ['Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions', 'Permissions']; - - export const fileDocx = { name: `file-docx-${Utils.random()}.docx`, @@ -211,10 +191,7 @@ export const fileDocxShared = { searchContextMenu: searchDocxSharedContextMenu, searchToolbarPrimary: searchSharedToolbarPrimary, searchToolbarMore: searchDocxToolbarMore, - searchViewerToolbarMore: searchViewerDocxToolbarMore, - - sharedContextMenu: sharedFilesDocxContextMenu, - sharedToolbarMore: sharedFilesDocxToolbarMore + searchViewerToolbarMore: searchViewerDocxToolbarMore }; export const fileDocxSharedFav = { @@ -228,16 +205,13 @@ export const fileDocxSharedFav = { viewerToolbarMore: viewerDocxFavToolbarMore, favoritesContextMenu: favoritesSharedContextMenu, - favoritesToolbarPrimary: favoritesSharedToolbarPrimary, + favoritesToolbarPrimary: fileSharedToolbarPrimary, favoritesToolbarMore, searchContextMenu: searchDocxSharedFavContextMenu, searchToolbarPrimary: searchSharedToolbarPrimary, searchToolbarMore: searchDocxFavToolbarMore, - searchViewerToolbarMore: searchViewerDocxFavToolbarMore, - - sharedContextMenu: sharedFilesDocxSharedFavContextMenu, - sharedToolbarMore: sharedFilesDocxSharedFavToolbarMore + searchViewerToolbarMore: searchViewerDocxFavToolbarMore }; export const fileShared = { @@ -253,10 +227,7 @@ export const fileShared = { searchContextMenu: searchSharedContextMenu, searchToolbarPrimary: searchSharedToolbarPrimary, searchToolbarMore, - searchViewerToolbarMore, - - sharedContextMenu: sharedFilesSharedContextMenu, - sharedToolbarMore: sharedFilesSharedToolbarMore + searchViewerToolbarMore }; export const fileSharedFav = { @@ -270,16 +241,13 @@ export const fileSharedFav = { viewerToolbarMore: viewerFavToolbarMore, favoritesContextMenu: favoritesSharedContextMenu, - favoritesToolbarPrimary: favoritesSharedToolbarPrimary, + favoritesToolbarPrimary: fileSharedToolbarPrimary, favoritesToolbarMore, searchContextMenu: searchSharedFavContextMenu, searchToolbarPrimary: searchSharedToolbarPrimary, searchToolbarMore: searchFavToolbarMore, - searchViewerToolbarMore: searchViewerFavToolbarMore, - - sharedContextMenu: sharedFilesFavSharedContextMenu, - sharedToolbarMore: sharedFilesSharedFavToolbarMore + searchViewerToolbarMore: searchViewerFavToolbarMore }; export const fileLocked = { @@ -308,8 +276,8 @@ export const fileFavLocked = { viewerToolbarPrimary, viewerToolbarMore: viewerFavLockedToolbarMore, - favoritesContextMenu, - favoritesToolbarMore, + favoritesContextMenu: favoritesLockedContextMenu, + favoritesToolbarMore: favoritesLockedToolbarMore, searchContextMenu: searchFavLockedContextMenu, searchToolbarPrimary, @@ -330,10 +298,7 @@ export const fileSharedLocked = { searchContextMenu: searchSharedLockedContextMenu, searchToolbarPrimary: searchSharedToolbarPrimary, searchToolbarMore: searchLockedToolbarMore, - searchViewerToolbarMore: searchViewerLockedToolbarMore, - - sharedContextMenu: sharedFilesSharedContextMenu, - sharedToolbarMore: sharedFilesSharedToolbarMore + searchViewerToolbarMore: searchViewerLockedToolbarMore }; export const fileSharedFavLocked = { @@ -346,17 +311,14 @@ export const fileSharedFavLocked = { viewerToolbarPrimary: viewerSharedToolbarPrimary, viewerToolbarMore: viewerFavLockedToolbarMore, - favoritesContextMenu: favoritesSharedContextMenu, - favoritesToolbarPrimary: favoritesSharedToolbarPrimary, - favoritesToolbarMore, + favoritesToolbarMore: favoritesLockedToolbarMore, + favoritesContextMenu: favoritesSharedLockedContextMenu, + favoritesToolbarPrimary: fileSharedToolbarPrimary, searchContextMenu: searchSharedFavLockedContextMenu, searchToolbarPrimary: searchSharedToolbarPrimary, searchToolbarMore: searchFavLockedToolbarMore, - searchViewerToolbarMore: searchViewerFavLockedToolbarMore, - - sharedContextMenu: sharedFilesFavSharedContextMenu, - sharedToolbarMore: sharedFilesSharedFavToolbarMore + searchViewerToolbarMore: searchViewerFavLockedToolbarMore }; export const fileInTrash = { diff --git a/e2e/suites/actions-available/special-permissions/favorites.ts b/e2e/suites/actions-available/special-permissions/favorites.ts index f0ca7949c..1e39fc052 100755 --- a/e2e/suites/actions-available/special-permissions/favorites.ts +++ b/e2e/suites/actions-available/special-permissions/favorites.ts @@ -58,12 +58,12 @@ export function favoritesTests() { }); it('File Office, shared, favorite - [C279187]', async () => { - await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.favoritesToolbarPrimary, testData.fileDocxSharedFav.favoritesToolbarMore); + await testUtil.checkToolbarActions(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.toolbarPrimary, testData.fileDocxSharedFav.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileDocxSharedFav.name, testData.fileDocxSharedFav.favoritesContextMenu); }); it('File shared, favorite - [C280053]', async () => { - await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.favoritesToolbarPrimary, testData.fileSharedFav.favoritesToolbarMore); + await testUtil.checkToolbarActions(testData.fileSharedFav.name, testData.fileSharedFav.toolbarPrimary, testData.fileSharedFav.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileSharedFav.name, testData.fileSharedFav.favoritesContextMenu); }); @@ -73,7 +73,7 @@ export function favoritesTests() { }); it('File shared, favorite, locked - [C325011]', async () => { - await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.favoritesToolbarPrimary, testData.fileSharedFavLocked.favoritesToolbarMore); + await testUtil.checkToolbarActions(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.toolbarPrimary, testData.fileSharedFavLocked.favoritesToolbarMore); await testUtil.checkContextMenu(testData.fileSharedFavLocked.name, testData.fileSharedFavLocked.favoritesContextMenu); }); diff --git a/e2e/suites/actions-available/special-permissions/other-permissions.ts b/e2e/suites/actions-available/special-permissions/other-permissions.ts index 55dce7b30..9f8ae1f76 100755 --- a/e2e/suites/actions-available/special-permissions/other-permissions.ts +++ b/e2e/suites/actions-available/special-permissions/other-permissions.ts @@ -59,8 +59,7 @@ export function collaboratorTests(siteName?: string) { await page.clickSharedFilesAndWait(); const expectedToolbarPrimary = ['Shared Link Settings', 'Download', 'View', 'View Details', 'More Actions']; - // TODO: add 'Edit Offline' when ACA-2173 is done - const expectedToolbarMore = ['Upload New Version', 'Remove Favorite', 'Copy', 'Manage Versions', 'Permissions']; + const expectedToolbarMore = ['Edit Offline', 'Upload New Version', 'Remove Favorite', 'Copy', 'Manage Versions', 'Permissions']; await testUtil.checkToolbarActions(testData.fileSharedFav.name, expectedToolbarPrimary, expectedToolbarMore); }); @@ -69,9 +68,8 @@ export function collaboratorTests(siteName?: string) { await page.clickFavoritesAndWait(); const expectedToolbarPrimary = ['Shared Link Settings', 'Download', 'View', 'View Details', 'More Actions']; - // TODO: add 'Edit Offline' when ACA-2174 is done - // TODO: remove 'Delete' when ACA-1737 is done - // TODO: remove 'Move' when ACA-1737 is done + // TODO: investigate why 'Edit Offline' is not displayed and raise issue + // TODO: remove 'Move' and 'Delete' when ACA-1737 is done const expectedToolbarMore = ['Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; await testUtil.checkToolbarActions(testData.fileSharedFav.name, expectedToolbarPrimary, expectedToolbarMore); @@ -156,8 +154,7 @@ export function filesLockedByCurrentUser(siteName?: string) { await page.clickSharedFilesAndWait(); const expectedToolbarPrimary = ['Shared Link Settings', 'Download', 'View', 'View Details', 'More Actions']; - // TODO: add 'Cancel Editing' when ACA-2173 is done - const expectedToolbarMore = ['Upload New Version', 'Remove Favorite', 'Copy', 'Manage Versions']; + const expectedToolbarMore = ['Cancel Editing', 'Upload New Version', 'Remove Favorite', 'Copy', 'Manage Versions']; await testUtil.checkToolbarActions(testData.fileLockedByUser, expectedToolbarPrimary, expectedToolbarMore); }); @@ -166,10 +163,8 @@ export function filesLockedByCurrentUser(siteName?: string) { await page.clickFavoritesAndWait(); const expectedToolbarPrimary = ['Shared Link Settings', 'Download', 'View', 'View Details', 'More Actions']; - // TODO: add 'Cancel Editing' when ACA-2174 is fixed - // TODO: remove 'Move' when ACA-1737 is fixed - // TODO: remove 'Delete' when ACA-1737 is fixed - const expectedToolbarMore = ['Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; + // TODO: remove 'Move' and 'Delete' when ACA-1737 is fixed + const expectedToolbarMore = ['Cancel Editing', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; await testUtil.checkToolbarActions(testData.fileLockedByUser, expectedToolbarPrimary, expectedToolbarMore); }); @@ -255,9 +250,8 @@ export function filesLockedByOtherUser(siteName?: string) { await page.clickSharedFilesAndWait(); const expectedToolbarPrimary = ['Shared Link Settings', 'Download', 'View', 'View Details', 'More Actions']; - // TODO: add 'Cancel Editing' when ACA-2173 is done - // TODO: remove 'Upload New Version' when ACA-2173 is done - const expectedToolbarMore = ['Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions', 'Permissions']; + // TODO: investigate why 'Upload New Version' appears and raise issue + const expectedToolbarMore = ['Cancel Editing', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions', 'Permissions']; await testUtil.checkToolbarActions(testData.fileLockedByUser, expectedToolbarPrimary, expectedToolbarMore); }); @@ -266,7 +260,7 @@ export function filesLockedByOtherUser(siteName?: string) { await page.clickFavoritesAndWait(); const expectedToolbarPrimary = ['Shared Link Settings', 'Download', 'View', 'View Details', 'More Actions']; - // TODO: add 'Cancel Editing' when ACA-2174 is fixed + // TODO: investigate why 'Cancel Editing' doesn't appear and raise issue // TODO: remove 'Upload New Version' when ACA-1737 is done const expectedToolbarMore = ['Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; @@ -320,8 +314,7 @@ export function filesLockedByOtherUser(siteName?: string) { await searchResultsPage.waitForResults(); const expectedToolbarPrimary = ['Activate full-screen mode', 'Shared Link Settings', 'Download', 'Print', 'View Details', 'More Actions']; - // TODO: add 'Move' when ACA-2319 is fixed - // TODO: add 'Delete' when ACA-2319 is fixed + // TODO: add 'Move' and 'Delete' when ACA-2319 is fixed const expectedToolbarMore = ['Cancel Editing', 'Remove Favorite', 'Copy', 'Manage Versions', 'Permissions']; await testUtil.checkViewerActions(testData.fileLockedByUser, expectedToolbarPrimary, expectedToolbarMore); diff --git a/e2e/suites/actions-available/special-permissions/test-data-permissions.ts b/e2e/suites/actions-available/special-permissions/test-data-permissions.ts index 6aec85a2d..3df083069 100644 --- a/e2e/suites/actions-available/special-permissions/test-data-permissions.ts +++ b/e2e/suites/actions-available/special-permissions/test-data-permissions.ts @@ -52,27 +52,38 @@ const consumerViewerToolbarMore = ['Favorite', 'Copy', 'Manage Versions']; // ---- FAVORITES workarounds ---- // TODO: remove 'Move' and 'Delete' when ACA-1737 is done -// TODO: remove 'Upload New Version' when ACA-2175 is done +// TODO: investigate why 'Upload New Version' appears and raise issue const favoritesConsumerToolbarMore = ['Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; // TODO: remove 'Move' and 'Delete' when ACA-1737 is done -// TODO: remove 'Upload New Version' when ACA-2175 is done +// TODO: investigate why 'Upload New Version' appears and raise issue const favoritesConsumerContextMenu = ['Share', 'Download', 'View', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; // TODO: remove 'Move' and 'Delete' when ACA-1737 is done -// TODO: remove 'Upload New Version' when ACA-2175 is done +// TODO: investigate why 'Upload New Version' appears and raise issue const favoritesConsumerSharedContextMenu = ['Shared Link Settings', 'Download', 'View', 'Upload New Version', 'Remove Favorite', 'Move', 'Copy', 'Delete', 'Manage Versions']; -const favoritesConsumerSharedToolbarPrimary = ['Shared Link Settings', 'Download', 'View', 'View Details', 'More Actions']; // ---- SHARED FILES workaround ---- -// TODO: remove 'Upload New Version' when ACA-2173 is done +// TODO: investigate why 'Upload New Version' appears and raise issue const sharedConsumerToolbarMore = ['Upload New Version', 'Favorite', 'Copy', 'Manage Versions']; -// TODO: remove 'Upload New Version' when ACA-2173 is done +// TODO: investigate why 'Cancel Editing' appears and raise issue +// TODO: investigate why 'Upload New Version' appears and raise issue +const sharedConsumerLockedToolbarMore = ['Cancel Editing', 'Upload New Version', 'Favorite', 'Copy', 'Manage Versions']; +// TODO: investigate why 'Upload New Version' appears and raise issue const sharedConsumerFavToolbarMore = ['Upload New Version', 'Remove Favorite', 'Copy', 'Manage Versions']; -// TODO: remove 'Upload New Version' when ACA-2173 is done +// TODO: investigate why 'Cancel Editing' appears and raise issue +// TODO: investigate why 'Upload New Version' appears and raise issue +const sharedConsumerFavLockedToolbarMore = ['Cancel Editing', 'Upload New Version', 'Remove Favorite', 'Copy', 'Manage Versions']; +// TODO: investigate why 'Upload New Version' appears and raise issue const sharedConsumerContextMenu = ['Shared Link Settings', 'Download', 'View', 'Upload New Version', 'Favorite', 'Copy', 'Manage Versions']; -// TODO: remove 'Upload New Version' when ACA-2173 is done +// TODO: investigate why 'Cancel Editing' appears and raise issue +// TODO: investigate why 'Upload New Version' appears and raise issue +const sharedConsumerLockedContextMenu = ['Shared Link Settings', 'Download', 'View', 'Cancel Editing', 'Upload New Version', 'Favorite', 'Copy', 'Manage Versions']; +// TODO: investigate why 'Upload New Version' appears and raise issue const sharedConsumerFavContextMenu = ['Shared Link Settings', 'Download', 'View', 'Upload New Version', 'Remove Favorite', 'Copy', 'Manage Versions']; +// TODO: investigate why 'Cancel Editing' appears and raise issue +// TODO: investigate why 'Upload New Version' appears and raise issue +const sharedConsumerFavLockedContextMenu = ['Shared Link Settings', 'Download', 'View', 'Cancel Editing', 'Upload New Version', 'Remove Favorite', 'Copy', 'Manage Versions']; export const fileDocx = { @@ -161,7 +172,6 @@ export const fileDocxSharedFav = { favoritesToolbarMore: favoritesConsumerToolbarMore, favoritesContextMenu: favoritesConsumerSharedContextMenu, - favoritesToolbarPrimary: favoritesConsumerSharedToolbarPrimary, sharedToolbarMore: sharedConsumerFavToolbarMore, sharedContextMenu: sharedConsumerFavContextMenu, @@ -197,7 +207,6 @@ export const fileSharedFav = { favoritesToolbarMore: favoritesConsumerToolbarMore, favoritesContextMenu: favoritesConsumerSharedContextMenu, - favoritesToolbarPrimary: favoritesConsumerSharedToolbarPrimary, sharedToolbarMore: sharedConsumerFavToolbarMore, sharedContextMenu: sharedConsumerFavContextMenu, @@ -244,8 +253,8 @@ export const fileSharedLocked = { viewerToolbarPrimary: consumerViewerSharedToolbarPrimary, viewerToolbarMore: consumerViewerToolbarMore, - sharedToolbarMore: sharedConsumerToolbarMore, - sharedContextMenu: sharedConsumerContextMenu, + sharedToolbarMore: sharedConsumerLockedToolbarMore, + sharedContextMenu: sharedConsumerLockedContextMenu, searchToolbarPrimary: searchConsumerSharedToolbarPrimary }; @@ -262,10 +271,9 @@ export const fileSharedFavLocked = { favoritesToolbarMore: favoritesConsumerToolbarMore, favoritesContextMenu: favoritesConsumerSharedContextMenu, - favoritesToolbarPrimary: favoritesConsumerSharedToolbarPrimary, - sharedToolbarMore: sharedConsumerFavToolbarMore, - sharedContextMenu: sharedConsumerFavContextMenu, + sharedToolbarMore: sharedConsumerFavLockedToolbarMore, + sharedContextMenu: sharedConsumerFavLockedContextMenu, searchToolbarPrimary: searchConsumerSharedToolbarPrimary }; diff --git a/e2e/suites/actions/edit-offline.test.ts b/e2e/suites/actions/edit-offline.test.ts index 0ef7f2cfd..80f3dd45e 100755 --- a/e2e/suites/actions/edit-offline.test.ts +++ b/e2e/suites/actions/edit-offline.test.ts @@ -55,29 +55,14 @@ describe('Edit offline', () => { const { dataTable, toolbar } = page; const { searchInput } = page.header; - beforeAll(async (done) => { + beforeAll(async () => { await apis.admin.people.createUser({ username }); - - parentPFId = (await apis.user.nodes.createFolder(parentPF)).entry.id; - parentSFId = (await apis.user.nodes.createFolder(parentSF)).entry.id; - parentRFId = (await apis.user.nodes.createFolder(parentRF)).entry.id; - parentFavId = (await apis.user.nodes.createFolder(parentFav)).entry.id; - parentSearchId = (await apis.user.nodes.createFolder(parentSearch)).entry.id; - - done(); - }); - - afterAll(async (done) => { - await apis.user.nodes.deleteNodeById(parentPFId); - await apis.user.nodes.deleteNodeById(parentSFId); - await apis.user.nodes.deleteNodeById(parentRFId); - await apis.user.nodes.deleteNodeById(parentFavId); - await apis.user.nodes.deleteNodeById(parentSearchId); - done(); }); describe('on Personal Files', () => { - beforeAll(async (done) => { + beforeAll(async () => { + parentPFId = (await apis.user.nodes.createFolder(parentPF)).entry.id; + file1Id = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentPFId, file1)).entry.id; fileLockedId = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentPFId, fileLocked)).entry.id; fileLocked2Id = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentPFId, fileLocked2)).entry.id; @@ -86,18 +71,19 @@ describe('Edit offline', () => { await apis.user.nodes.lockFile(fileLocked2Id); await loginPage.loginWith(username); - done(); }); - beforeEach(async (done) => { + beforeEach(async () => { await page.clickPersonalFilesAndWait(); await dataTable.doubleClickOnRowByName(parentPF); - done(); }); - afterEach(async (done) => { + afterEach(async () => { await Utils.pressEscape(); - done(); + }); + + afterAll(async () => { + await apis.user.nodes.deleteNodeById(parentPFId); }); it('File is locked and downloaded when clicking Edit Offline - [C297538]', async () => { @@ -117,16 +103,17 @@ describe('Edit offline', () => { it('Cancel Editing unlocks the file - [C297540]', async () => { await dataTable.selectItem(fileLocked); await toolbar.clickMoreActionsCancelEditing(); - await dataTable.clearSelection(); + await dataTable.unselectItem(fileLocked); expect(await apis.user.nodes.isFileLockedWrite(fileLockedId)).toBe(false, `${fileLocked} is still locked`); expect(await dataTable.hasLockIcon(fileLocked)).toBe(false, `${fileLocked} has a lock icon`); }); }); - // TODO: enable tests when ACA-2173 is done - xdescribe('on Shared Files', () => { - beforeAll(async (done) => { + describe('on Shared Files', () => { + beforeAll(async () => { + parentSFId = (await apis.user.nodes.createFolder(parentSF)).entry.id; + file1Id = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentSFId, file1)).entry.id; fileLockedId = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentSFId, fileLocked)).entry.id; fileLocked2Id = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentSFId, fileLocked2)).entry.id; @@ -138,20 +125,21 @@ describe('Edit offline', () => { await apis.user.shared.waitForApi({ expect: 3 }); await loginPage.loginWith(username); - done(); }); - beforeEach(async (done) => { + afterAll(async () => { + await apis.user.nodes.deleteNodeById(parentSFId); + }); + + beforeEach(async () => { await page.clickSharedFilesAndWait(); - done(); }); - afterEach(async (done) => { + afterEach(async () => { await Utils.pressEscape(); - done(); }); - xit('File is locked and downloaded when clicking Edit Offline - [C306950]', async () => { + it('File is locked and downloaded when clicking Edit Offline - [C306950]', async () => { await dataTable.selectItem(file1, parentSF); await toolbar.clickMoreActionsEditOffline(); @@ -159,16 +147,16 @@ describe('Edit offline', () => { expect(await apis.user.nodes.isFileLockedWrite(file1Id)).toBe(true, `${file1} is not locked`); }); - xit('Lock information is displayed - [C306951]', async () => { + it('Lock information is displayed - [C306951]', async () => { expect(await dataTable.isItemPresent(fileLocked2, parentSF)).toBe(true, `${fileLocked2} is not displayed`); expect(await dataTable.hasLockIcon(fileLocked2, parentSF)).toBe(true, `${fileLocked2} does not have a lock icon`); expect(await dataTable.getLockOwner(fileLocked2, parentSF)).toContain(username, `${fileLocked2} does not have correct lock owner info`); }); - xit('Cancel Editing unlocks the file - [C306952]', async () => { + it('Cancel Editing unlocks the file - [C306952]', async () => { await dataTable.selectItem(fileLocked); await toolbar.clickMoreActionsCancelEditing(); - await dataTable.clearSelection(); + await dataTable.unselectItem(fileLocked); expect(await apis.user.nodes.isFileLockedWrite(fileLockedId)).toBe(false, `${fileLocked} is still locked`); expect(await dataTable.hasLockIcon(fileLocked, parentSF)).toBe(false, `${fileLocked} has a lock icon`); @@ -176,7 +164,11 @@ describe('Edit offline', () => { }); describe('on Recent Files', () => { - beforeAll(async (done) => { + beforeAll(async () => { + parentRFId = (await apis.user.nodes.createFolder(parentRF)).entry.id; + + await apis.user.search.waitForApi(username, { expect: 0 }); + file1Id = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentRFId, file1)).entry.id; fileLockedId = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentRFId, fileLocked)).entry.id; fileLocked2Id = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentRFId, fileLocked2)).entry.id; @@ -184,20 +176,21 @@ describe('Edit offline', () => { await apis.user.nodes.lockFile(fileLockedId); await apis.user.nodes.lockFile(fileLocked2Id); - await apis.user.search.waitForApi(username, { expect: 6 }); + await apis.user.search.waitForApi(username, { expect: 3 }); await loginPage.loginWith(username); - done(); }); - beforeEach(async (done) => { + afterAll(async () => { + await apis.user.nodes.deleteNodeById(parentRFId); + }); + + beforeEach(async () => { await page.clickRecentFilesAndWait(); - done(); }); - afterEach(async (done) => { + afterEach(async () => { await Utils.pressEscape(); - done(); }); it('File is locked and downloaded when clicking Edit Offline - [C297541]', async () => { @@ -217,16 +210,17 @@ describe('Edit offline', () => { it('Cancel Editing unlocks the file - [C297543]', async () => { await dataTable.selectItem(fileLocked, parentRF); await toolbar.clickMoreActionsCancelEditing(); - await dataTable.clearSelection(); + await dataTable.unselectItem(fileLocked, parentRF); expect(await apis.user.nodes.isFileLockedWrite(fileLockedId)).toBe(false, `${fileLocked} is still locked`); expect(await dataTable.hasLockIcon(fileLocked, parentRF)).toBe(false, `${fileLocked} has a lock icon`); }); }); - // TODO: enable tests when ACA-2174 is done - xdescribe('on Favorite Files', () => { - beforeAll(async (done) => { + describe('on Favorite Files', () => { + beforeAll(async () => { + parentFavId = (await apis.user.nodes.createFolder(parentFav)).entry.id; + file1Id = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentFavId, file1)).entry.id; fileLockedId = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentFavId, fileLocked)).entry.id; fileLocked2Id = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentFavId, fileLocked2)).entry.id; @@ -238,19 +232,21 @@ describe('Edit offline', () => { await apis.user.favorites.waitForApi({ expect: 3 }); await loginPage.loginWith(username); - done(); }); - beforeEach(async (done) => { + afterAll(async () => { + await apis.user.nodes.deleteNodeById(parentFavId); + }); + + beforeEach(async () => { await page.clickFavoritesAndWait(); - done(); }); - afterEach(async (done) => { + afterEach(async () => { await Utils.pressEscape(); - done(); }); + // TODO: raise REPO issue: permissions not returned in /people/${personId}/favorites api xit('File is locked and downloaded when clicking Edit Offline - [C306956]', async () => { await dataTable.selectItem(file1); await toolbar.clickMoreActionsEditOffline(); @@ -259,16 +255,16 @@ describe('Edit offline', () => { expect(await apis.user.nodes.isFileLockedWrite(file1Id)).toBe(true, `${file1} is not locked`); }); - xit('Lock information is displayed - [C306957]', async () => { + it('Lock information is displayed - [C306957]', async () => { expect(await dataTable.isItemPresent(fileLocked2)).toBe(true, `${fileLocked2} is not displayed`); expect(await dataTable.hasLockIcon(fileLocked2)).toBe(true, `${fileLocked2} does not have a lock icon`); expect(await dataTable.getLockOwner(fileLocked2)).toContain(username, `${fileLocked2} does not have correct lock owner info`); }); - xit('Cancel Editing unlocks the file - [C306958]', async () => { + it('Cancel Editing unlocks the file - [C306958]', async () => { await dataTable.selectItem(fileLocked); await toolbar.clickMoreActionsCancelEditing(); - await dataTable.clearSelection(); + await dataTable.unselectItem(fileLocked); expect(await apis.user.nodes.isFileLockedWrite(fileLockedId)).toBe(false, `${fileLocked} is still locked`); expect(await dataTable.hasLockIcon(fileLocked)).toBe(false, `${fileLocked} has a lock icon`); @@ -276,7 +272,9 @@ describe('Edit offline', () => { }); describe('on Search Results', () => { - beforeAll(async (done) => { + beforeAll(async () => { + parentSearchId = (await apis.user.nodes.createFolder(parentSearch)).entry.id; + fileSearch1Id = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentSearchId, fileSearch1)).entry.id; fileSearchLockedId = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentSearchId, fileSearchLocked)).entry.id; fileSearchLocked2Id = (await apis.user.upload.uploadFileWithRename(FILES.docxFile, parentSearchId, fileSearchLocked2)).entry.id; @@ -287,21 +285,21 @@ describe('Edit offline', () => { await apis.user.search.waitForNodes('file-search', { expect: 3 }); await loginPage.loginWith(username); - done(); }); - beforeEach(async (done) => { + afterAll(async () => { + await apis.user.nodes.deleteNodeById(parentSearchId); + }); + + beforeEach(async () => { await page.clickPersonalFilesAndWait(); await searchInput.clickSearchButton(); - await searchInput.checkFilesAndFolders(); await searchInput.searchFor('file-search'); await dataTable.waitForBody(); - done(); }); - afterEach(async (done) => { + afterEach(async () => { await Utils.pressEscape(); - done(); }); it('File is locked and downloaded when clicking Edit Offline - [C306953]', async () => { @@ -312,21 +310,20 @@ describe('Edit offline', () => { expect(await apis.user.nodes.isFileLockedWrite(fileSearch1Id)).toBe(true, `${fileSearch1} is not locked`); }); - // TODO: enable when ACA-2314 is fixed - xit('Lock information is displayed - [C306954]', async () => { + it('Lock information is displayed - [C306954]', async () => { expect(await dataTable.isItemPresent(fileSearchLocked2, parentSearch)).toBe(true, `${fileSearchLocked2} is not displayed`); expect(await dataTable.hasLockIcon(fileSearchLocked2, parentSearch)).toBe(true, `${fileSearchLocked2} does not have a lock icon`); - expect(await dataTable.getLockOwner(fileSearchLocked2, parentSearch)).toContain(username, `${fileSearchLocked2} does not have correct lock owner info`); + // TODO: enable when ACA-2314 is fixed + // expect(await dataTable.getLockOwner(fileSearchLocked2, parentSearch)).toContain(username, `${fileSearchLocked2} does not have correct lock owner info`); }); it('Cancel Editing unlocks the file - [C306955]', async () => { await dataTable.selectItem(fileSearchLocked); await toolbar.clickMoreActionsCancelEditing(); - await dataTable.clearSelection(); + await dataTable.unselectItem(fileSearchLocked); expect(await apis.user.nodes.isFileLockedWrite(fileSearchLockedId)).toBe(false, `${fileSearchLocked} is still locked`); - // TODO: enable when ACA-2314 is fixed - // expect(await dataTable.hasLockIcon(fileSearchLocked, parentSearch)).toBe(false, `${fileSearchLocked} has a lock icon`); + expect(await dataTable.hasLockIcon(fileSearchLocked, parentSearch)).toBe(false, `${fileSearchLocked} has a lock icon`); }); }); }); diff --git a/e2e/suites/actions/unshare-file.test.ts b/e2e/suites/actions/unshare-file.test.ts index 6ea5be057..aee35f584 100755 --- a/e2e/suites/actions/unshare-file.test.ts +++ b/e2e/suites/actions/unshare-file.test.ts @@ -479,9 +479,6 @@ describe('Unshare a file', () => { expect(await shareDialog.isDialogOpen()).toBe(false, 'Share dialog open'); expect(await apis.user.nodes.isFileShared(file2Id)).toBe(false, `${file2} is shared`); - // TODO: disable check cause api is slow to update - // expect(await dataTable.isItemPresent(file2)).toBe(false, `${file2} is in the Shared files list`); - await browser.get(url); expect(await viewer.isViewerOpened()).toBe(true, 'viewer is not open'); expect(await viewer.getFileTitle()).not.toEqual(file2); @@ -519,9 +516,6 @@ describe('Unshare a file', () => { expect(await shareDialog.isDialogOpen()).toBe(false, 'Share dialog open'); expect(await apis.user.nodes.isFileShared(file4Id)).toBe(false, `${file4} is shared`); - // TODO: disable check cause api is slow to update - // expect(await dataTable.isItemPresent(file4)).toBe(false, `${file4} is in the Shared files list`); - await browser.get(url); expect(await viewer.isViewerOpened()).toBe(true, 'viewer is not open'); expect(await viewer.getFileTitle()).not.toEqual(file4); @@ -631,9 +625,7 @@ describe('Unshare a file', () => { it('Unshare a file from the context menu - [C286698]', async () => { await dataTable.rightClickOnItem(file4); - // TODO: remove workaround for favorites - // await toolbar.clickSharedLinkSettings(); - await contextMenu.clickShare(); + await contextMenu.clickSharedLinkSettings(); await shareDialog.waitForDialogToOpen(); const url = await shareDialog.getLinkUrl(); await shareDialog.clickShareToggle(); diff --git a/e2e/suites/viewer/viewer-protected-file.test.ts b/e2e/suites/viewer/viewer-protected-file.test.ts index 28d3a32aa..a7e1863ac 100755 --- a/e2e/suites/viewer/viewer-protected-file.test.ts +++ b/e2e/suites/viewer/viewer-protected-file.test.ts @@ -48,16 +48,15 @@ describe('Viewer - password protected file', () => { const viewer = new Viewer(); const passwordDialog = new PasswordDialog(); - beforeAll(async (done) => { + beforeAll(async () => { await apis.admin.people.createUser({ username }); parentId = (await apis.user.nodes.createFolder(parent)).entry.id; await apis.user.upload.uploadFile(protectedFile.name, parentId); await loginPage.loginWith(username); - done(); }); - beforeEach(async (done) => { + beforeEach(async () => { await page.header.expandSideNav(); await page.clickPersonalFilesAndWait(); await dataTable.doubleClickOnRowByName(parent); @@ -65,20 +64,15 @@ describe('Viewer - password protected file', () => { await dataTable.doubleClickOnRowByName(protectedFile.name); await viewer.waitForViewerToOpen(); await page.waitForDialog(); - done(); }); - afterEach(async (done) => { - if (await passwordDialog.isDialogOpen()) { - await passwordDialog.clickClose(); - } + afterEach(async () => { + await page.closeOpenDialogs(); await Utils.pressEscape(); - done(); }); - afterAll(async (done) => { + afterAll(async () => { await apis.user.nodes.deleteNodeById(parentId); - done(); }); it('Password dialog appears when opening a protected file - [C268958]', async () => { diff --git a/projects/aca-shared/rules/src/app.rules.ts b/projects/aca-shared/rules/src/app.rules.ts index 027e0cd90..11381309e 100644 --- a/projects/aca-shared/rules/src/app.rules.ts +++ b/projects/aca-shared/rules/src/app.rules.ts @@ -152,7 +152,7 @@ export function canDeleteSelection(context: RuleContext): boolean { return false; } - // temp workaround for Search api + // temp workaround for Favorites api if (navigation.isFavorites(context)) { return true; } @@ -391,7 +391,7 @@ export function canLockFile(context: RuleContext): boolean { /** * Checks if user can unlock selected file. - * JSON ref: `app.selection.file.canLock` + * JSON ref: `app.selection.file.canUnlock` */ export function canUnlockFile(context: RuleContext): boolean { const { file } = context.selection; @@ -508,9 +508,6 @@ export function canToggleEditOffline(context: RuleContext): boolean { return [ hasFileSelected(context), navigation.isNotTrashcan(context), - navigation.isNotFavorites(context) || - navigation.isFavoritesPreview(context), - navigation.isNotSharedFiles(context) || navigation.isSharedPreview(context), canLockFile(context) || canUnlockFile(context) ].every(Boolean); } diff --git a/projects/adf-office-services-ext/src/lib/evaluators.ts b/projects/adf-office-services-ext/src/lib/evaluators.ts index 535a26dd7..18c626143 100644 --- a/projects/adf-office-services-ext/src/lib/evaluators.ts +++ b/projects/adf-office-services-ext/src/lib/evaluators.ts @@ -53,19 +53,6 @@ export function canOpenWithOffice( return false; } - // workaround for Shared files - if ( - context.navigation && - context.navigation.url && - context.navigation.url.startsWith('/shared') - ) { - if (file.entry.hasOwnProperty('allowableOperationsOnTarget')) { - return context.permissions.check(file, ['update'], { - target: 'allowableOperationsOnTarget' - }); - } - } - if (!file.entry.properties) { return false; } @@ -107,5 +94,18 @@ export function canOpenWithOffice( return false; } + // workaround for Shared files + if ( + context.navigation && + context.navigation.url && + context.navigation.url.startsWith('/shared') + ) { + if (file.entry.hasOwnProperty('allowableOperationsOnTarget')) { + return context.permissions.check(file, ['update'], { + target: 'allowableOperationsOnTarget' + }); + } + } + return context.permissions.check(file, ['update']); } diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index 27148c698..009cb074f 100644 --- a/src/app/components/favorites/favorites.component.html +++ b/src/app/components/favorites/favorites.component.html @@ -20,6 +20,7 @@ selectionMode="multiple" [navigate]="false" [sorting]="['modifiedAt', 'desc']" + [imageResolver]="imageResolver" (node-dblclick)="onNodeDoubleClick($event.detail?.node)" (name-click)="onNodeDoubleClick($event.detail?.node)" > diff --git a/src/app/components/search/search-results/search-results.component.html b/src/app/components/search/search-results/search-results.component.html index 01befdeb4..af905470b 100644 --- a/src/app/components/search/search-results/search-results.component.html +++ b/src/app/components/search/search-results/search-results.component.html @@ -69,6 +69,7 @@ [selectionMode]="'multiple'" [sortingMode]="'server'" [sorting]="sorting" + [imageResolver]="imageResolver" [node]="data" (node-dblclick)="onNodeDoubleClick($event.detail?.node)" > diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index 3ee06f402..d70a9e4b1 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -19,6 +19,7 @@ currentFolderId="-sharedlinks-" selectionMode="multiple" [sorting]="['modifiedAt', 'desc']" + [imageResolver]="imageResolver" (node-dblclick)="preview($event.detail?.node)" (name-click)="preview($event.detail?.node)" > From c4b97f5b87acdbdde7dd00665527f6628242413e Mon Sep 17 00:00:00 2001 From: Irving Navarrete Date: Mon, 17 Feb 2020 14:02:52 +0000 Subject: [PATCH 93/96] Updates for 1.10 release (#1342) Updating the what's new section, compatibility and feature sections --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 20ca051d8..3bea9eca0 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,8 @@ Please include a clear description, steps to reproduce and screenshots where app #### What's new in the latest release -- Single Log Out -- WCAG AA accessibility improvements +- Create (file/folder) Templates +- More WCAG AA accessibility improvements Please refer to the [release notes] for details of all changes. @@ -59,6 +59,7 @@ Read up on our guidelines for [contributing] and then check out one of our issue | ACA Version | Built with | Tested on | | ----------- | ---------- | --------- | +| ACA 1.10 | ADF 3.7.0 | ACS 6.2 | | ACA 1.9 | ADF 3.6.0 | ACS 6.2 | | ACA 1.8 | ADF 3.3.0 | ACS 6.1 | | ACA 1.7 | ADF 3.0.0 | ACS 6.1 | @@ -100,6 +101,7 @@ Read up on our guidelines for [contributing] and then check out one of our issue | 1.8 | Extensibility improvements | Various - see [release notes](https://github.com/Alfresco/alfresco-content-app/releases) for details | | 1.9 | Single Log Out | Users will be automatically logged out from the Content App after logging out from another application in the same browser session | | 1.9 | Accessibility improvements | Various - see [release notes](https://github.com/Alfresco/alfresco-content-app/releases) for details | + 1.10 | Create (file/folder) from template | Users can create files and folders structures from pre-set templates | [contributing]: https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md [github]: https://github.com/Alfresco/alfresco-content-app/issues From 5284f96981df1a26054e7089e5e9c0acf1ff7427 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Mon, 17 Feb 2020 17:35:51 +0200 Subject: [PATCH 94/96] bump 1.10.0 (#1343) * 1.10.0 * bump app config --- package-lock.json | 2 +- package.json | 2 +- src/app.config.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9a287ce71..5afbba802 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "alfresco-content-app", - "version": "1.9.0", + "version": "1.10.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9c226513e..adc8ab417 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "alfresco-content-app", - "version": "1.9.0", + "version": "1.10.0", "license": "LGPL-3.0", "scripts": { "ng": "ng", diff --git a/src/app.config.json b/src/app.config.json index e3a799564..fb77dca77 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -19,7 +19,7 @@ }, "application": { "name": "Alfresco Content Application", - "version": "1.9.0", + "version": "1.10.0", "logo": "assets/images/alfresco-logo-flower.svg", "copyright": "APP.COPYRIGHT" }, From 66a440c26e4342e4885a542482e48eddf93db9d2 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Mon, 17 Feb 2020 19:06:26 +0200 Subject: [PATCH 95/96] bump version (#1344) --- projects/aca-shared/package.json | 2 +- projects/adf-office-services-ext/assets/aos.plugin.json | 2 +- projects/adf-office-services-ext/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/aca-shared/package.json b/projects/aca-shared/package.json index 232e60e55..3d154ab00 100644 --- a/projects/aca-shared/package.json +++ b/projects/aca-shared/package.json @@ -1,6 +1,6 @@ { "name": "@alfresco/aca-shared", - "version": "1.9.1", + "version": "1.9.2", "peerDependencies": { "@angular/common": "^7.2.0", "@angular/core": "^7.2.0", diff --git a/projects/adf-office-services-ext/assets/aos.plugin.json b/projects/adf-office-services-ext/assets/aos.plugin.json index 4a6b2f053..07ed542a8 100644 --- a/projects/adf-office-services-ext/assets/aos.plugin.json +++ b/projects/adf-office-services-ext/assets/aos.plugin.json @@ -1,7 +1,7 @@ { "$schema": "../../../extension.schema.json", "$id": "9a635542-d87a-4558-ae64-ffa199d1a364", - "$version": "0.0.9", + "$version": "0.0.10", "$name": "keensoft.aos.plugin", "$description": "Extension that provides Office Edit Online Action", "$vendor": "Keensoft", diff --git a/projects/adf-office-services-ext/package.json b/projects/adf-office-services-ext/package.json index a428a7fa8..99bdc4e8a 100644 --- a/projects/adf-office-services-ext/package.json +++ b/projects/adf-office-services-ext/package.json @@ -1,6 +1,6 @@ { "name": "@alfresco/adf-office-services-ext", - "version": "0.0.9", + "version": "0.0.10", "license": "Apache-2.0", "homepage": "https://github.com/Alfresco/alfresco-content-app", "keywords": ["Alfresco", "ADF", "ACA", "Content Application"], From db86a081e43aa8dec5eb85d730b790e5d991fce1 Mon Sep 17 00:00:00 2001 From: Gloria Broadbent Date: Wed, 19 Feb 2020 03:01:42 +0000 Subject: [PATCH 96/96] LOC-191: Localised UI files for ADW 1.4 (#1347) --- src/assets/i18n/ar.json | 33 +++++++++++++++++++-- src/assets/i18n/cs.json | 33 +++++++++++++++++++-- src/assets/i18n/da.json | 33 +++++++++++++++++++-- src/assets/i18n/de.json | 33 +++++++++++++++++++-- src/assets/i18n/es.json | 47 +++++++++++++++++++++++------- src/assets/i18n/fi.json | 33 +++++++++++++++++++-- src/assets/i18n/fr.json | 33 +++++++++++++++++++-- src/assets/i18n/it.json | 59 +++++++++++++++++++++++++++----------- src/assets/i18n/ja.json | 33 +++++++++++++++++++-- src/assets/i18n/nb.json | 33 +++++++++++++++++++-- src/assets/i18n/nl.json | 33 +++++++++++++++++++-- src/assets/i18n/pl.json | 33 +++++++++++++++++++-- src/assets/i18n/pt-BR.json | 33 +++++++++++++++++++-- src/assets/i18n/ru.json | 33 +++++++++++++++++++-- src/assets/i18n/sv.json | 35 +++++++++++++++++++--- src/assets/i18n/zh-CN.json | 33 +++++++++++++++++++-- 16 files changed, 501 insertions(+), 69 deletions(-) diff --git a/src/assets/i18n/ar.json b/src/assets/i18n/ar.json index d1881440f..76b5182dc 100644 --- a/src/assets/i18n/ar.json +++ b/src/assets/i18n/ar.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "إنشاء مجلد", "UPLOAD_FILE": "تحميل ملف", "UPLOAD_FOLDER": "تحميل مجلد", - "CREATE_LIBRARY": "إنشاء مكتبة" + "CREATE_LIBRARY": "إنشاء مكتبة", + "FILE_TEMPLATE": "إنشاء ملف من قالب", + "FOLDER_TEMPLATE": "إنشاء مجلد من قالب" }, "TOOLTIPS": { "CREATE_FOLDER": "إنشاء مجلد جديد", "CREATE_FOLDER_NOT_ALLOWED": "يتعذر إنشاء مجلدات أثناء عرض العناصر الحالية", + "CREATE_FILE_NOT_ALLOWED": "لا يمكن إنشاء الملفات أثناء عرض العناصر الحالية", "UPLOAD_FILES": "تحديد ملفات لتحميلها", "UPLOAD_FILES_NOT_ALLOWED": "يتعذر تحميل الملفات أثناء عرض العناصر الحالية", "UPLOAD_FOLDERS": "تحديد مجلدات لتحميلها", @@ -355,7 +358,31 @@ "COPY_ITEMS": "نسخ {{ number }} عناصر إلى...", "MOVE_ITEM": "نقل '{{ name }}' إلى...", "MOVE_ITEMS": "نقل {{ number }} عناصر إلى...", - "SEARCH": "بحث" + "SEARCH": "بحث", + "NEXT": "التالي", + "SELECT_FILE_TEMPLATE_TITLE": "تحديد قالب مستند", + "SELECT_FOLDER_TEMPLATE_TITLE": "تحديد قالب مجلد" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "إلغاء", + "CREATE": "إنشاء", + "FOLDER_DIALOG_TITLE": "إنشاء مجلد جديد من '{{ template }}'", + "FILE_DIALOG_TITLE": "إنشاء مجلد جديد من '{{ template }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "الاسم", + "TITLE": "العنوان", + "DESCRIPTION": "الوصف" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "استخدم 512 حرفًا أو أقل للوصف", + "TITLE_TOO_LONG": "استخدم 256 أو أقل للعنوان", + "REQUIRED": "الاسم مطلوب", + "SPECIAL_CHARACTERS": "لا يمكن أن يحتوي الاسم على هذه الرموز * \" < > \\ / ? : |", + "ENDING_DOT": "لا يمكن أن ينتهي الاسم بنقطة .", + "ONLY_SPACES": "لا يمكن أن يحتوي الاسم على مسافات فقط" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "ملف مؤمن" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/cs.json b/src/assets/i18n/cs.json index 47128474e..e3e349c79 100644 --- a/src/assets/i18n/cs.json +++ b/src/assets/i18n/cs.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "Vytvořit složku", "UPLOAD_FILE": "Odeslat soubor", "UPLOAD_FOLDER": "Odeslat složku", - "CREATE_LIBRARY": "Vytvořit knihovnu" + "CREATE_LIBRARY": "Vytvořit knihovnu", + "FILE_TEMPLATE": "Vytvořit soubor ze šablony", + "FOLDER_TEMPLATE": "Vytvořit složku ze šablony" }, "TOOLTIPS": { "CREATE_FOLDER": "Vytvořit novou složku", "CREATE_FOLDER_NOT_ALLOWED": "Během prohlížení současných položek není vytvoření složky možné", + "CREATE_FILE_NOT_ALLOWED": "Soubory nelze vytvářet během prohlížení aktuálních položek.", "UPLOAD_FILES": "Vyberte soubory, které chcete odeslat", "UPLOAD_FILES_NOT_ALLOWED": "Během prohlížení současných položek není odeslání souborů možné", "UPLOAD_FOLDERS": "Vyberte složky, které chcete odeslat", @@ -355,7 +358,31 @@ "COPY_ITEMS": "Zkopírovat položky ({{ number }}) do...", "MOVE_ITEM": "Přesunout položku '{{ name }}' do...", "MOVE_ITEMS": "Přesunout položky ({{ number }}) do...", - "SEARCH": "Hledat" + "SEARCH": "Hledat", + "NEXT": "Další", + "SELECT_FILE_TEMPLATE_TITLE": "Výběr šablony dokumentu", + "SELECT_FOLDER_TEMPLATE_TITLE": "Výběr šablony složky" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Zrušit", + "CREATE": "Vytvořit", + "FOLDER_DIALOG_TITLE": "Vytvořit novou složku ze šablony '{{ template }}'", + "FILE_DIALOG_TITLE": "Vytvořit nový dokument ze šablony '{{ template }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Název", + "TITLE": "Označení", + "DESCRIPTION": "Popis" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "Popis může obsahovat maximálně 512 znaků", + "TITLE_TOO_LONG": "Označení může obsahovat maximálně 256 znaků", + "REQUIRED": "Název je povinný", + "SPECIAL_CHARACTERS": "Název nemůže obsahovat tyto znaky: * \" < > \\ / ? : |", + "ENDING_DOT": "Název nemůže končit tečkou.", + "ONLY_SPACES": "Název nemůže obsahovat pouze mezery." + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "uzamčený soubor" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index 34c3cef28..39e69518f 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "Opret mappe", "UPLOAD_FILE": "Upload fil", "UPLOAD_FOLDER": "Upload mappe", - "CREATE_LIBRARY": "Opret bibliotek" + "CREATE_LIBRARY": "Opret bibliotek", + "FILE_TEMPLATE": "Opret fil fra skabelon", + "FOLDER_TEMPLATE": "Opret mappe fra skabelon" }, "TOOLTIPS": { "CREATE_FOLDER": "Opret ny mappe", "CREATE_FOLDER_NOT_ALLOWED": "Der kan ikke oprettes mapper, mens du får vist de aktuelle elementer", + "CREATE_FILE_NOT_ALLOWED": "Filer kan ikke oprettes, samtidig med at de aktuelle elementer vises", "UPLOAD_FILES": "Vælg de filer, du vil uploade", "UPLOAD_FILES_NOT_ALLOWED": "Der kan ikke uploades filer, mens du får vist de aktuelle elementer", "UPLOAD_FOLDERS": "Vælg de mapper, du vil uploade", @@ -355,7 +358,31 @@ "COPY_ITEMS": "Kopiér {{ number }} elementer til...", "MOVE_ITEM": "Flyt '{{ name }}' til...", "MOVE_ITEMS": "Flyt {{ number }} elementer til...", - "SEARCH": "Søg" + "SEARCH": "Søg", + "NEXT": "Næste", + "SELECT_FILE_TEMPLATE_TITLE": "Vælg en dokumentskabelon", + "SELECT_FOLDER_TEMPLATE_TITLE": "Vælg en mappeskabelon" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Annuller", + "CREATE": "Opret", + "FOLDER_DIALOG_TITLE": "Opret en ny mappe fra '{{ template }}'", + "FILE_DIALOG_TITLE": "Opret et nyt dokument fra '{{ template }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Navn", + "TITLE": "Titel", + "DESCRIPTION": "Beskrivelse" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "Beskrivelsen må ikke være på mere end 512 tegn", + "TITLE_TOO_LONG": "Titlen må ikke være på mere end 256 tegn", + "REQUIRED": "Et navn er påkrævet", + "SPECIAL_CHARACTERS": "Navnet må ikke indeholde følgende tegn: * \" < > \\ / ? : |", + "ENDING_DOT": "Navnet må ikke slutte med et punktum (.)", + "ONLY_SPACES": "Navnet skal indeholde andet end mellemrum" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "låst fil" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 12cb115c4..0bbbbd36c 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "Ordner erstellen", "UPLOAD_FILE": "Datei hochladen", "UPLOAD_FOLDER": "Ordner hochladen", - "CREATE_LIBRARY": "Bibliothek erstellen" + "CREATE_LIBRARY": "Bibliothek erstellen", + "FILE_TEMPLATE": "Datei aus Vorlage erstellen", + "FOLDER_TEMPLATE": "Ordner aus Vorlage erstellen" }, "TOOLTIPS": { "CREATE_FOLDER": "Neuen Ordner erstellen", "CREATE_FOLDER_NOT_ALLOWED": "Ordner können nicht erstellt werden, während die aktuellen Elemente angezeigt werden", + "CREATE_FILE_NOT_ALLOWED": "Dateien können nicht erstellt werden, während aktuelle Elemente angezeigt werden", "UPLOAD_FILES": "Dateien zum Hochladen auswählen", "UPLOAD_FILES_NOT_ALLOWED": "Dateien können nicht hochgeladen werden, während die aktuellen Elemente angezeigt werden", "UPLOAD_FOLDERS": "Ordner zum Hochladen auswählen", @@ -355,7 +358,31 @@ "COPY_ITEMS": "{{ number }} Elemente kopieren nach...", "MOVE_ITEM": "'{{ name }}' verschieben nach...", "MOVE_ITEMS": "{{ number }} Elemente verschieben nach...", - "SEARCH": "Suchen" + "SEARCH": "Suchen", + "NEXT": "Weiter", + "SELECT_FILE_TEMPLATE_TITLE": "Wählen Sie eine Dokumentvorlage aus", + "SELECT_FOLDER_TEMPLATE_TITLE": "Wählen Sie eine Ordnervorlage aus" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Abbrechen", + "CREATE": "Erstellen", + "FOLDER_DIALOG_TITLE": "Neuen Ordner aus Vorlage '{{ template }}' erstellen", + "FILE_DIALOG_TITLE": "Neues Dokument aus Vorlage '{{ template }}' erstellen", + "FORM": { + "PLACEHOLDER": { + "NAME": "Name", + "TITLE": "Titel", + "DESCRIPTION": "Beschreibung" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "Die Beschreibung darf höchstens 512 Zeichen lang sein", + "TITLE_TOO_LONG": "Der Titel darf höchstens 256 Zeichen lang sein", + "REQUIRED": "Name ist erforderlich", + "SPECIAL_CHARACTERS": "Name darf die folgenden Zeichen nicht enthalten: * \" < > \\ / ? : |", + "ENDING_DOT": "Name darf nicht mit einem Punkt enden", + "ONLY_SPACES": "Name darf keine Leerzeichen enthalten" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "gesperrte Datei" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/es.json b/src/assets/i18n/es.json index 8414654b6..c59921140 100644 --- a/src/assets/i18n/es.json +++ b/src/assets/i18n/es.json @@ -15,12 +15,12 @@ }, "LICENSE": { "TITLE": "Licencia", - "PROPERTY": "Propiedad", + "PROPERTY": "Propiedades", "VALUE": "Valor" }, "STATUS": { "TITLE": "Estado", - "PROPERTY": "Propiedad", + "PROPERTY": "Propiedades", "VALUE": "Valor" }, "MODULES": { @@ -57,13 +57,16 @@ "CREATE_FOLDER": "Crear carpeta", "UPLOAD_FILE": "Añadir fichero", "UPLOAD_FOLDER": "Cargar carpeta", - "CREATE_LIBRARY": "Crear biblioteca" + "CREATE_LIBRARY": "Crear biblioteca", + "FILE_TEMPLATE": "Crear fichero a partir de plantilla", + "FOLDER_TEMPLATE": "Crear carpeta a partir de plantilla" }, "TOOLTIPS": { "CREATE_FOLDER": "Crear nueva carpeta", "CREATE_FOLDER_NOT_ALLOWED": "No se pueden crear carpetas mientras se visualizan los elementos actuales", + "CREATE_FILE_NOT_ALLOWED": "No es posible crear los ficheros mientras se muestran los elementos actuales", "UPLOAD_FILES": "Seleccionar ficheros para cargar", - "UPLOAD_FILES_NOT_ALLOWED": "No se pueden crear ficheros mientras se visualizan los elementos actuales", + "UPLOAD_FILES_NOT_ALLOWED": "No se pueden cargar ficheros mientras se visualizan elementos actuales", "UPLOAD_FOLDERS": "Seleccionar carpetas para cargar", "UPLOAD_FOLDERS_NOT_ALLOWED": "No se pueden cargar carpetas mientras se visualizan los elementos actuales", "CREATE_LIBRARY": "Crear una nueva biblioteca de ficheros" @@ -309,8 +312,8 @@ "NODE_DELETION": { "SINGULAR": "{{ name }} eliminado", "PLURAL": "Se han eliminado {{ number }} elementos", - "PARTIAL_SINGULAR": "Se ha eliminado {{ success }} elemento, {{ failed }} no se ha podido eliminar", - "PARTIAL_PLURAL": "Se han eliminado {{ success }} elementos, {{ failed }} no se han podido eliminar" + "PARTIAL_SINGULAR": "Se ha eliminado el elemento {{ success }}, {{ failed }} no se ha podido eliminar", + "PARTIAL_PLURAL": "Se han eliminado los elementos {{ success }}, {{ failed }} no se han podido eliminar" }, "NODE_COPY": { "SINGULAR": "Se ha copiado {{ success }} elemento", @@ -355,7 +358,31 @@ "COPY_ITEMS": "Copiar {{ number }} elementos a...", "MOVE_ITEM": "Mover '{{ name }}' a...", "MOVE_ITEMS": "Mover {{ number }} elementos a...", - "SEARCH": "Buscar" + "SEARCH": "Buscar", + "NEXT": "Siguiente", + "SELECT_FILE_TEMPLATE_TITLE": "Seleccione una plantilla de documento", + "SELECT_FOLDER_TEMPLATE_TITLE": "Seleccione una plantilla de carpeta" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Cancelar", + "CREATE": "Crear", + "FOLDER_DIALOG_TITLE": "Crear nueva carpeta a partir de '{{ template }}'", + "FILE_DIALOG_TITLE": "Crear nuevo documento a partir de '{{ template }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Nombre", + "TITLE": "Título", + "DESCRIPTION": "Descripción" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "Utilice como máximo 512 caracteres para la descripción", + "TITLE_TOO_LONG": "Utilice como máximo 256 caracteres para el título", + "REQUIRED": "Se requiere el nombre", + "SPECIAL_CHARACTERS": "El nombre no puede contener estos caracteres * \" < > \\ / ? : |", + "ENDING_DOT": "El nombre no puede terminar en punto .", + "ONLY_SPACES": "El nombre no puede contener solo espacios" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -367,7 +394,7 @@ } }, "SHARED_LINK": { - "UNSHARE_PERMISSION_ERROR": "No tiene acceso para dejar de compartir este fichero" + "UNSHARE_PERMISSION_ERROR": "No tiene permiso para dejar de compartir este fichero" }, "VERSION": { "DIALOG_ADF": { @@ -503,7 +530,7 @@ "ADF_VERSION_LIST": { "ACTIONS": { "UPLOAD": { - "TOOLTIP": "Cargue nueva versión" + "TOOLTIP": "Cargar nueva versión" } } }, @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "fichero bloqueado" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/fi.json b/src/assets/i18n/fi.json index 8537975c7..32d875447 100644 --- a/src/assets/i18n/fi.json +++ b/src/assets/i18n/fi.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "Luo kansio", "UPLOAD_FILE": "Lataa tiedosto", "UPLOAD_FOLDER": "Lataa kansio", - "CREATE_LIBRARY": "Luo kirjasto" + "CREATE_LIBRARY": "Luo kirjasto", + "FILE_TEMPLATE": "Luo tiedosto mallista", + "FOLDER_TEMPLATE": "Luo kansio mallista" }, "TOOLTIPS": { "CREATE_FOLDER": "Luo uusi kansio", "CREATE_FOLDER_NOT_ALLOWED": "Kansioita ei voi luoda, kun tarkastelet nykyisiä kohteita", + "CREATE_FILE_NOT_ALLOWED": "Tiedostoja ei voi luoda, kun tarkastelet nykyisiä kohteita", "UPLOAD_FILES": "Valitse ladattavat tiedostot", "UPLOAD_FILES_NOT_ALLOWED": "Tiedostoja ei voi ladata, kun tarkastelet nykyisiä kohteita", "UPLOAD_FOLDERS": "Valitse ladattavat kansiot", @@ -355,7 +358,31 @@ "COPY_ITEMS": "Kopioi {{ number }} kohdetta kohteeseen...", "MOVE_ITEM": "Siirrä '{{ name }}' kohteeseen...", "MOVE_ITEMS": "Siirrä {{ number }} kohdetta kohteeseen...", - "SEARCH": "Hae" + "SEARCH": "Hae", + "NEXT": "Seuraava", + "SELECT_FILE_TEMPLATE_TITLE": "Valitse asiakirjamalli", + "SELECT_FOLDER_TEMPLATE_TITLE": "Valitse kansiomalli" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Peruuta", + "CREATE": "Luo", + "FOLDER_DIALOG_TITLE": "Luo uusi kansio mallista '{{ template }}'", + "FILE_DIALOG_TITLE": "Luo uusi asiakirja mallista '{{ template }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Nimi", + "TITLE": "Otsikko", + "DESCRIPTION": "Kuvaus" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "Kuvauksessa voi olla enintään 512 merkkiä", + "TITLE_TOO_LONG": "Otsikossa voi olla enintään 256 merkkiä", + "REQUIRED": "Nimi on pakollinen", + "SPECIAL_CHARACTERS": "Nimessä ei saa olla näitä merkkejä: * \" < > \\ / ? : |", + "ENDING_DOT": "Nimi ei voi päättyä pisteeseen (.)", + "ONLY_SPACES": "Nimi ei voi koostua vain välilyönneistä" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "tiedosto lukittu" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index 838bb21ef..eb59e676f 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "Créer un dossier", "UPLOAD_FILE": "Importer le fichier", "UPLOAD_FOLDER": "Importer le dossier", - "CREATE_LIBRARY": "Créer une Bibliothèque" + "CREATE_LIBRARY": "Créer une Bibliothèque", + "FILE_TEMPLATE": "Créer un fichier à partir d'un modèle", + "FOLDER_TEMPLATE": "Créer un dossier à partir d'un modèle" }, "TOOLTIPS": { "CREATE_FOLDER": "Créer un nouveau filtre", "CREATE_FOLDER_NOT_ALLOWED": "Impossible de créer des dossiers pendant l'affichage des éléments actuels.", + "CREATE_FILE_NOT_ALLOWED": "Impossible de créer des fichiers tout en visualisant les éléments actuels", "UPLOAD_FILES": "Sélectionner les fichiers à ajouter", "UPLOAD_FILES_NOT_ALLOWED": "Impossible de charger les fichiers pendant l'affichage des éléments actuels", "UPLOAD_FOLDERS": "Sélectionner les fichiers à ajouter", @@ -355,7 +358,31 @@ "COPY_ITEMS": "Copier {{ number }} éléments vers...", "MOVE_ITEM": "Déplacer '{{ name }}' vers...", "MOVE_ITEMS": "Déplacer {{ number }} éléments vers...", - "SEARCH": "Rechercher" + "SEARCH": "Rechercher", + "NEXT": "Suivant", + "SELECT_FILE_TEMPLATE_TITLE": "Sélectionner un modèle de document", + "SELECT_FOLDER_TEMPLATE_TITLE": "Sélectionner un modèle de dossier" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Annuler", + "CREATE": "Créer", + "FOLDER_DIALOG_TITLE": "Créer un nouveau dossier à partir de '{{ template }}'", + "FILE_DIALOG_TITLE": "Créer un nouveau document à partir de '{{ template }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Nom", + "TITLE": "Titre", + "DESCRIPTION": "Description" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "La description doit contenir 512 caractères maximum", + "TITLE_TOO_LONG": "Le titre doit contenir 256 caractères maximum", + "REQUIRED": "Un nom est requis", + "SPECIAL_CHARACTERS": "Le nom ne peut pas contenir les caractères * \" < > \\ / ? : |", + "ENDING_DOT": "Le nom ne peut pas se terminer par un point .", + "ONLY_SPACES": "Le nom ne peut pas contenir que des espaces" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "fichier verrouillé" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/it.json b/src/assets/i18n/it.json index 4d4309df9..40d7ce4c8 100644 --- a/src/assets/i18n/it.json +++ b/src/assets/i18n/it.json @@ -8,7 +8,7 @@ "ID": "ID", "NAME": "Nome", "VERSION": "Versione", - "VENDOR": "Venditore", + "VENDOR": "Fornitore", "LICENSE": "Licenza", "RUNTIME": "Runtime", "DESCRIPTION": "Descrizione" @@ -57,11 +57,14 @@ "CREATE_FOLDER": "Crea cartella", "UPLOAD_FILE": "Carica file", "UPLOAD_FOLDER": "Carica cartella", - "CREATE_LIBRARY": "Crea libreria" + "CREATE_LIBRARY": "Crea libreria", + "FILE_TEMPLATE": "Crea file da modello", + "FOLDER_TEMPLATE": "Crea cartella da modello" }, "TOOLTIPS": { "CREATE_FOLDER": "Crea nuova cartella", "CREATE_FOLDER_NOT_ALLOWED": "Impossibile creare cartelle durante la visualizzazione degli elementi correnti", + "CREATE_FILE_NOT_ALLOWED": "I file non possono essere creati durante la visualizzazione degli elementi correnti", "UPLOAD_FILES": "Seleziona file da caricare", "UPLOAD_FILES_NOT_ALLOWED": "Impossibile caricare file durante la visualizzazione degli elementi correnti", "UPLOAD_FOLDERS": "Seleziona cartelle da caricare", @@ -103,9 +106,9 @@ } }, "FAVORITE_LIBRARIES": { - "TITLE": "Raccolte preferite", + "TITLE": "Raccolte preferite", "SIDENAV_LINK": { - "LABEL": "Raccolte preferite", + "LABEL": "Raccolte preferite", "TOOLTIP": "Accedi alle raccolte preferite" } } @@ -201,7 +204,7 @@ "UNSHARE": "Rimuovi condivisione", "DETAILS": "Visualizza dettagli", "VERSIONS": "Gestione versioni", - "UPLOAD_VERSION": "Carica la nuova versione", + "UPLOAD_VERSION": "Caricare la nuova versione", "TOGGLE-SIDENAV": "Attiva/disattiva barra di navigazione laterale", "SHARE": "Condividi", "SHARE_EDIT": "Impostazioni di collegamento condiviso", @@ -280,13 +283,13 @@ "JOIN_REQUEST_FAILED": "Impossibile partecipare alla raccolta", "JOIN_CANCEL_FAILED": "Impossibile annullare la richiesta di partecipazione", "LEAVE_LIBRARY_FAILED": "Impossibile uscire dalla raccolta", - "INVALID_SENDER_EMAIL": "L'indirizzo e-mail deve essere valido prima della richiesta di accesso.", - "INVALID_RECEIVER_EMAIL": "Indirizzo e-mail del destinatario non valido. Contattare l'IT." + "INVALID_SENDER_EMAIL": "L'indirizzo email deve essere valido prima della richiesta di accesso.", + "INVALID_RECEIVER_EMAIL": "Indirizzo email del destinatario non valido. Contattare l'IT." }, "UPLOAD": { "ERROR": { "GENERIC": "Caricamento non riuscito. Se il problema persiste, contattare l'IT", - "CONFLICT": "Nuova versione non caricata. Esiste già un file con lo stesso nome.", + "CONFLICT": "Nuova versione non caricata. Esiste già un fil con lo stesso nome.", "500": "Errore interno del server. Riprovare o contattare il supporto IT [500]", "504": "Timeout del server. Riprovare o contattare il supporto IT [504]", "403": "Autorizzazioni insufficienti per caricare in questa posizione [403]", @@ -297,7 +300,7 @@ "TRASH": { "NODES_PURGE": { "PLURAL": "{{ number }} elementi eliminati", - "SINGULAR": "{{ name }} eliminato", + "SINGULAR": "Elemento {{ name }} eliminato", "PARTIAL_SINGULAR": "Elemento {{ name }} eliminato. Impossibile eliminare l'elemento {{ failed }}.", "PARTIAL_PLURAL": "{{ number }} elementi eliminati, impossibile eliminare {{ failed }}" }, @@ -308,7 +311,7 @@ }, "NODE_DELETION": { "SINGULAR": "{{ name }} eliminato", - "PLURAL": "Eliminati {{ number }} elementi", + "PLURAL": "{{ number }} elementi eliminati", "PARTIAL_SINGULAR": "Elemento {{ success }} eliminato, impossibile eliminare {{ failed }}", "PARTIAL_PLURAL": "Elementi {{ success }} eliminati, impossibile eliminare {{ failed }}" }, @@ -345,7 +348,7 @@ "TABS": { "PROPERTIES": "Proprietà", "LIBRARY_PROPERTIES": "Informazioni su", - "VERSIONS": "Versioni", + "VERSIONS": "Versione", "COMMENTS": "Commenti" } } @@ -355,7 +358,31 @@ "COPY_ITEMS": "Copia {{ number }} elementi in...", "MOVE_ITEM": "Sposta '{{ name }}' in...", "MOVE_ITEMS": "Sposta {{ number }} elementi in...", - "SEARCH": "Cerca" + "SEARCH": "Cerca", + "NEXT": "Successivo", + "SELECT_FILE_TEMPLATE_TITLE": "Selezionare un modello di documento", + "SELECT_FOLDER_TEMPLATE_TITLE": "Selezionare un modello di cartella" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Annulla", + "CREATE": "Crea", + "FOLDER_DIALOG_TITLE": "Creazione nuova cartella da '{{ template }}'", + "FILE_DIALOG_TITLE": "Creazione nuovo documento da '{{ template }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Nome", + "TITLE": "Titolo", + "DESCRIPTION": "Descrizione" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "Utilizzare 512 o meno per la descrizione", + "TITLE_TOO_LONG": "Utilizzare 256 caratteri o meno per il titolo", + "REQUIRED": "Nome obbligatorio", + "SPECIAL_CHARACTERS": "Il nome non può contenere questi caratteri * \" < > \\ / ? : |", + "ENDING_DOT": "Il nome non può terminare con un punto.", + "ONLY_SPACES": "Il nome non può contenere solo spazi" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -367,7 +394,7 @@ } }, "SHARED_LINK": { - "UNSHARE_PERMISSION_ERROR": "Non si dispone dei permessi per rimuovere la condivisione di questo file" + "UNSHARE_PERMISSION_ERROR": "Non hai il permesso per rimuovere la condivisione di questo file" }, "VERSION": { "DIALOG_ADF": { @@ -375,7 +402,7 @@ "CLOSE": "Chiudi" }, "DIALOG": { - "TITLE": "Carica la nuova versione", + "TITLE": "Utilizza nuova versione", "CANCEL": "Annulla", "UPLOAD": "Carica" }, @@ -503,7 +530,7 @@ "ADF_VERSION_LIST": { "ACTIONS": { "UPLOAD": { - "TOOLTIP": "Carica la nuova versione" + "TOOLTIP": "Caricare la nuova versione" } } }, @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "File bloccato" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/ja.json b/src/assets/i18n/ja.json index 59712b7aa..e0cb34fcb 100644 --- a/src/assets/i18n/ja.json +++ b/src/assets/i18n/ja.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "フォルダの作成", "UPLOAD_FILE": "ファイルのアップロード", "UPLOAD_FOLDER": "フォルダのアップロード", - "CREATE_LIBRARY": "ライブラリの作成" + "CREATE_LIBRARY": "ライブラリの作成", + "FILE_TEMPLATE": "テンプレートからファイルを作成", + "FOLDER_TEMPLATE": "テンプレートからフォルダを作成" }, "TOOLTIPS": { "CREATE_FOLDER": "新しいフォルダを作成します", "CREATE_FOLDER_NOT_ALLOWED": "現在のアイテムを表示している間はフォルダを作成できません", + "CREATE_FILE_NOT_ALLOWED": "現在のアイテムを表示している間はファイルを作成できません", "UPLOAD_FILES": "アップロードするファイルを選択します", "UPLOAD_FILES_NOT_ALLOWED": "現在のアイテムを表示している間はファイルをアップロードできません", "UPLOAD_FOLDERS": "アップロードするフォルダを選択します", @@ -355,7 +358,31 @@ "COPY_ITEMS": "{{ number }} 件のアイテムのコピー先...", "MOVE_ITEM": "'{{ name }}' の移動先...", "MOVE_ITEMS": "{{ number }} 件のアイテムの移動先...", - "SEARCH": "検索" + "SEARCH": "検索", + "NEXT": "次へ", + "SELECT_FILE_TEMPLATE_TITLE": "文書テンプレートを選択してください", + "SELECT_FOLDER_TEMPLATE_TITLE": "フォルダテンプレートを選択してください" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "キャンセル", + "CREATE": "作成", + "FOLDER_DIALOG_TITLE": "'{{ template }}' から新規フォルダを作成します", + "FILE_DIALOG_TITLE": "'{{ template }}' から新規文書を作成します", + "FORM": { + "PLACEHOLDER": { + "NAME": "名前", + "TITLE": "タイトル", + "DESCRIPTION": "説明" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "説明は 512 文字以内で入力してください", + "TITLE_TOO_LONG": "タイトルは 256 文字以内で入力してください", + "REQUIRED": "名前を指定してください", + "SPECIAL_CHARACTERS": "名前に次の文字を含めることはできません。 * \" < > \\ / ? : |", + "ENDING_DOT": "名前の末尾にピリオド (.) を付けることはできません。", + "ONLY_SPACES": "名前にスペースだけを含めることはできません" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "ロックされているファイル" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/nb.json b/src/assets/i18n/nb.json index 45370420d..eb8725183 100644 --- a/src/assets/i18n/nb.json +++ b/src/assets/i18n/nb.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "Opprett mappe", "UPLOAD_FILE": "Last opp fil", "UPLOAD_FOLDER": "Last opp mappe", - "CREATE_LIBRARY": "Opprett bibliotek" + "CREATE_LIBRARY": "Opprett bibliotek", + "FILE_TEMPLATE": "Opprett fil fra mal", + "FOLDER_TEMPLATE": "Opprett mappe fra mal" }, "TOOLTIPS": { "CREATE_FOLDER": "Opprett ny mappe", "CREATE_FOLDER_NOT_ALLOWED": "Mapper kan ikke opprettes mens du viser de gjeldende elementene", + "CREATE_FILE_NOT_ALLOWED": "Filer kan ikke opprettes mens du viser de gjeldende elementene", "UPLOAD_FILES": "Velg filene som skal lastes opp", "UPLOAD_FILES_NOT_ALLOWED": "Filer kan ikke lastes opp mens du viser de gjeldende elementene", "UPLOAD_FOLDERS": "Velg mappene som skal lastes opp", @@ -355,7 +358,31 @@ "COPY_ITEMS": "Kopier {{ number }} elementer til...", "MOVE_ITEM": "Flytt {{ name }}'til...", "MOVE_ITEMS": "Flytt {{ number }} elementer til...", - "SEARCH": "Søk" + "SEARCH": "Søk", + "NEXT": "Neste", + "SELECT_FILE_TEMPLATE_TITLE": "Velg en dokumentmal", + "SELECT_FOLDER_TEMPLATE_TITLE": "Velg en mappemal" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Avbryt", + "CREATE": "Opprett", + "FOLDER_DIALOG_TITLE": "Opprett ny mappe fra '{{ template }}'", + "FILE_DIALOG_TITLE": "Opprett nytt dokument fra '{{ template }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Navn", + "TITLE": "Tittel", + "DESCRIPTION": "Beskrivelse" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "Bruk 512 tegn eller mindre i beskrivelsen", + "TITLE_TOO_LONG": "Bruk 256 tegn eller mindre i tittelen", + "REQUIRED": "Navn må oppgis", + "SPECIAL_CHARACTERS": "Navnet kan ikke inneholde tegnene * \" < > \\ / ? : |", + "ENDING_DOT": "Navnet kan ikke ende med et punktum .", + "ONLY_SPACES": "Navnet kan ikke kun bestå av mellomrom" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "låst fil" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/nl.json b/src/assets/i18n/nl.json index c520b358e..fee220471 100644 --- a/src/assets/i18n/nl.json +++ b/src/assets/i18n/nl.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "Map maken", "UPLOAD_FILE": "Bestand uploaden", "UPLOAD_FOLDER": "Map uploaden", - "CREATE_LIBRARY": "Bibliotheek maken" + "CREATE_LIBRARY": "Bibliotheek maken", + "FILE_TEMPLATE": "Bestand maken op basis van sjabloon", + "FOLDER_TEMPLATE": "Map maken op basis van sjabloon" }, "TOOLTIPS": { "CREATE_FOLDER": "Nieuwe map maken", "CREATE_FOLDER_NOT_ALLOWED": "Mappen kunnen niet worden gemaakt terwijl de huidige items worden weergegeven", + "CREATE_FILE_NOT_ALLOWED": "Bestanden kunnen niet worden gemaakt terwijl de huidige items worden weergegeven", "UPLOAD_FILES": "Bestanden selecteren om te uploaden", "UPLOAD_FILES_NOT_ALLOWED": "Bestanden kunnen niet worden geüpload terwijl de huidige items worden weergegeven", "UPLOAD_FOLDERS": "Mappen selecteren om te uploaden", @@ -355,7 +358,31 @@ "COPY_ITEMS": "{{ number }} items kopiëren naar...", "MOVE_ITEM": "'{{ name }}' verplaatsen naar...", "MOVE_ITEMS": "{{ number }} items verplaatsen naar...", - "SEARCH": "Zoeken" + "SEARCH": "Zoeken", + "NEXT": "Volgende", + "SELECT_FILE_TEMPLATE_TITLE": "Een documentsjabloon selecteren", + "SELECT_FOLDER_TEMPLATE_TITLE": "Een mapsjabloon selecteren" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Annuleren", + "CREATE": "Maken", + "FOLDER_DIALOG_TITLE": "Nieuwe map maken op basis van '{{ template }}'", + "FILE_DIALOG_TITLE": "Nieuw document maken op basis van '{{ template }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Naam", + "TITLE": "Titel", + "DESCRIPTION": "Beschrijving" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "Gebruik 512 tekens of minder voor de beschrijving", + "TITLE_TOO_LONG": "Gebruik 256 tekens of minder voor de titel", + "REQUIRED": "Naam is vereist", + "SPECIAL_CHARACTERS": "Naam mag de volgende tekens niet bevatten: * \" < > \\ / ? : |", + "ENDING_DOT": "Naam mag niet eindigen met een punt.", + "ONLY_SPACES": "Naam mag niet alleen uit spaties bestaan" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "Vergrendeld bestand" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/pl.json b/src/assets/i18n/pl.json index 5903b24be..e79ef626b 100644 --- a/src/assets/i18n/pl.json +++ b/src/assets/i18n/pl.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "Utwórz Folder", "UPLOAD_FILE": "Prześlij plik", "UPLOAD_FOLDER": "Prześlij folder", - "CREATE_LIBRARY": "Utwórz bibliotekę" + "CREATE_LIBRARY": "Utwórz bibliotekę", + "FILE_TEMPLATE": "Stwórz plik w oparciu o szablon", + "FOLDER_TEMPLATE": "Stwórz folder w oparciu o szablon" }, "TOOLTIPS": { "CREATE_FOLDER": "Utwórz nowy folder", "CREATE_FOLDER_NOT_ALLOWED": "Nie można tworzyć folderów podczas przeglądania bieżących elementów", + "CREATE_FILE_NOT_ALLOWED": "Pliki nie mogą zostać utworzone podczas oglądania aktualnych elementów.", "UPLOAD_FILES": "Wybierz pliki do przesłania", "UPLOAD_FILES_NOT_ALLOWED": "Nie można przesyłać plików podczas przeglądania bieżących elementów", "UPLOAD_FOLDERS": "Wybierz foldery do przesłania", @@ -355,7 +358,31 @@ "COPY_ITEMS": "Kopiowanie {{ number }} elementów do...", "MOVE_ITEM": "Przenieś '{{ name }}' do...", "MOVE_ITEMS": "Przenoszenie {{ number }} elementów do...", - "SEARCH": "Szukaj" + "SEARCH": "Szukaj", + "NEXT": "Następny", + "SELECT_FILE_TEMPLATE_TITLE": "Wybierz szablon dokumentu", + "SELECT_FOLDER_TEMPLATE_TITLE": "Wybierz szablon folderu" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Anuluj", + "CREATE": "Utwórz", + "FOLDER_DIALOG_TITLE": "Utwórz nowy folder w oparciu o '{{ szablon }}'", + "FILE_DIALOG_TITLE": "Utwórz nowy dokument w oparciu o '{{ szablon }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Nazwa", + "TITLE": "Tytuł", + "DESCRIPTION": "Opis" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "W opisie można użyć maksymalnie 512 znaków", + "TITLE_TOO_LONG": "W tytule można użyć maksymalnie 256 znaków", + "REQUIRED": "Nazwa jest wymagana", + "SPECIAL_CHARACTERS": "Nazwa nie może zawierać następujących znaków: * \" < > \\ / ? : |", + "ENDING_DOT": "Nazwa nie może kończyć się kropką (.)", + "ONLY_SPACES": "Nazwa nie może zawierać spacji" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "zablokowany plik" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/pt-BR.json b/src/assets/i18n/pt-BR.json index b009f41a1..d7e6d09f8 100644 --- a/src/assets/i18n/pt-BR.json +++ b/src/assets/i18n/pt-BR.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "Criar pasta", "UPLOAD_FILE": "Carregar arquivo", "UPLOAD_FOLDER": "Carregar pasta", - "CREATE_LIBRARY": "Criar biblioteca" + "CREATE_LIBRARY": "Criar biblioteca", + "FILE_TEMPLATE": "Criar arquivo a partir do modelo", + "FOLDER_TEMPLATE": "Criar pasta a partir do modelo" }, "TOOLTIPS": { "CREATE_FOLDER": "Criar nova pasta", "CREATE_FOLDER_NOT_ALLOWED": "Não é possível criar pastas durante a visualização dos itens atuais", + "CREATE_FILE_NOT_ALLOWED": "Os arquivos não podem ser criados enquanto os itens atuais estiverem sendo visualizados", "UPLOAD_FILES": "Selecionar arquivos para carregar", "UPLOAD_FILES_NOT_ALLOWED": "Não é possível carregar arquivos durante a visualização dos itens atuais", "UPLOAD_FOLDERS": "Selecionar pastas para carregar", @@ -355,7 +358,31 @@ "COPY_ITEMS": "Copiar {{ number }} itens para...", "MOVE_ITEM": "Mover '{{ name }}' para...", "MOVE_ITEMS": "Mover {{ number }} itens para...", - "SEARCH": "Pesquisar" + "SEARCH": "Pesquisar", + "NEXT": "Próximo", + "SELECT_FILE_TEMPLATE_TITLE": "Selecionar um modelo de documento", + "SELECT_FOLDER_TEMPLATE_TITLE": "Selecionar um modelo de pasta" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Cancelar", + "CREATE": "Criar", + "FOLDER_DIALOG_TITLE": "Criar nova pasta a partir de '{{ template }}'", + "FILE_DIALOG_TITLE": "Criar novo documento a partir de '{{ template }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Nome", + "TITLE": "Título", + "DESCRIPTION": "Descrição" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "Use 512 caracteres ou menos para a descrição", + "TITLE_TOO_LONG": "Use 256 caracteres ou menos para o título", + "REQUIRED": "Nome é obrigatório", + "SPECIAL_CHARACTERS": "O nome não pode ter estes caracteres * \" < > \\ / ? : |", + "ENDING_DOT": "O nome não pode terminar com um ponto final .", + "ONLY_SPACES": "O nome não pode ter apenas espaços" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "arquivo bloqueado" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json index e43690939..eb4826585 100644 --- a/src/assets/i18n/ru.json +++ b/src/assets/i18n/ru.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "Создать папку", "UPLOAD_FILE": "Загрузить файл", "UPLOAD_FOLDER": "Загрузить папку", - "CREATE_LIBRARY": "Создание библиотеки" + "CREATE_LIBRARY": "Создание библиотеки", + "FILE_TEMPLATE": "Создать файл из шаблона", + "FOLDER_TEMPLATE": "Создать папку из шаблона" }, "TOOLTIPS": { "CREATE_FOLDER": "Создать новую папку", "CREATE_FOLDER_NOT_ALLOWED": "Невозможно создать папки во время просмотра текущих элементов", + "CREATE_FILE_NOT_ALLOWED": "Файлы нельзя создать во время просмотра текущих элементов", "UPLOAD_FILES": "Выберите файлы, которые необходимо загрузить", "UPLOAD_FILES_NOT_ALLOWED": "Невозможно загрузить файлы во время просмотра текущих элементов", "UPLOAD_FOLDERS": "Выберите папки, которые необходимо загрузить", @@ -355,7 +358,31 @@ "COPY_ITEMS": "Скопировать элементы {{ number }} в...", "MOVE_ITEM": "Переместить '{{ name }}' в...", "MOVE_ITEMS": "Переместить элементы {{ number }} в...", - "SEARCH": "Поиск" + "SEARCH": "Поиск", + "NEXT": "Далее", + "SELECT_FILE_TEMPLATE_TITLE": "Выберите шаблон документа", + "SELECT_FOLDER_TEMPLATE_TITLE": "Выберите шаблон папки" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Отмена", + "CREATE": "Создать", + "FOLDER_DIALOG_TITLE": "Создать новую папку из '{{ шаблона }}'", + "FILE_DIALOG_TITLE": "Создать новый документ из '{{ шаблона }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Имя", + "TITLE": "Название", + "DESCRIPTION": "Описание" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "Описание должно содержать не более 512 символов", + "TITLE_TOO_LONG": "Название должно содержать не более 256 символов", + "REQUIRED": "Необходимо указать имя", + "SPECIAL_CHARACTERS": "Имя не может содержать символы * \" < > \\ / ? : |", + "ENDING_DOT": "Имя не может заканчиваться точкой .", + "ONLY_SPACES": "Имя не может содержать только пробелы" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "заблокированный файл" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/sv.json b/src/assets/i18n/sv.json index ca30c0833..60f418f84 100644 --- a/src/assets/i18n/sv.json +++ b/src/assets/i18n/sv.json @@ -45,7 +45,7 @@ "INVALID-VALUE-FORMAT": "Ogiltigt värdeformat", "REQUIRED-FIELD": "Det här fältet krävs", "RESET": "Återställ", - "APPLY": "Använd" + "APPLY": "Tillämpa" }, "PREVIEW": { "TITLE": "Förhandsgranskning" @@ -57,11 +57,14 @@ "CREATE_FOLDER": "Skapa mapp", "UPLOAD_FILE": "Ladda upp fil", "UPLOAD_FOLDER": "Ladda upp mapp", - "CREATE_LIBRARY": "Skapa bibliotek" + "CREATE_LIBRARY": "Skapa bibliotek", + "FILE_TEMPLATE": "Skapa fil från mall", + "FOLDER_TEMPLATE": "Skapa mapp från mall" }, "TOOLTIPS": { "CREATE_FOLDER": "Skapa ny mapp", "CREATE_FOLDER_NOT_ALLOWED": "Mappar kan inte skapas när man visar de aktuella objekten", + "CREATE_FILE_NOT_ALLOWED": "Filerna kan inte skapas när aktuella objekt visas", "UPLOAD_FILES": "Välj filer att ladda upp", "UPLOAD_FILES_NOT_ALLOWED": "Filer kan inte laddas upp när man visar de aktuella objekten", "UPLOAD_FOLDERS": "Välj mappar att ladda upp", @@ -355,7 +358,31 @@ "COPY_ITEMS": "Kopiera {{ number }} objekt till...", "MOVE_ITEM": "Flytta '{{ name }}' till...", "MOVE_ITEMS": "Flytta {{ number }} objekt till...", - "SEARCH": "Sök" + "SEARCH": "Sök", + "NEXT": "Nästa", + "SELECT_FILE_TEMPLATE_TITLE": "Välj en dokumentmall", + "SELECT_FOLDER_TEMPLATE_TITLE": "Välj en mappmall" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "Avbryt", + "CREATE": "Skapa", + "FOLDER_DIALOG_TITLE": "Skapa ny mapp från '{{ template }}'", + "FILE_DIALOG_TITLE": "Skapa nytt dokument från '{{ template }}'", + "FORM": { + "PLACEHOLDER": { + "NAME": "Namn", + "TITLE": "Titel", + "DESCRIPTION": "Beskrivning" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "Använd 512 tecken eller färre till beskrivningen", + "TITLE_TOO_LONG": "Använd 256 tecken eller färre till titeln", + "REQUIRED": "Namn krävs", + "SPECIAL_CHARACTERS": "Namnet kan inte innehålla dessa tecken * \" < > \\ / ? : |", + "ENDING_DOT": "Namnet kan inte sluta med en punkt .", + "ONLY_SPACES": "Namnet kan inte innehålla endast mellanslag" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "låst fil" } } -} +} \ No newline at end of file diff --git a/src/assets/i18n/zh-CN.json b/src/assets/i18n/zh-CN.json index d918b251e..b9fe83f25 100644 --- a/src/assets/i18n/zh-CN.json +++ b/src/assets/i18n/zh-CN.json @@ -57,11 +57,14 @@ "CREATE_FOLDER": "创建文件夹", "UPLOAD_FILE": "上传文件", "UPLOAD_FOLDER": "上传文件夹", - "CREATE_LIBRARY": "创建库" + "CREATE_LIBRARY": "创建库", + "FILE_TEMPLATE": "从模板创建文件", + "FOLDER_TEMPLATE": "从模板创建文件夹" }, "TOOLTIPS": { "CREATE_FOLDER": "新建文件夹", "CREATE_FOLDER_NOT_ALLOWED": "查看当前项目时无法创建文件夹", + "CREATE_FILE_NOT_ALLOWED": "查看当前项目时无法创建文件", "UPLOAD_FILES": "选择要上传的文件", "UPLOAD_FILES_NOT_ALLOWED": "查看当前项目时无法上传文件", "UPLOAD_FOLDERS": "选择要上传的文件夹", @@ -355,7 +358,31 @@ "COPY_ITEMS": "将 {{ number }} 个项目复制到...", "MOVE_ITEM": "将 '{{ name }}' 移动到...", "MOVE_ITEMS": "将 {{ number }} 个项目移动到...", - "SEARCH": "搜索" + "SEARCH": "搜索", + "NEXT": "下一个", + "SELECT_FILE_TEMPLATE_TITLE": "选择一个文档模板", + "SELECT_FOLDER_TEMPLATE_TITLE": "选择一个文件夹模板" + }, + "NODE_FROM_TEMPLATE": { + "CANCEL": "取消", + "CREATE": "创建", + "FOLDER_DIALOG_TITLE": "从 '{{ template }}' 创建新文件夹", + "FILE_DIALOG_TITLE": "从 '{{ template }}' 创建新文档", + "FORM": { + "PLACEHOLDER": { + "NAME": "名称", + "TITLE": "标题", + "DESCRIPTION": "说明" + }, + "ERRORS": { + "DESCRIPTION_TOO_LONG": "对描述使用 512 个字符或更少字符", + "TITLE_TOO_LONG": "对标题使用 256 个字符或更少字符", + "REQUIRED": "需要名称", + "SPECIAL_CHARACTERS": "名称不能包含字符 * \" < > \\ / ? : |", + "ENDING_DOT": "名称不能以句号 . 结尾", + "ONLY_SPACES": "名称不能仅包含空格" + } + } }, "PERMISSIONS": { "DIALOG": { @@ -519,4 +546,4 @@ "BASELINE-LOCK-24PX": "已锁定文件" } } -} +} \ No newline at end of file