diff --git a/e2e/suites/actions/toolbar-multiple-selection.test.ts b/e2e/suites/actions/toolbar-multiple-selection.test.ts index 56c67ac1d..a717626db 100755 --- a/e2e/suites/actions/toolbar-multiple-selection.test.ts +++ b/e2e/suites/actions/toolbar-multiple-selection.test.ts @@ -135,11 +135,6 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple files are selected', () => { dataTable.selectMultipleItems([file1, file2]) - .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); - }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); @@ -154,11 +149,6 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple folders are selected', () => { dataTable.selectMultipleItems([folder1, folder2]) - .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); - }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); @@ -171,13 +161,39 @@ describe('Toolbar actions - multiple selection : ', () => { .then(() => dataTable.clearSelection()); }); + it('should display View action when at least one file selected', async () => { + await dataTable.selectMultipleItems([folder1, file1, folder2]); + expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'Action is not displayed'); + }); + + it('should not display View action when only folders selected', async () => { + await dataTable.selectMultipleItems([folder1, folder2]); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'Action is displayed'); + }); + + it('should display Download action for selected items', async () => { + await dataTable.selectMultipleItems([folder1, file1, folder2]); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Action is not displayed'); + }); + + it('should not display Download action for empty selection', async () => { + await dataTable.selectMultipleItems([folder1, file1, folder2]); + await dataTable.clearSelection(); + expect(toolbar.actions.isButtonPresent('Download')).toBe(false, 'Action is displayed'); + }); + + it('should display Edit action when at least one folder selected', async () => { + await dataTable.selectMultipleItems([folder1, file1, folder2]); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Action is not displayed'); + }); + + it('should not display Edit action if no folders selected', async () => { + await dataTable.selectMultipleItems([file1, file2]); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Action is displayed'); + }); + it('correct actions appear when both files and folders are selected', () => { dataTable.selectMultipleItems([file1, file2, folder1, folder2]) - .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); - }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); @@ -228,7 +244,7 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple files are selected', () => { dataTable.selectMultipleItems([file1Admin, file2Admin]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View not displayed for selected files'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); }) @@ -247,9 +263,9 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple folders are selected', () => { dataTable.selectMultipleItems([folder1Admin, folder2Admin]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Edit is not displayed'); }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { @@ -266,9 +282,9 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when both files and folders are selected', () => { dataTable.selectMultipleItems([file1Admin, file2Admin, folder1Admin, folder2Admin]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Edit is not displayed'); }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { @@ -295,7 +311,7 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple files are selected', () => { dataTable.selectMultipleItems([file1Admin, file2Admin]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed for selected files'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); }) @@ -314,16 +330,16 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple folders are selected', () => { dataTable.selectMultipleItems([folder1Admin, folder2Admin]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed'); }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { - expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); - expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for selected files`); - expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for selected files`); - expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed`); + expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed`); + expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed`); }) // .then(() => browser.$('body').click()) .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) @@ -333,9 +349,9 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when both files and folders are selected', () => { dataTable.selectMultipleItems([file1Admin, file2Admin, folder1Admin, folder2Admin]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed'); }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { @@ -369,7 +385,7 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple files are selected', () => { dataTable.selectMultipleItems([file1, file2]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); }) @@ -404,9 +420,9 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple files are selected', () => { dataTable.selectMultipleItems([file1, file2]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed'); }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { @@ -439,9 +455,9 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple files are selected', () => { dataTable.selectMultipleItems([file1, file2]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed'); }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { @@ -458,9 +474,9 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple folders are selected', () => { dataTable.selectMultipleItems([folder1, folder2]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Edit is not displayed'); }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { @@ -477,9 +493,9 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when both files and folders are selected', () => { dataTable.selectMultipleItems([file1, file2, folder1, folder2]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Edit is not displayed'); }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { diff --git a/package-lock.json b/package-lock.json index 944545eca..76829abc0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-beta10", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-beta10.tgz", - "integrity": "sha512-uBHkDrp60oeen770MjCh8aCFZm/g8nOIdilruB26EXaj9KOE3ZJ2ptGrHVGf51qrWRyDjnne/dwKvHW2O+kxvA==", + "version": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-24b573b08f3a072327efefc0196bd949cbca3766.tgz", + "integrity": "sha512-5B/JHEsCdvksEP16TyS5yHtOT/zCOLj7uHS8lqGhu7Z20Cj5K7RTBwco4flTh3T8OSyoUBzdmp3HQgfqJk/QrQ==", "requires": { - "@alfresco/adf-core": "2.4.0-beta10", + "@alfresco/adf-core": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -24,7 +24,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-beta9", + "alfresco-js-api": "2.4.0-fed4e011ee70eb36b5e2015859e719153d70b6c2", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -40,15 +40,6 @@ "zone.js": "0.8.14" }, "dependencies": { - "alfresco-js-api": { - "version": "2.4.0-beta9", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-beta9.tgz", - "integrity": "sha512-4SlaFerEucx+Gnusf4dwhEfrCvwWTKBxJm1kwe7eoKnPJO0I6B/Zx1I/Dkvvw4GVqO2f5WYoab+XGQSdMNyOng==", - "requires": { - "event-emitter": "0.3.4", - "superagent": "3.8.2" - } - }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", @@ -70,9 +61,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-beta10", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-beta10.tgz", - "integrity": "sha512-w8W6Uv9QfLOWojF+2zpvnjlYsAhJErawc77rIFPROQIN81nibSQ8Y6Xm3NdsrCz2drlrKbx5XD8yzia+2QKeyw==", + "version": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-24b573b08f3a072327efefc0196bd949cbca3766.tgz", + "integrity": "sha512-vDC4Wz+j6uSEMzdZUhy5xB0Sm63brb360o+uiPXs0uMyL9agMEh5wUPAl4Zfic0alnlww8OGADA8r6sFwb7HhQ==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -88,7 +79,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-beta9", + "alfresco-js-api": "2.4.0-fed4e011ee70eb36b5e2015859e719153d70b6c2", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -104,15 +95,6 @@ "zone.js": "0.8.14" }, "dependencies": { - "alfresco-js-api": { - "version": "2.4.0-beta9", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-beta9.tgz", - "integrity": "sha512-4SlaFerEucx+Gnusf4dwhEfrCvwWTKBxJm1kwe7eoKnPJO0I6B/Zx1I/Dkvvw4GVqO2f5WYoab+XGQSdMNyOng==", - "requires": { - "event-emitter": "0.3.4", - "superagent": "3.8.2" - } - }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", @@ -674,9 +656,9 @@ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, "alfresco-js-api": { - "version": "2.4.0-beta9", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-beta9.tgz", - "integrity": "sha512-4SlaFerEucx+Gnusf4dwhEfrCvwWTKBxJm1kwe7eoKnPJO0I6B/Zx1I/Dkvvw4GVqO2f5WYoab+XGQSdMNyOng==", + "version": "2.4.0-fed4e011ee70eb36b5e2015859e719153d70b6c2", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-fed4e011ee70eb36b5e2015859e719153d70b6c2.tgz", + "integrity": "sha512-HWA2zLbuRTi1mjIoaEW2ZSWKMDfOWcYOgplFZovQgXUOaFZuPJH1AQ7RbImq/G5/NKwe9AJSUAnkg5vpuKEBTg==", "requires": { "event-emitter": "0.3.4", "superagent": "3.8.2" @@ -2400,9 +2382,9 @@ "dev": true }, "cookiejar": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz", - "integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" }, "copy-concurrently": { "version": "1.0.5", diff --git a/package.json b/package.json index 2799ebc8f..ff5d8ffcd 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-beta10", - "@alfresco/adf-core": "2.4.0-beta10", + "@alfresco/adf-content-services": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766", + "@alfresco/adf-core": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -48,7 +48,7 @@ "@ngrx/store-devtools": "^5.2.0", "@ngstack/electron": "0.1.0", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-beta9", + "alfresco-js-api": "2.4.0-fed4e011ee70eb36b5e2015859e719153d70b6c2", "core-js": "2.5.3", "cspell": "^2.1.12", "hammerjs": "2.0.8", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 8776393e8..46bf6cfe1 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -62,7 +62,6 @@ import { NodeMoveDirective } from './common/directives/node-move.directive'; import { NodeRestoreDirective } from './common/directives/node-restore.directive'; import { NodePermanentDeleteDirective } from './common/directives/node-permanent-delete.directive'; import { NodeUnshareDirective } from './common/directives/node-unshare.directive'; -import { NodeInfoDirective } from './common/directives/node-info.directive'; import { NodeVersionsDirective } from './common/directives/node-versions.directive'; import { VersionManagerDialogAdapterComponent } from './components/versions-dialog/version-manager-dialog-adapter.component'; import { BrowsingFilesService } from './common/services/browsing-files.service'; @@ -77,6 +76,7 @@ import { SortingPreferenceKeyDirective } from './directives/sorting-preference-k import { INITIAL_STATE } from './store/states/app.state'; import { appReducer } from './store/reducers/app.reducer'; +import { InfoDrawerComponent } from './components/info-drawer/info-drawer.component'; @NgModule({ @@ -127,12 +127,12 @@ import { appReducer } from './store/reducers/app.reducer'; NodeRestoreDirective, NodePermanentDeleteDirective, NodeUnshareDirective, - NodeInfoDirective, NodeVersionsDirective, VersionManagerDialogAdapterComponent, SearchComponent, SettingsComponent, - SortingPreferenceKeyDirective + SortingPreferenceKeyDirective, + InfoDrawerComponent ], providers: [ { provide: AppConfigService, useClass: HybridAppConfigService }, diff --git a/src/app/common/directives/node-info.directive.spec.ts b/src/app/common/directives/node-info.directive.spec.ts deleted file mode 100644 index 5b9784615..000000000 --- a/src/app/common/directives/node-info.directive.spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2018 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 { ComponentFixture, TestBed, async, fakeAsync, tick } from '@angular/core/testing'; -import { AlfrescoApiService, CoreModule } from '@alfresco/adf-core'; -import { NodeInfoDirective } from './node-info.directive'; - -@Component({ - template: '
' -}) -class TestComponent { - selection; -} - -describe('NodeInfoDirective', () => { - let fixture: ComponentFixture; - let component: TestComponent; - let apiService: AlfrescoApiService; - let nodeService; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ - CoreModule - ], - declarations: [ - TestComponent, - NodeInfoDirective - ] - }); - - fixture = TestBed.createComponent(TestComponent); - component = fixture.componentInstance; - apiService = TestBed.get(AlfrescoApiService); - })); - - beforeEach(() => { - nodeService = apiService.getInstance().nodes; - - spyOn(nodeService, 'getNodeInfo').and.returnValue(Promise.resolve({ - entry: { name: 'borg' } - })); - }); - - it('should not get node info onInit when selection is empty', () => { - component.selection = []; - - fixture.detectChanges(); - - expect(nodeService.getNodeInfo).not.toHaveBeenCalled(); - }); - - it('should get node info onInit when selection is not empty', () => { - component.selection = [{ entry: { id: 'id' } }]; - - fixture.detectChanges(); - - expect(nodeService.getNodeInfo).toHaveBeenCalled(); - }); - - it('should not get node info on event when selection is empty', () => { - component.selection = []; - - fixture.detectChanges(); - - document.dispatchEvent(new CustomEvent('click')); - - expect(nodeService.getNodeInfo).not.toHaveBeenCalled(); - }); - - it('should get node info on event from selection', () => { - component.selection = [{ entry: { id: 'id' } }]; - - fixture.detectChanges(); - - document.dispatchEvent(new CustomEvent('click')); - - expect(nodeService.getNodeInfo).toHaveBeenCalledWith('id', { include: [ 'allowableOperations' ] }); - }); - - - it('should get node info of last entry when selecting multiple nodes', fakeAsync(() => { - component.selection = [ - { entry: { id: 'id1', isFile: true } }, - { entry: { id: 'id2', isFile: true } }, - { entry: { id: 'id3', isFile: true } } - ]; - - fixture.detectChanges(); - - document.dispatchEvent(new CustomEvent('click')); - - fixture.detectChanges(); - tick(); - - expect(nodeService.getNodeInfo).toHaveBeenCalledWith('id3', { include: [ 'allowableOperations' ] }); - })); -}); diff --git a/src/app/common/directives/node-info.directive.ts b/src/app/common/directives/node-info.directive.ts deleted file mode 100644 index 0ecd2ea1e..000000000 --- a/src/app/common/directives/node-info.directive.ts +++ /dev/null @@ -1,83 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2018 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 { Directive, HostListener, Input, Output, EventEmitter, OnInit } from '@angular/core'; -import { AlfrescoApiService } from '@alfresco/adf-core'; -import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api'; - -@Directive({ - selector: '[acaNodeInfo]', - exportAs: 'nodeInfo' -}) - -export class NodeInfoDirective implements OnInit { - // tslint:disable-next-line:no-input-rename - @Input('acaNodeInfo') selection: MinimalNodeEntity[]; - @Output() changed: EventEmitter = new EventEmitter(); - @Output() error: EventEmitter = new EventEmitter(); - - node: MinimalNodeEntryEntity; - loading: boolean = null; - - @HostListener('document:node-click', ['$event']) - onClick(event) { - this.getNodeInfo(); - } - - constructor(private apiService: AlfrescoApiService) {} - - ngOnInit() { - this.getNodeInfo(); - } - - getNodeInfo() { - if (!this.selection.length) { - this.node = null; - this.loading = false; - this.changed.emit(null); - return; - } - - const node = this.selection[this.selection.length - 1]; - - if (node) { - this.loading = true; - - this.apiService.getInstance().nodes - .getNodeInfo((node.entry).nodeId || node.entry.id, { - include: ['allowableOperations'] - }) - .then((data: MinimalNodeEntryEntity) => { - this.node = data; - this.changed.emit(data); - this.loading = false; - }) - .catch(() => { - this.error.emit(); - this.loading = false; - }); - } - } -} diff --git a/src/app/common/directives/node-permanent-delete.directive.spec.ts b/src/app/common/directives/node-permanent-delete.directive.spec.ts index 755f632b4..989f78f79 100644 --- a/src/app/common/directives/node-permanent-delete.directive.spec.ts +++ b/src/app/common/directives/node-permanent-delete.directive.spec.ts @@ -31,6 +31,7 @@ import { AlfrescoApiService, TranslationService, NotificationService, CoreModule import { NodePermanentDeleteDirective } from './node-permanent-delete.directive'; import { MatDialogModule, MatDialog } from '@angular/material'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; @Component({ template: `
` @@ -53,6 +54,7 @@ describe('NodePermanentDeleteDirective', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ + NoopAnimationsModule, CoreModule, MatDialogModule ], @@ -69,7 +71,10 @@ describe('NodePermanentDeleteDirective', () => { directiveInstance = element.injector.get(NodePermanentDeleteDirective); dialog = TestBed.get(MatDialog); + alfrescoService = TestBed.get(AlfrescoApiService); + alfrescoService.reset(); + translation = TestBed.get(TranslationService); notificationService = TestBed.get(NotificationService); }); diff --git a/src/app/common/directives/node-restore.directive.spec.ts b/src/app/common/directives/node-restore.directive.spec.ts index 9a7c55708..2b9af8b3b 100644 --- a/src/app/common/directives/node-restore.directive.spec.ts +++ b/src/app/common/directives/node-restore.directive.spec.ts @@ -33,7 +33,7 @@ import { Observable } from 'rxjs/Rx'; import { AlfrescoApiService, TranslationService, NotificationService, CoreModule } from '@alfresco/adf-core'; import { NodeRestoreDirective } from './node-restore.directive'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; @Component({ template: `
` @@ -57,7 +57,7 @@ describe('NodeRestoreDirective', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - BrowserAnimationsModule, + NoopAnimationsModule, RouterTestingModule, CoreModule ], @@ -74,6 +74,8 @@ describe('NodeRestoreDirective', () => { directiveInstance = element.injector.get(NodeRestoreDirective); alfrescoService = TestBed.get(AlfrescoApiService); + alfrescoService.reset(); + translation = TestBed.get(TranslationService); notificationService = TestBed.get(NotificationService); router = TestBed.get(Router); diff --git a/src/app/common/directives/node-versions.directive.ts b/src/app/common/directives/node-versions.directive.ts index 93c209f35..6b8551dab 100644 --- a/src/app/common/directives/node-versions.directive.ts +++ b/src/app/common/directives/node-versions.directive.ts @@ -26,7 +26,7 @@ import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core'; import { TranslationService, NotificationService, AlfrescoApiService } from '@alfresco/adf-core'; -import { MinimalNodeEntity } from 'alfresco-js-api'; +import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api'; import { VersionManagerDialogAdapterComponent } from '../../components/versions-dialog/version-manager-dialog-adapter.component'; import { MatDialog } from '@angular/material'; @@ -38,7 +38,7 @@ export class NodeVersionsDirective { // tslint:disable-next-line:no-input-rename @Input('acaNodeVersions') - selection: MinimalNodeEntity[]; + node: MinimalNodeEntity; @Output() nodeVersionError: EventEmitter = new EventEmitter(); @@ -55,17 +55,23 @@ export class NodeVersionsDirective { private translation: TranslationService ) {} - onManageVersions() { - const contentEntry = this.selection[0].entry; - const nodeId = (contentEntry).nodeId; - - this.apiService.getInstance().nodes.getNodeInfo(nodeId || contentEntry.id, { - include: ['allowableOperations'] - }).then(entry => this.openVersionManagerDialog(entry)); + async onManageVersions() { + if (this.node && this.node.entry) { + let entry = this.node.entry; + if (entry.nodeId) { + entry = await this.apiService.nodesApi.getNodeInfo( + entry.nodeId, + { include: ['allowableOperations'] } + ); + this.openVersionManagerDialog(entry); + } else { + this.openVersionManagerDialog(entry); + } + } } - openVersionManagerDialog(contentEntry) { + openVersionManagerDialog(contentEntry: MinimalNodeEntryEntity) { if (contentEntry.isFile) { this.dialog.open( VersionManagerDialogAdapterComponent, diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index 9d6bc4283..5d7e66bea 100644 --- a/src/app/components/favorites/favorites.component.html +++ b/src/app/components/favorites/favorites.component.html @@ -3,39 +3,37 @@ - + @@ -100,7 +97,10 @@ [navigate]="false" [sorting]="[ 'modifiedAt', 'desc' ]" [acaSortingPreferenceKey]="sortingPreferenceKey" - (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"> + (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)" + (ready)="onDocumentListReady($event, documentList)" + (node-select)="onNodeSelect($event, documentList)" + (node-unselect)="onNodeUnselect($event, documentList)"> @@ -168,39 +168,8 @@ -
- - - -
- -
- - - -
- - - - - - - -
- face - {{ 'VERSION.SELECTION.EMPTY' | translate }} -
-
-
-
+
+
diff --git a/src/app/components/favorites/favorites.component.spec.ts b/src/app/components/favorites/favorites.component.spec.ts index 22227f806..7b5e7bf88 100644 --- a/src/app/components/favorites/favorites.component.spec.ts +++ b/src/app/components/favorites/favorites.component.spec.ts @@ -44,10 +44,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; -import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { FavoritesComponent } from './favorites.component'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; describe('Favorites Routed Component', () => { let fixture: ComponentFixture; @@ -95,14 +97,14 @@ describe('Favorites Routed Component', () => { HttpClientModule, TranslateModule.forRoot(), RouterTestingModule, - MatSnackBarModule, MatIconModule + MatSnackBarModule, MatIconModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ DataTableComponent, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, - NodeInfoDirective, DocumentListComponent, FavoritesComponent, AppConfigPipe @@ -232,56 +234,6 @@ describe('Favorites Routed Component', () => { }); }); - describe('edit option', () => { - it('should return false if a file node is selected', () => { - const selection = [ - { - entry: { - isFolder: false, - isFile: true - } - } - ]; - - const result = component.showEditOption(selection); - expect(result).toBe(false); - }); - - it('should return false if multiple nodes are selected', () => { - const selection = [ - { - entry: { - isFolder: true, - isFile: false - } - }, - { - entry: { - isFolder: true, - isFile: false - } - } - ]; - - const result = component.showEditOption(selection); - expect(result).toBe(false); - }); - - it('should return true if selected node is a folder', () => { - const selection = [ - { - entry: { - isFolder: true, - isFile: false - } - } - ]; - - const result = component.showEditOption(selection); - expect(result).toBe(true); - }); - }); - describe('refresh', () => { it('should call document list reload', () => { spyOn(component.documentList, 'reload'); diff --git a/src/app/components/favorites/favorites.component.ts b/src/app/components/favorites/favorites.component.ts index 67d8d1f92..83e302e6b 100644 --- a/src/app/components/favorites/favorites.component.ts +++ b/src/app/components/favorites/favorites.component.ts @@ -25,30 +25,35 @@ import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; -import { MinimalNodeEntryEntity, MinimalNodeEntity, PathElementEntity, PathInfo } from 'alfresco-js-api'; +import { MinimalNodeEntryEntity, PathElementEntity, PathInfo } from 'alfresco-js-api'; import { ContentService, NodesApiService, UserPreferencesService, NotificationService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { PageComponent } from '../page.component'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../../store/states/app.state'; @Component({ templateUrl: './favorites.component.html' }) export class FavoritesComponent extends PageComponent implements OnInit { - constructor(private router: Router, + constructor(router: Router, route: ActivatedRoute, + store: Store, private nodesApi: NodesApiService, private contentService: ContentService, private content: ContentManagementService, private notificationService: NotificationService, public permission: NodePermissionService, preferences: UserPreferencesService) { - super(preferences, route); + super(preferences, router, route, store); } ngOnInit() { + super.ngOnInit(); + this.subscriptions = this.subscriptions.concat([ this.content.nodeDeleted.subscribe(() => this.reload()), this.content.nodeRestored.subscribe(() => this.reload()), @@ -87,10 +92,6 @@ export class FavoritesComponent extends PageComponent implements OnInit { } } - showEditOption(selection: MinimalNodeEntity[]) { - return selection && selection.length === 1 && selection[0].entry.isFolder; - } - openSnackMessage(event: any) { this.notificationService.openSnackMessage( event, diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index d7de9b902..5c50a342f 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -6,39 +6,36 @@ (navigate)="onBreadcrumbNavigate($event)"> - + @@ -117,7 +113,9 @@ [navigate]="false" [imageResolver]="imageResolver" (node-dblclick)="onNodeDoubleClick($event)" - (node-select)="onNodeSelect($event, documentList)"> + (ready)="onDocumentListReady($event, documentList)" + (node-select)="onNodeSelect($event, documentList)" + (node-unselect)="onNodeUnselect($event, documentList)"> -
- - - -
- -
- - - -
- - - - - - - -
- face - {{ 'VERSION.SELECTION.EMPTY' | translate }} -
-
-
-
+
+
diff --git a/src/app/components/files/files.component.spec.ts b/src/app/components/files/files.component.spec.ts index 220c7e91c..bf9642628 100644 --- a/src/app/components/files/files.component.spec.ts +++ b/src/app/components/files/files.component.spec.ts @@ -46,9 +46,11 @@ import { ContentManagementService } from '../../common/services/content-manageme import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { NodeActionsService } from '../../common/services/node-actions.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; -import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { FilesComponent } from './files.component'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; describe('FilesComponent', () => { let node; @@ -73,7 +75,8 @@ describe('FilesComponent', () => { TranslateModule.forRoot(), RouterTestingModule, MatSnackBarModule, MatIconModule, - MatDialogModule + MatDialogModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ FilesComponent, @@ -81,7 +84,6 @@ describe('FilesComponent', () => { TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, - NodeInfoDirective, DocumentListComponent, FileSizePipe, AppConfigPipe diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index 7c7e57ca4..9973f0ef2 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -38,6 +38,8 @@ import { NodeActionsService } from '../../common/services/node-actions.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { PageComponent } from '../page.component'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../../store/states/app.state'; @Component({ templateUrl: './files.component.html' @@ -48,8 +50,9 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { private nodePath: PathElement[]; - constructor(private router: Router, + constructor(router: Router, route: ActivatedRoute, + store: Store, private nodesApi: NodesApiService, private nodeActionsService: NodeActionsService, private uploadService: UploadService, @@ -60,10 +63,12 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { private notificationService: NotificationService, public permission: NodePermissionService, preferences: UserPreferencesService) { - super(preferences, route); + super(preferences, router, route, store); } ngOnInit() { + super.ngOnInit(); + const { route, contentManagementService, contentService, nodeActionsService, uploadService } = this; const { data } = route.snapshot; @@ -156,14 +161,6 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { } } - showPreview(node: MinimalNodeEntryEntity) { - if (node) { - if (node.isFile) { - this.router.navigate(['./preview', node.id], { relativeTo: this.route }); - } - } - } - onBreadcrumbNavigate(route: PathElementEntity) { // todo: review this approach once 5.2.3 is out if (this.nodePath && this.nodePath.length > 2) { diff --git a/src/app/components/header/header.component.spec.ts b/src/app/components/header/header.component.spec.ts index 139ecda59..66347206e 100644 --- a/src/app/components/header/header.component.spec.ts +++ b/src/app/components/header/header.component.spec.ts @@ -50,7 +50,7 @@ describe('HeaderComponent', () => { HttpClientModule, RouterTestingModule, TranslateModule.forRoot(), - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ HeaderComponent diff --git a/src/app/components/info-drawer/info-drawer.component.html b/src/app/components/info-drawer/info-drawer.component.html new file mode 100644 index 000000000..99468992f --- /dev/null +++ b/src/app/components/info-drawer/info-drawer.component.html @@ -0,0 +1,28 @@ +
+ +
+ + + + + + + + + + + + + +
+ face + {{ 'VERSION.SELECTION.EMPTY' | translate }} +
+
+
+
+
diff --git a/src/app/components/info-drawer/info-drawer.component.ts b/src/app/components/info-drawer/info-drawer.component.ts new file mode 100644 index 000000000..df3b064f8 --- /dev/null +++ b/src/app/components/info-drawer/info-drawer.component.ts @@ -0,0 +1,94 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 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, OnChanges, SimpleChanges } from '@angular/core'; +import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api'; +import { NodePermissionService } from '../../common/services/node-permission.service'; +import { AlfrescoApiService } from '@alfresco/adf-core'; + +@Component({ + selector: 'aca-info-drawer', + templateUrl: './info-drawer.component.html' +}) +export class InfoDrawerComponent implements OnChanges { + @Input() nodeId: string; + + @Input() node: MinimalNodeEntity; + + isLoading = false; + displayNode: MinimalNodeEntryEntity; + + canUpdateNode(): boolean { + if (this.node) { + if ((this.node.entry).nodeId) { + return this.permission.check(this.node.entry, ['update'], { + target: 'allowableOperationsOnTarget' + }); + } + return this.permission.check(this.node.entry, ['update']); + } + + return false; + } + + get isFileSelected(): boolean { + if (this.node && this.node.entry) { + return this.node.entry.isFile; + } + return false; + } + + constructor( + public permission: NodePermissionService, + private apiService: AlfrescoApiService + ) {} + + ngOnChanges(changes: SimpleChanges) { + if (this.node) { + const entry = this.node.entry; + if (entry.nodeId) { + this.loadNodeInfo(entry.nodeId); + } else { + this.displayNode = this.node.entry; + } + } + } + + private loadNodeInfo(nodeId: string) { + if (nodeId) { + this.isLoading = true; + + this.apiService.nodesApi + .getNodeInfo(nodeId, { include: ['allowableOperations'] }) + .then((entity: MinimalNodeEntryEntity) => { + this.displayNode = entity; + this.isLoading = false; + }) + .catch(() => { + this.isLoading = false; + }); + } + } +} diff --git a/src/app/components/libraries/libraries.component.html b/src/app/components/libraries/libraries.component.html index 9031c518d..0083aefba 100644 --- a/src/app/components/libraries/libraries.component.html +++ b/src/app/components/libraries/libraries.component.html @@ -14,6 +14,9 @@ [navigate]="false" [sorting]="[ 'title', 'asc' ]" [acaSortingPreferenceKey]="sortingPreferenceKey" + (ready)="onDocumentListReady($event, documentList)" + (node-select)="onNodeSelect($event, documentList)" + (node-unselect)="onNodeUnselect($event, documentList)" (node-dblclick)="onNodeDoubleClick($event)"> diff --git a/src/app/components/libraries/libraries.component.spec.ts b/src/app/components/libraries/libraries.component.spec.ts index 28ed0f3ce..fc2e0db7f 100644 --- a/src/app/components/libraries/libraries.component.spec.ts +++ b/src/app/components/libraries/libraries.component.spec.ts @@ -44,6 +44,9 @@ import { DocumentListService } from '@alfresco/adf-content-services'; import { ShareDataTableAdapter } from '@alfresco/adf-content-services'; import { LibrariesComponent } from './libraries.component'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; describe('Libraries Routed Component', () => { let fixture: ComponentFixture; @@ -78,7 +81,8 @@ describe('Libraries Routed Component', () => { HttpClientModule, TranslateModule.forRoot(), RouterTestingModule, - MatSnackBarModule, MatIconModule + MatSnackBarModule, MatIconModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ DataTableComponent, diff --git a/src/app/components/libraries/libraries.component.ts b/src/app/components/libraries/libraries.component.ts index 0d66e02ba..a34c0215d 100644 --- a/src/app/components/libraries/libraries.component.ts +++ b/src/app/components/libraries/libraries.component.ts @@ -29,6 +29,8 @@ import { NodesApiService, UserPreferencesService } from '@alfresco/adf-core'; import { ShareDataRow } from '@alfresco/adf-content-services'; import { PageComponent } from '../page.component'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../../store/states/app.state'; @Component({ templateUrl: './libraries.component.html' @@ -37,9 +39,10 @@ export class LibrariesComponent extends PageComponent { constructor(private nodesApi: NodesApiService, route: ActivatedRoute, - private router: Router, + store: Store, + router: Router, preferences: UserPreferencesService) { - super(preferences, route); + super(preferences, router, route, store); } makeLibraryTooltip(library: any): string { diff --git a/src/app/components/page.component.spec.ts b/src/app/components/page.component.spec.ts index 2543ec889..fc38e6fce 100644 --- a/src/app/components/page.component.spec.ts +++ b/src/app/components/page.component.spec.ts @@ -24,17 +24,22 @@ */ import { PageComponent } from './page.component'; +import { MinimalNodeEntity } from 'alfresco-js-api'; class TestClass extends PageComponent { node: any; + setSelection(selection: MinimalNodeEntity[] = []) { + this.onSelectionChanged(selection); + } + constructor() { - super(null, null); + super(null, null, null, null); } } describe('PageComponent', () => { - let component; + let component: TestClass; beforeEach(() => { component = new TestClass(); @@ -56,47 +61,44 @@ describe('PageComponent', () => { describe('hasSelection()', () => { it('returns true when it has nodes selected', () => { - const hasSelection = component.hasSelection([ {}, {} ]); - expect(hasSelection).toBe(true); + component.setSelection([ + { entry: { isFile: true } }, + { entry: { isFile: true } } + ]); + expect(component.hasSelection).toBe(true); }); it('returns false when it has no selections', () => { - const hasSelection = component.hasSelection([]); - expect(hasSelection).toBe(false); + component.setSelection([]); + expect(component.hasSelection).toBe(false); }); }); - describe('isFileSelected()', () => { + describe('firstSelectedDocument', () => { it('returns true if selected node is file', () => { const selection = [ { entry: { isFile: true } } ]; - expect(component.isFileSelected(selection)).toBe(true); + component.setSelection(selection); + expect(component.firstSelectedDocument).toBe(selection[0]); }); it('returns false if selected node is folder', () => { - const selection = [ { entry: { isFolder: true } } ]; - expect(component.isFileSelected(selection)).toBe(false); - }); - - it('returns false if there are more than one selections', () => { - const selection = [ { entry: { isFile: true } }, { entry: { isFile: true } } ]; - expect(component.isFileSelected(selection)).toBe(false); + const selection = [ { entry: { isFile: false, isFolder: true } } ]; + component.setSelection(selection); + expect(component.firstSelectedDocument).toBeFalsy(); }); }); - describe('isFolderSelected()', () => { + describe('firstSelectedFolder', () => { it('returns true if selected node is folder', () => { - const selection = [ { entry: { isFolder: true } } ]; - expect(component.isFolderSelected(selection)).toBe(true); + const selection = [ { entry: { isFile: false, isFolder: true } } ]; + component.setSelection(selection); + expect(component.firstSelectedFolder).toBe(selection[0]); }); it('returns false if selected node is file', () => { - const selection = [ { entry: { isFile: true } } ]; - expect(component.isFolderSelected(selection)).toBe(false); - }); - - it('returns false if there are more than one selections', () => { - const selection = [ { entry: { isFolder: true } }, { entry: { isFolder: true } } ]; - expect(component.isFolderSelected(selection)).toBe(false); + const selection = [ { entry: { isFile: true, isFolder: false } } ]; + component.setSelection(selection); + expect(component.firstSelectedFolder).toBeFalsy(); }); }); }); diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index edcd1b126..b2dfce3d2 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -26,11 +26,18 @@ import { MinimalNodeEntity, MinimalNodeEntryEntity, Pagination } from 'alfresco-js-api'; import { UserPreferencesService } from '@alfresco/adf-core'; import { ShareDataRow, DocumentListComponent } from '@alfresco/adf-content-services'; -import { ActivatedRoute } from '@angular/router'; -import { OnDestroy, ViewChild } from '@angular/core'; -import { Subscription } from 'rxjs/Rx'; +import { ActivatedRoute, Router } from '@angular/router'; +import { OnDestroy, ViewChild, OnInit } from '@angular/core'; +import { Subscription, Subject } from 'rxjs/Rx'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../store/states/app.state'; +import { SetSelectedNodesAction } from '../store/actions/select-nodes.action'; +import { selectedNodes } from '../store/selectors/app.selectors'; +import { takeUntil } from 'rxjs/operators'; -export abstract class PageComponent implements OnDestroy { +export abstract class PageComponent implements OnInit, OnDestroy { + + onDestroy$: Subject = new Subject(); @ViewChild(DocumentListComponent) documentList: DocumentListComponent; @@ -39,6 +46,13 @@ export abstract class PageComponent implements OnDestroy { infoDrawerOpened = false; node: MinimalNodeEntryEntity; + hasSelection = false; + firstSelectedDocument: MinimalNodeEntity; + firstSelectedFolder: MinimalNodeEntity; + firstSelectedNode: MinimalNodeEntity; + lastSelectedNode: MinimalNodeEntity; + selectedNodes: MinimalNodeEntity[]; + protected subscriptions: Subscription[] = []; get sortingPreferenceKey(): string { @@ -49,59 +63,82 @@ export abstract class PageComponent implements OnDestroy { return node.isLocked || (node.properties && node.properties['cm:lockType'] === 'READ_ONLY_LOCK'); } - constructor(protected preferences: UserPreferencesService, protected route: ActivatedRoute) { + constructor(protected preferences: UserPreferencesService, + protected router: Router, + protected route: ActivatedRoute, + protected store: Store) { + } + + ngOnInit() { + this.store + .select(selectedNodes) + .pipe(takeUntil(this.onDestroy$)) + .subscribe(selection => this.onSelectionChanged(selection)); } ngOnDestroy() { this.subscriptions.forEach(subscription => subscription.unsubscribe()); this.subscriptions = []; + this.onDestroy$.complete(); + } + + // Precalculates all the "static state" flags so that UI does not re-evaluate that on every tick + protected onSelectionChanged(selection: MinimalNodeEntity[] = []) { + this.selectedNodes = selection; + this.hasSelection = selection.length > 0; + + if (selection.length > 0) { + const firstNode = selection[0]; + this.firstSelectedNode = firstNode; + this.firstSelectedDocument = selection.find(entity => entity.entry.isFile); + this.firstSelectedFolder = selection.find(entity => entity.entry.isFolder); + } else { + this.firstSelectedNode = null; + this.firstSelectedDocument = null; + this.firstSelectedFolder = null; + this.lastSelectedNode = null; + this.infoDrawerOpened = false; + } + } + + showPreview(node: MinimalNodeEntity) { + if (node && node.entry) { + if (node.entry.isFile) { + this.router.navigate(['./preview', node.entry.id], { relativeTo: this.route }); + } + } } getParentNodeId(): string { return this.node ? this.node.id : null; } - hasSelection(selection: Array): boolean { - return selection && selection.length > 0; - } - - isFileSelected(selection: Array): boolean { - if (selection && selection.length === 1) { - const entry = selection[0].entry; - - if (entry && entry.isFile) { - return true; - } - } - return false; - } - - isFolderSelected(selection: Array): boolean { - if (selection && selection.length === 1) { - const entry = selection[0].entry; - - if (entry && entry.isFolder) { - return true; - } - } - return false; - } - onChangePageSize(event: Pagination): void { this.preferences.paginationSize = event.maxItems; } - onNodeSelect(event, documentList) { + onNodeSelect(event: CustomEvent, documentList: DocumentListComponent) { if (!!event.detail && !!event.detail.node) { const node: MinimalNodeEntryEntity = event.detail.node.entry; if (node && PageComponent.isLockedNode(node)) { this.unSelectLockedNodes(documentList); } + + this.lastSelectedNode = event.detail.node; + this.store.dispatch(new SetSelectedNodesAction(documentList.selection)); } } - unSelectLockedNodes(documentList) { + onDocumentListReady(event: CustomEvent, documentList: DocumentListComponent) { + this.store.dispatch(new SetSelectedNodesAction(documentList.selection)); + } + + onNodeUnselect(event: CustomEvent, documentList: DocumentListComponent) { + this.store.dispatch(new SetSelectedNodesAction(documentList.selection)); + } + + unSelectLockedNodes(documentList: DocumentListComponent) { documentList.selection = documentList.selection.filter(item => !PageComponent.isLockedNode(item.entry)); const dataTable = documentList.dataTable; @@ -143,6 +180,7 @@ export abstract class PageComponent implements OnDestroy { reload(): void { if (this.documentList) { this.documentList.resetSelection(); + this.store.dispatch(new SetSelectedNodesAction([])); this.documentList.reload(); } } diff --git a/src/app/components/preview/preview.component.html b/src/app/components/preview/preview.component.html index ef8420396..666879f6e 100644 --- a/src/app/components/preview/preview.component.html +++ b/src/app/components/preview/preview.component.html @@ -68,7 +68,7 @@ diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index 635316fa9..3019f1b10 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -3,29 +3,27 @@ - + @@ -95,7 +92,9 @@ [acaSortingPreferenceKey]="sortingPreferenceKey" [imageResolver]="imageResolver" (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)" - (node-select)="onNodeSelect($event, documentList)"> + (ready)="onDocumentListReady($event, documentList)" + (node-select)="onNodeSelect($event, documentList)" + (node-unselect)="onNodeUnselect($event, documentList)"> @@ -156,41 +155,8 @@ -
- - - -
- -
- - - -
- - - - - - - -
- face - {{ 'VERSION.SELECTION.EMPTY' | translate }} -
-
-
-
+
+
diff --git a/src/app/components/recent-files/recent-files.component.spec.ts b/src/app/components/recent-files/recent-files.component.spec.ts index 323a5b231..c89aa944b 100644 --- a/src/app/components/recent-files/recent-files.component.spec.ts +++ b/src/app/components/recent-files/recent-files.component.spec.ts @@ -41,10 +41,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; -import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { RecentFilesComponent } from './recent-files.component'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; describe('RecentFiles Routed Component', () => { let fixture: ComponentFixture; @@ -71,14 +73,14 @@ describe('RecentFiles Routed Component', () => { HttpClientModule, TranslateModule.forRoot(), RouterTestingModule, - MatSnackBarModule, MatIconModule + MatSnackBarModule, MatIconModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ DataTableComponent, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, - NodeInfoDirective, DocumentListComponent, RecentFilesComponent, AppConfigPipe diff --git a/src/app/components/recent-files/recent-files.component.ts b/src/app/components/recent-files/recent-files.component.ts index c771a410c..f74895f80 100644 --- a/src/app/components/recent-files/recent-files.component.ts +++ b/src/app/components/recent-files/recent-files.component.ts @@ -31,6 +31,8 @@ import { UserPreferencesService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { PageComponent } from '../page.component'; import { NodePermissionService } from '../../common/services/node-permission.service'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../../store/states/app.state'; @Component({ templateUrl: './recent-files.component.html' @@ -38,15 +40,18 @@ import { NodePermissionService } from '../../common/services/node-permission.ser export class RecentFilesComponent extends PageComponent implements OnInit { constructor( - private router: Router, + router: Router, route: ActivatedRoute, + store: Store, private content: ContentManagementService, public permission: NodePermissionService, preferences: UserPreferencesService) { - super(preferences, route); + super(preferences, router, route, store); } ngOnInit() { + super.ngOnInit(); + this.subscriptions = this.subscriptions.concat([ this.content.nodeDeleted.subscribe(() => this.reload()), this.content.nodeMoved.subscribe(() => this.reload()), diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index 15beb27c8..41c8c843e 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -3,28 +3,25 @@ - + @@ -100,7 +96,10 @@ selectionMode="multiple" [sorting]="[ 'modifiedAt', 'desc' ]" [acaSortingPreferenceKey]="sortingPreferenceKey" - (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"> + (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)" + (ready)="onDocumentListReady($event, documentList)" + (node-select)="onNodeSelect($event, documentList)" + (node-unselect)="onNodeUnselect($event, documentList)"> @@ -173,41 +172,8 @@ -
- - - -
- -
- - - -
- - - - - - - -
- face - {{ 'VERSION.SELECTION.EMPTY' | translate }} -
-
-
-
+
+
diff --git a/src/app/components/shared-files/shared-files.component.spec.ts b/src/app/components/shared-files/shared-files.component.spec.ts index 730702330..ab1c3a15a 100644 --- a/src/app/components/shared-files/shared-files.component.spec.ts +++ b/src/app/components/shared-files/shared-files.component.spec.ts @@ -41,10 +41,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; -import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { SharedFilesComponent } from './shared-files.component'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; describe('SharedFilesComponent', () => { let fixture: ComponentFixture; @@ -73,14 +75,14 @@ describe('SharedFilesComponent', () => { HttpClientModule, TranslateModule.forRoot(), RouterTestingModule, - MatSnackBarModule, MatIconModule + MatSnackBarModule, MatIconModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ DataTableComponent, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, - NodeInfoDirective, DocumentListComponent, SharedFilesComponent, AppConfigPipe diff --git a/src/app/components/shared-files/shared-files.component.ts b/src/app/components/shared-files/shared-files.component.ts index f6c7cc5a4..e23806878 100644 --- a/src/app/components/shared-files/shared-files.component.ts +++ b/src/app/components/shared-files/shared-files.component.ts @@ -31,22 +31,27 @@ import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { PageComponent } from '../page.component'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../../store/states/app.state'; @Component({ templateUrl: './shared-files.component.html' }) export class SharedFilesComponent extends PageComponent implements OnInit { - constructor(private router: Router, + constructor(router: Router, route: ActivatedRoute, + store: Store, private content: ContentManagementService, private apiService: AlfrescoApiService, public permission: NodePermissionService, preferences: UserPreferencesService) { - super(preferences, route); + super(preferences, router, route, store); } ngOnInit() { + super.ngOnInit(); + this.subscriptions = this.subscriptions.concat([ this.content.nodeDeleted.subscribe(() => this.reload()), this.content.nodeMoved.subscribe(() => this.reload()), @@ -65,9 +70,4 @@ export class SharedFilesComponent extends PageComponent implements OnInit { ); } } - - /** @override */ - isFileSelected(selection: Array): boolean { - return selection && selection.length === 1; - } } diff --git a/src/app/components/sidenav/sidenav.component.spec.ts b/src/app/components/sidenav/sidenav.component.spec.ts index 4d48dbca5..73df9f2fb 100644 --- a/src/app/components/sidenav/sidenav.component.spec.ts +++ b/src/app/components/sidenav/sidenav.component.spec.ts @@ -32,13 +32,14 @@ import { HttpClientModule } from '@angular/common/http'; import { AppConfigService, AuthenticationService, UserPreferencesService, StorageService, AlfrescoApiService, - CookieService, LogService, NotificationService + CookieService, LogService, NotificationService, TranslationService, TranslationMock } from '@alfresco/adf-core'; import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { SidenavComponent } from './sidenav.component'; import { ElectronModule } from '@ngstack/electron'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; describe('SidenavComponent', () => { let fixture; @@ -58,6 +59,7 @@ describe('SidenavComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ + NoopAnimationsModule, HttpClientModule, MatMenuModule, MatSnackBarModule, @@ -69,6 +71,7 @@ describe('SidenavComponent', () => { SidenavComponent ], providers: [ + { provide: TranslationService, useClass: TranslationMock }, LogService, CookieService, AlfrescoApiService, diff --git a/src/app/components/trashcan/trashcan.component.html b/src/app/components/trashcan/trashcan.component.html index 12775a851..e792b078f 100644 --- a/src/app/components/trashcan/trashcan.component.html +++ b/src/app/components/trashcan/trashcan.component.html @@ -3,13 +3,12 @@ - + @@ -18,8 +17,7 @@ color="primary" mat-icon-button (selection-node-restored)="reload()" - [acaRestoreNode]="documentList.selection" - *ngIf="documentList.selection.length" + [acaRestoreNode]="selectedNodes" title="{{ 'APP.ACTIONS.RESTORE' | translate }}"> restore @@ -33,7 +31,10 @@ selectionMode="multiple" [navigate]="false" [sorting]="[ 'archivedAt', 'desc' ]" - [acaSortingPreferenceKey]="sortingPreferenceKey"> + [acaSortingPreferenceKey]="sortingPreferenceKey" + (ready)="onDocumentListReady($event, documentList)" + (node-select)="onNodeSelect($event, documentList)" + (node-unselect)="onNodeUnselect($event, documentList)"> diff --git a/src/app/components/trashcan/trashcan.component.spec.ts b/src/app/components/trashcan/trashcan.component.spec.ts index 7ba36264a..d646e10e1 100644 --- a/src/app/components/trashcan/trashcan.component.spec.ts +++ b/src/app/components/trashcan/trashcan.component.spec.ts @@ -40,9 +40,11 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; -import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { TrashcanComponent } from './trashcan.component'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; describe('TrashcanComponent', () => { let fixture: ComponentFixture; @@ -68,14 +70,14 @@ describe('TrashcanComponent', () => { HttpClientModule, TranslateModule.forRoot(), RouterTestingModule, - MatSnackBarModule, MatIconModule + MatSnackBarModule, MatIconModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ DataTableComponent, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, - NodeInfoDirective, DocumentListComponent, TrashcanComponent, AppConfigPipe diff --git a/src/app/components/trashcan/trashcan.component.ts b/src/app/components/trashcan/trashcan.component.ts index 542a1dec0..37ccdbf5b 100644 --- a/src/app/components/trashcan/trashcan.component.ts +++ b/src/app/components/trashcan/trashcan.component.ts @@ -24,11 +24,13 @@ */ import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { Pagination } from 'alfresco-js-api'; import { UserPreferencesService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { PageComponent } from '../page.component'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../../store/states/app.state'; @Component({ templateUrl: './trashcan.component.html' @@ -37,11 +39,15 @@ export class TrashcanComponent extends PageComponent implements OnInit { constructor(private contentManagementService: ContentManagementService, preferences: UserPreferencesService, + store: Store, + router: Router, route: ActivatedRoute) { - super(preferences, route); + super(preferences, router, route, store); } ngOnInit() { + super.ngOnInit(); + this.subscriptions.push( this.contentManagementService.nodeRestored.subscribe(() => this.reload()) ); diff --git a/src/app/store/actions/select-nodes.action.ts b/src/app/store/actions/select-nodes.action.ts new file mode 100644 index 000000000..1e0646fd5 --- /dev/null +++ b/src/app/store/actions/select-nodes.action.ts @@ -0,0 +1,8 @@ +import { Action } from '@ngrx/store'; + +export const SET_SELECTED_NODES = 'SET_SELECTED_NODES'; + +export class SetSelectedNodesAction implements Action { + readonly type = SET_SELECTED_NODES; + constructor(public payload: any[] = []) {} +} diff --git a/src/app/store/reducers/app.reducer.ts b/src/app/store/reducers/app.reducer.ts index 48fa50df3..d12eae6ea 100644 --- a/src/app/store/reducers/app.reducer.ts +++ b/src/app/store/reducers/app.reducer.ts @@ -3,6 +3,7 @@ import { AppState, INITIAL_APP_STATE } from '../states/app.state'; import { SET_HEADER_COLOR, SetHeaderColorAction } from '../actions/header-color.action'; import { SET_APP_NAME, SetAppNameAction } from '../actions/app-name.action'; import { SET_LOGO_PATH, SetLogoPathAction } from '../actions/logo-path.action'; +import { SET_SELECTED_NODES, SetSelectedNodesAction } from '../actions/select-nodes.action'; export function appReducer(state: AppState = INITIAL_APP_STATE, action: Action): AppState { @@ -18,6 +19,9 @@ export function appReducer(state: AppState = INITIAL_APP_STATE, action: Action): case SET_LOGO_PATH: newState = updateLogoPath(state, action); break; + case SET_SELECTED_NODES: + newState = updateSelectedNodes(state, action); + break; default: newState = Object.assign({}, state); } @@ -42,3 +46,9 @@ function updateLogoPath(state: AppState, action: SetLogoPathAction): AppState { newState.logoPath = action.payload; return newState; } + +function updateSelectedNodes(state: AppState, action: SetSelectedNodesAction): AppState { + const newState = Object.assign({}, state); + newState.selectedNodes = [...action.payload]; + return newState; +} diff --git a/src/app/store/selectors/app.selectors.ts b/src/app/store/selectors/app.selectors.ts index 52e6a81f3..d49588766 100644 --- a/src/app/store/selectors/app.selectors.ts +++ b/src/app/store/selectors/app.selectors.ts @@ -5,3 +5,4 @@ export const selectApp = (state: AcaState) => state.app; export const selectHeaderColor = createSelector(selectApp, (state: AppState) => state.headerColor); export const selectAppName = createSelector(selectApp, (state: AppState) => state.appName); export const selectLogoPath = createSelector(selectApp, (state: AppState) => state.logoPath); +export const selectedNodes = createSelector(selectApp, (state: AppState) => state.selectedNodes); diff --git a/src/app/store/states/app.state.ts b/src/app/store/states/app.state.ts index 75fcd165d..370e2c78e 100644 --- a/src/app/store/states/app.state.ts +++ b/src/app/store/states/app.state.ts @@ -1,13 +1,17 @@ +import { MinimalNodeEntity } from 'alfresco-js-api'; + export interface AppState { appName: string; headerColor: string; logoPath: string; + selectedNodes: MinimalNodeEntity[]; } export const INITIAL_APP_STATE: AppState = { appName: 'Alfresco Example Content Application', headerColor: '#2196F3', - logoPath: 'assets/images/alfresco-logo-white.svg' + logoPath: 'assets/images/alfresco-logo-white.svg', + selectedNodes: [] }; export interface AcaState { diff --git a/tslint.json b/tslint.json index 34eed5a45..b43b9774e 100644 --- a/tslint.json +++ b/tslint.json @@ -122,7 +122,7 @@ "component-selector": [ true, "element", - "app", + [ "app", "aca"], "kebab-case" ], "use-input-property-decorator": true,