[ACA-2745] Viewer - return to location on close (#1196)

* use viewNodeExtras when calling action

* open viewer based on ViewNodeExtras data

* resolve closing destination based on ViewNodeExtras query params

* remove unused param

* call ViewNodeAction with correct params

* update tests

* update docs
This commit is contained in:
Cilibiu Bogdan
2019-09-06 14:17:29 +03:00
committed by GitHub
parent cbe9cf4690
commit edf1e52e94
19 changed files with 186 additions and 82 deletions

View File

@@ -77,7 +77,7 @@ and perform document list reload if needed.
Below is the list of public actions types you can use in the plugin definitions as a reference to the action:
| Version | Name | Payload | Description |
| ------- | ---------------------- | ------------------- | ----------------------------------------------------------------------------------------------- |
| ------- | ---------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 1.7.0 | SET_CURRENT_FOLDER | Node | Notify components about currently opened folder. |
| 1.7.0 | SET_CURRENT_URL | string | Notify components about current browser URL. |
| 1.7.0 | SET_USER_PROFILE | Person | Assign current user profile. |
@@ -121,6 +121,6 @@ Below is the list of public actions types you can use in the plugin definitions
| 1.7.0 | TOGGLE_SEARCH_FILTER | n/a | Toggle Filter component visibility in Search Results. |
| 1.7.0 | SHOW_SEARCH_FILTER | n/a | Show Filter component in Search Results. |
| 1.7.0 | HIDE_SEARCH_FILTER | n/a | Hide Filter component in Search Results |
| 1.8.0 | VIEW_NODE | string | Lightweight preview of a node by id. Can be invoked from extensions. |
| 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 |

View File

@@ -59,3 +59,66 @@ At the bottom of the content the Viewer Controls allow users to interact with th
- Toggle audio
- Audio volume
- Full screen
## Details
The viewer can be invoked by calling [ViewNodeAction](../extending/application-actions). This method supports a second parameter `ViewNodeExtras` which affects the behaviour on opening and closing hte viewer as detailed bellow.
```typescript
// ViewNodeExtras
export interface ViewNodeExtras {
location?: string;
path?: string;
}
```
```typescript
// app.routes.ts
...
{
path: 'custom-path',
children: [
{
path: '',
component: CustomComponent
},
{
path: 'view/:nodeId',
outlet: 'viewer',
children: [
{
path: '',
loadChildren: './components/viewer/viewer.module#AppViewerModule'
}
]
}
]
}
...
```
```typescript
// custom-component.component.ts
import { ViewNodeAction } from '@alfresco/aca-shared/store';
import { Router } from '@angular/router';
@Component({...})
export class CustomComponent {
constructor(private store: Store<AppStore>, private router: Router)
viewNode(nodeId: string) {
this.store.dispatch(new ViewNodeAction(nodeId, { location: this.router.url }));
}
}
```
In the above example, passing `location` when calling `ViewNodeAction` will open the viewer relative to current activated route _/custom-path/(viewer:view/nodeId)_.
If no location is passed, the viewer will default to open on a [predefined route](https://github.com/Alfresco/alfresco-content-app/blob/development/src/app/app.routes.ts#L58). In this case, in order to get back to original location from where the viewer was invoked, `ViewNodeAction` should be called by passing a `path`.
```typescript
// when invoked from an extension
this.store.dispatch(new ViewNodeAction(nodeId, { path: this.router.url }));
```

View File

@@ -33,6 +33,11 @@ export enum ViewerActionTypes {
ClosePreview = 'CLOSE_PREVIEW'
}
export interface ViewNodeExtras {
location?: string;
path?: string;
}
export class ViewFileAction implements Action {
readonly type = ViewerActionTypes.ViewFile;
@@ -42,7 +47,7 @@ export class ViewFileAction implements Action {
export class ViewNodeAction implements Action {
readonly type = ViewerActionTypes.ViewNode;
constructor(public nodeId: string, public location?: string) {}
constructor(public nodeId: string, public viewNodeExtras?: ViewNodeExtras) {}
}
export class FullscreenViewerAction implements Action {

View File

@@ -185,9 +185,8 @@ describe('FavoritesComponent', () => {
fixture.detectChanges();
component.onNodeDoubleClick(nodeEntity);
expect(component.showPreview).toHaveBeenCalledWith(
nodeEntity,
mockRouter.url
);
expect(component.showPreview).toHaveBeenCalledWith(nodeEntity, {
location: mockRouter.url
});
});
});

View File

@@ -112,7 +112,7 @@ export class FavoritesComponent extends PageComponent implements OnInit {
}
if (node.entry.isFile) {
this.showPreview(node, this.router.url);
this.showPreview(node, { location: this.router.url });
}
}
}

View File

@@ -151,7 +151,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
return;
}
this.showPreview(node, this.router.url);
this.showPreview(node, { location: this.router.url });
}
}

View File

@@ -43,7 +43,8 @@ import {
getDocumentDisplayMode,
isInfoDrawerOpened,
getSharedUrl,
ViewNodeAction
ViewNodeAction,
ViewNodeExtras
} from '@alfresco/aca-shared/store';
import { isLocked, isLibrary } from '../utils/node.utils';
@@ -105,12 +106,12 @@ export abstract class PageComponent implements OnInit, OnDestroy {
this.onDestroy$.complete();
}
showPreview(node: MinimalNodeEntity, location?: string) {
showPreview(node: MinimalNodeEntity, extras?: ViewNodeExtras) {
if (node && node.entry) {
const id =
(<any>node).entry.nodeId || (<any>node).entry.guid || node.entry.id;
this.store.dispatch(new ViewNodeAction(id, location));
this.store.dispatch(new ViewNodeAction(id, extras));
}
}

View File

@@ -124,6 +124,8 @@ describe('RecentFilesComponent', () => {
fixture.detectChanges();
component.onNodeDoubleClick(node);
expect(component.showPreview).toHaveBeenCalledWith(node, mockRouter.url);
expect(component.showPreview).toHaveBeenCalledWith(node, {
location: mockRouter.url
});
});
});

View File

@@ -77,7 +77,7 @@ export class RecentFilesComponent extends PageComponent implements OnInit {
onNodeDoubleClick(node: MinimalNodeEntity) {
if (node && node.entry) {
this.showPreview(node, this.router.url);
this.showPreview(node, { location: this.router.url });
}
}

View File

@@ -126,7 +126,7 @@ export class SearchResultsRowComponent implements OnInit, OnDestroy {
showPreview(event: MouseEvent) {
event.stopPropagation();
this.store.dispatch(
new ViewNodeAction(this.node.entry.id, this.router.url)
new ViewNodeAction(this.node.entry.id, { location: this.router.url })
);
}

View File

@@ -305,7 +305,9 @@ describe('SearchComponent', () => {
component.onNodeDoubleClick(node);
expect(component.showPreview).toHaveBeenCalledWith(node, router.url);
expect(component.showPreview).toHaveBeenCalledWith(node, {
location: router.url
});
});
it('should re-run search on pagination change', () => {

View File

@@ -253,7 +253,7 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
return;
}
this.showPreview(node, this.router.url);
this.showPreview(node, { location: this.router.url });
}
}

View File

@@ -131,6 +131,8 @@ describe('SharedFilesComponent', () => {
fixture.detectChanges();
component.preview(node);
expect(component.showPreview).toHaveBeenCalledWith(node, mockRouter.url);
expect(component.showPreview).toHaveBeenCalledWith(node, {
location: mockRouter.url
});
});
});

View File

@@ -79,6 +79,6 @@ export class SharedFilesComponent extends PageComponent implements OnInit {
}
preview(node: MinimalNodeEntity) {
this.showPreview(node, this.router.url);
this.showPreview(node, { location: this.router.url });
}
}

View File

@@ -69,7 +69,9 @@ export class ViewNodeComponent {
(<any>selection.file).entry.guid ||
selection.file.entry.id;
this.store.dispatch(new ViewNodeAction(id, this.router.url));
this.store.dispatch(
new ViewNodeAction(id, { location: this.router.url })
);
});
}
}

View File

@@ -11,7 +11,7 @@
[allowDownload]="false"
[allowFullScreen]="false"
[overlayMode]="true"
(showViewerChange)="onViewerVisibilityChanged($event)"
(showViewerChange)="onViewerVisibilityChanged()"
[canNavigateBefore]="previousNodeId"
[canNavigateNext]="nextNodeId"
(navigateBefore)="onNavigateBefore()"

View File

@@ -59,6 +59,8 @@ import { ReloadDocumentListAction } from '@alfresco/aca-shared/store';
host: { class: 'app-viewer' }
})
export class AppViewerComponent implements OnInit, OnDestroy {
private navigationPath: string;
onDestroy$ = new Subject<boolean>();
folderId: string = null;
@@ -149,6 +151,10 @@ export class AppViewerComponent implements OnInit, OnDestroy {
}
});
this.route.queryParams.subscribe(params => {
this.navigationPath = params.path;
});
if (this.route.snapshot.data && this.route.snapshot.data.navigateSource) {
const source = this.route.snapshot.data.navigateSource.toLowerCase();
if (this.navigationSources.includes(source)) {
@@ -231,12 +237,12 @@ export class AppViewerComponent implements OnInit, OnDestroy {
onNavigateBefore(): void {
const location = this.getFileLocation();
this.store.dispatch(new ViewNodeAction(this.previousNodeId, location));
this.store.dispatch(new ViewNodeAction(this.previousNodeId, { location }));
}
onNavigateNext(): void {
const location = this.getFileLocation();
this.store.dispatch(new ViewNodeAction(this.nextNodeId, location));
this.store.dispatch(new ViewNodeAction(this.nextNodeId, { location }));
}
/**
@@ -425,7 +431,7 @@ export class AppViewerComponent implements OnInit, OnDestroy {
private getFileLocation(): string {
return this.router
.parseUrl(this.router.url)
.parseUrl(this.navigationPath || this.router.url)
.root.children[PRIMARY_OUTLET].toString();
}
}

View File

@@ -74,12 +74,14 @@ describe('ViewerEffects', () => {
});
describe('ViewNode', () => {
it('should open viewer from file location', fakeAsync(() => {
store.dispatch(new ViewNodeAction('nodeId', 'some-location'));
it('should open viewer from file location if', fakeAsync(() => {
store.dispatch(
new ViewNodeAction('nodeId', { location: 'some-location' })
);
tick(100);
expect(router.navigateByUrl['calls'].argsFor(0)[0].toString()).toEqual(
'/some-location/(viewer:view/nodeId)?source=some-location'
'/some-location/(viewer:view/nodeId)?location=some-location'
);
}));
@@ -91,5 +93,14 @@ describe('ViewerEffects', () => {
'/view/(viewer:nodeId)'
);
}));
it('should navigate to viewer route with query param if path is passed', fakeAsync(() => {
store.dispatch(new ViewNodeAction('nodeId', { path: 'absolute-path' }));
tick(100);
expect(router.navigateByUrl['calls'].argsFor(0)[0].toString()).toEqual(
'/view/(viewer:nodeId)?path=absolute-path'
);
}));
});
});

View File

@@ -77,17 +77,28 @@ export class ViewerEffects {
viewNode$ = this.actions$.pipe(
ofType<ViewNodeAction>(ViewerActionTypes.ViewNode),
map(action => {
if (action.location) {
const location = this.getNavigationCommands(action.location);
if (action.viewNodeExtras) {
const { location, path } = action.viewNodeExtras;
if (location) {
const navigation = this.getNavigationCommands(location);
this.router.navigate(
[...location, { outlets: { viewer: ['view', action.nodeId] } }],
[...navigation, { outlets: { viewer: ['view', action.nodeId] } }],
{
queryParams: {
source: action.location
}
queryParams: { location }
}
);
}
if (path) {
this.router.navigate(
['view', { outlets: { viewer: [action.nodeId] } }],
{
queryParams: { path }
}
);
}
} else {
this.router.navigate([
'view',