diff --git a/src/app.config.json b/src/app.config.json index d0220dfbf..e8f87d16f 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -70,6 +70,11 @@ "type": "DOWNLOAD_NODES", "payload": null }, + { + "id": "aca:actions/preview", + "type": "VIEW_FILE", + "payload": null + }, { "id": "aca:actions/info", @@ -206,6 +211,18 @@ "action": "aca:actions/create-folder" } }, + { + "disabled": false, + "id": "aca:toolbar/preview", + "order": 15, + "title": "APP.ACTIONS.VIEW", + "icon": "open_in_browser", + "target": { + "types": ["file"], + "permissions": [], + "action": "aca:actions/preview" + } + }, { "disabled": false, "id": "aca:toolbar/download", diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index d551e0875..02f282ce6 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -30,7 +30,7 @@ import { Store } from '@ngrx/store'; import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api'; import { takeUntil } from 'rxjs/operators'; import { Subject, Subscription } from 'rxjs/Rx'; -import { ViewNodeAction, SetSelectedNodesAction, DownloadNodesAction } from '../store/actions'; +import { SetSelectedNodesAction, DownloadNodesAction, ViewFileAction } from '../store/actions'; import { appSelection, sharedUrl, currentFolder } from '../store/selectors/app.selectors'; import { AppStore } from '../store/states/app.state'; import { SelectionState } from '../store/states/selection.state'; @@ -109,16 +109,8 @@ export abstract class PageComponent implements OnInit, OnDestroy { showPreview(node: MinimalNodeEntity) { if (node && node.entry) { - const { id, nodeId, name, isFile, isFolder } = node.entry; const parentId = this.node ? this.node.id : null; - - this.store.dispatch(new ViewNodeAction({ - parentId, - id: nodeId || id, - name, - isFile, - isFolder - })); + this.store.dispatch(new ViewFileAction(node, parentId)); } } diff --git a/src/app/components/search/search-input/search-input.component.spec.ts b/src/app/components/search/search-input/search-input.component.spec.ts index a1e7b421e..59d5a0614 100644 --- a/src/app/components/search/search-input/search-input.component.spec.ts +++ b/src/app/components/search/search-input/search-input.component.spec.ts @@ -29,7 +29,7 @@ import { TestBed, async, ComponentFixture, fakeAsync, tick } from '@angular/core import { SearchInputComponent } from './search-input.component'; import { AppTestingModule } from '../../../testing/app-testing.module'; import { Actions, ofType } from '@ngrx/effects'; -import { ViewNodeAction, VIEW_NODE, NAVIGATE_FOLDER, NavigateToFolder } from '../../../store/actions'; +import { NAVIGATE_FOLDER, NavigateToFolder, VIEW_FILE, ViewFileAction } from '../../../store/actions'; import { map } from 'rxjs/operators'; describe('SearchInputComponent', () => { @@ -59,9 +59,9 @@ describe('SearchInputComponent', () => { describe('onItemClicked()', () => { it('opens preview if node is file', fakeAsync(done => { actions$.pipe( - ofType(VIEW_NODE), + ofType(VIEW_FILE), map(action => { - expect(action.payload.id).toBe('node-id'); + expect(action.payload.entry.id).toBe('node-id'); done(); }) ); diff --git a/src/app/components/search/search-input/search-input.component.ts b/src/app/components/search/search-input/search-input.component.ts index c05e5ccf4..3a74cdb05 100644 --- a/src/app/components/search/search-input/search-input.component.ts +++ b/src/app/components/search/search-input/search-input.component.ts @@ -32,7 +32,7 @@ import { MinimalNodeEntity } from 'alfresco-js-api'; import { SearchInputControlComponent } from '../search-input-control/search-input-control.component'; import { Store } from '@ngrx/store'; import { AppStore } from '../../../store/states/app.state'; -import { SearchByTermAction, ViewNodeAction, NavigateToFolder } from '../../../store/actions'; +import { SearchByTermAction, NavigateToFolder, ViewFileAction } from '../../../store/actions'; @Component({ selector: 'aca-search-input', @@ -90,15 +90,9 @@ export class SearchInputComponent implements OnInit { onItemClicked(node: MinimalNodeEntity) { if (node && node.entry) { - const { id, nodeId, name, isFile, isFolder, parentId } = node.entry; + const { isFile, isFolder } = node.entry; if (isFile) { - this.store.dispatch(new ViewNodeAction({ - parentId, - id: nodeId || id, - name, - isFile, - isFolder - })); + this.store.dispatch(new ViewFileAction(node)); } else if (isFolder) { this.store.dispatch(new NavigateToFolder(node)); } diff --git a/src/app/components/search/search-results-row/search-results-row.component.ts b/src/app/components/search/search-results-row/search-results-row.component.ts index 154229d70..163b47a92 100644 --- a/src/app/components/search/search-results-row/search-results-row.component.ts +++ b/src/app/components/search/search-results-row/search-results-row.component.ts @@ -24,8 +24,8 @@ */ import { Component, Input, OnInit, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core'; -import { MinimalNodeEntryEntity } from 'alfresco-js-api'; -import { ViewNodeAction } from '../../../store/actions/viewer.actions'; +import { MinimalNodeEntity } from 'alfresco-js-api'; +import { ViewFileAction } from '../../../store/actions'; import { Store } from '@ngrx/store'; import { AppStore } from '../../../store/states/app.state'; @@ -38,14 +38,14 @@ import { AppStore } from '../../../store/states/app.state'; host: { class: 'aca-search-results-row' } }) export class SearchResultsRowComponent implements OnInit { - private node: MinimalNodeEntryEntity; + private node: MinimalNodeEntity; @Input() context: any; constructor(private store: Store) {} ngOnInit() { - this.node = this.context.row.node.entry; + this.node = this.context.row.node; } get name() { @@ -89,13 +89,8 @@ export class SearchResultsRowComponent implements OnInit { } showPreview() { - const { id, name } = this.node; - this.store.dispatch( - new ViewNodeAction({ - id, - name - }) + new ViewFileAction(this.node) ); } @@ -106,6 +101,6 @@ export class SearchResultsRowComponent implements OnInit { .replace('[', '.') .replace(']', '') .split('.') - .reduce((acc, part) => (acc ? acc[part] : null), this.node); + .reduce((acc, part) => (acc ? acc[part] : null), this.node.entry); } } diff --git a/src/app/store/actions/viewer.actions.ts b/src/app/store/actions/viewer.actions.ts index 048a408eb..7d2ea5bea 100644 --- a/src/app/store/actions/viewer.actions.ts +++ b/src/app/store/actions/viewer.actions.ts @@ -24,11 +24,11 @@ */ import { Action } from '@ngrx/store'; -import { NodeInfo } from '../models'; +import { MinimalNodeEntity } from 'alfresco-js-api'; -export const VIEW_NODE = 'VIEW_NODE'; +export const VIEW_FILE = 'VIEW_FILE'; -export class ViewNodeAction implements Action { - readonly type = VIEW_NODE; - constructor(public payload: NodeInfo) {} +export class ViewFileAction implements Action { + readonly type = VIEW_FILE; + constructor(public payload: MinimalNodeEntity, public parentId?: string) {} } diff --git a/src/app/store/effects/viewer.effects.ts b/src/app/store/effects/viewer.effects.ts index 42a97bb2e..ccac612ef 100644 --- a/src/app/store/effects/viewer.effects.ts +++ b/src/app/store/effects/viewer.effects.ts @@ -26,37 +26,84 @@ import { Effect, Actions, ofType } from '@ngrx/effects'; import { Injectable } from '@angular/core'; import { map } from 'rxjs/operators'; -import { ViewNodeAction, VIEW_NODE } from '../actions/viewer.actions'; +import { VIEW_FILE, ViewFileAction } from '../actions'; import { Router } from '@angular/router'; +import { Store, createSelector } from '@ngrx/store'; +import { AppStore } from '../states'; +import { appSelection, currentFolder } from '../selectors/app.selectors'; + +export const fileToPreview = createSelector( + appSelection, + currentFolder, + (selection, folder) => { + return { + selection, + folder + }; + } +); @Injectable() export class ViewerEffects { - constructor(private actions$: Actions, private router: Router) {} + constructor( + private store: Store, + private actions$: Actions, + private router: Router + ) {} @Effect({ dispatch: false }) - viewNode$ = this.actions$.pipe( - ofType(VIEW_NODE), + viewFile$ = this.actions$.pipe( + ofType(VIEW_FILE), map(action => { - const node = action.payload; - if (!node) { - return; - } + if (action.payload && action.payload.entry) { + const { id, nodeId, isFile } = action.payload.entry; - let previewLocation = this.router.url; - if (previewLocation.lastIndexOf('/') > 0) { - previewLocation = previewLocation.substr( - 0, - this.router.url.indexOf('/', 1) - ); - } - previewLocation = previewLocation.replace(/\//g, ''); + if (isFile || nodeId) { + this.displayPreview(nodeId || id, action.parentId); + } + } else { + this.store + .select(fileToPreview) + .take(1) + .subscribe(result => { + if (result.selection && result.selection.file) { + const { + id, + nodeId, + isFile + } = result.selection.file.entry; - const path = [previewLocation]; - if (node.parentId) { - path.push(node.parentId); + if (isFile || nodeId) { + const parentId = result.folder + ? result.folder.id + : null; + this.displayPreview(nodeId || id, parentId); + } + } + }); } - path.push('preview', node.id); - this.router.navigateByUrl(path.join('/')); }) ); + + private displayPreview(nodeId: string, parentId: string) { + if (!nodeId) { + return; + } + + let previewLocation = this.router.url; + if (previewLocation.lastIndexOf('/') > 0) { + previewLocation = previewLocation.substr( + 0, + this.router.url.indexOf('/', 1) + ); + } + previewLocation = previewLocation.replace(/\//g, ''); + + const path = [previewLocation]; + if (parentId) { + path.push(parentId); + } + path.push('preview', nodeId); + this.router.navigateByUrl(path.join('/')); + } }