[ACA-3394] Generally available file preview feature for extensions (#1496)

* Adding general purpose preview overlay route

Preparation for file preview feature

Remove unnecessary preview root route and ability to use loadChildren

Extract RouterExtensionService

Remove loadChildren support and use component instead

Cover RouterExtensionService with unit tests

Fix tests

Fix build

Fix rebase issue

Add generally available PluginPreviewAction

Add data option to child routes and navigateBackAsClose option for the preview component

Support plain mode preview

Fix linting

Update to latest alpha of ADF

* Adding documentation

* Rebase fix

* Update to latest adf
This commit is contained in:
Popovics András
2020-08-07 18:24:38 +02:00
committed by GitHub
parent ac6cfdb5b6
commit cd1252cb94
17 changed files with 560 additions and 233 deletions

View File

@@ -28,7 +28,6 @@ import { SetInitialStateAction } from '@alfresco/aca-shared/store';
import { Router } from '@angular/router';
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { mockRoutesWithoutParentRoute, mockRoutesWithParentRoute } from './mock/extension-routes.mock';
describe('AppComponent', () => {
let component: AppComponent;
@@ -105,31 +104,4 @@ describe('AppComponent', () => {
expect(storeMock.dispatch['calls'].argsFor(0)[0].payload).toBe('APP.MESSAGES.UPLOAD.ERROR.GENERIC');
});
});
describe('Routing Configuration', () => {
it('Should extension route be included as child of the defined parent path', () => {
component.mapExtensionRoutes(mockRoutesWithParentRoute);
expect(router.config[0]).toEqual({
path: 'fake-path',
children: [
{
path: 'extension-path',
canActivate: ['fake-guard'],
canActivateChild: ['fake-guard']
}
]
});
});
it('Should extension route be included as root entry when there is no parent path defined', () => {
component.mapExtensionRoutes(mockRoutesWithoutParentRoute);
expect(router.config[0]).toEqual({
component: null,
path: 'extension-path',
canActivate: ['fake-guard'],
canActivateChild: ['fake-guard']
});
});
});
});

View File

@@ -48,7 +48,7 @@ import {
SetRepositoryInfoAction
} from '@alfresco/aca-shared/store';
import { filter, takeUntil } from 'rxjs/operators';
import { AppExtensionService, AppService, ContentApiService, ExtensionRoute } from '@alfresco/aca-shared';
import { RouterExtensionService, AppService, ContentApiService } from '@alfresco/aca-shared';
import { DiscoveryEntry, GroupEntry, Group } from '@alfresco/js-api';
import { Subject } from 'rxjs';
import { INITIAL_APP_STATE } from './store/initial-state';
@@ -71,7 +71,7 @@ export class AppComponent implements OnInit, OnDestroy {
private alfrescoApiService: AlfrescoApiService,
private authenticationService: AuthenticationService,
private uploadService: UploadService,
private extensions: AppExtensionService,
private routerExtensionService: RouterExtensionService,
private contentApi: ContentApiService,
private appService: AppService,
private sharedLinksApiService: SharedLinksApiService,
@@ -112,8 +112,7 @@ export class AppComponent implements OnInit, OnDestroy {
this.store.dispatch(new SetCurrentUrlAction(router.url));
});
const extensionRoutes = this.extensions.getApplicationRoutes();
this.mapExtensionRoutes(extensionRoutes);
this.routerExtensionService.mapExtensionRoutes();
this.uploadService.fileUploadError.subscribe((error) => this.onFileUploadedError(error));
@@ -140,30 +139,6 @@ export class AppComponent implements OnInit, OnDestroy {
});
}
private extensionRouteHasChild(route: ExtensionRoute): boolean {
return route.parentRoute !== undefined;
}
private convertExtensionRouteToRoute(extensionRoute: ExtensionRoute) {
delete extensionRoute.parentRoute;
delete extensionRoute.component;
}
mapExtensionRoutes(extensionRoutes: ExtensionRoute[]) {
const routesWithoutParent = [];
extensionRoutes.forEach((extensionRoute: ExtensionRoute) => {
if (this.extensionRouteHasChild(extensionRoute)) {
const routeIndex = this.router.config.findIndex((route) => route.path === extensionRoute.parentRoute);
this.convertExtensionRouteToRoute(extensionRoute);
this.router.config[routeIndex].children.unshift(extensionRoute);
} else {
routesWithoutParent.push(extensionRoute);
}
});
this.router.config.unshift(...routesWithoutParent);
}
private async loadUserProfile() {
const groupsEntries: GroupEntry[] = await this.groupService.listAllGroupMembershipsForPerson('-me-', { maxItems: 250 });

View File

@@ -27,10 +27,8 @@
</ng-container>
</adf-viewer-open-with>
<adf-viewer-toolbar-actions>
<ng-container
*ngFor="let action of viewerToolbarActions; trackBy: trackByActionId"
>
<adf-viewer-toolbar-actions *ngIf="!simplestMode">
<ng-container *ngFor="let action of viewerToolbarActions; trackBy: trackByActionId">
<aca-toolbar-action [actionRef]="action"></aca-toolbar-action>
</ng-container>
</adf-viewer-toolbar-actions>

View File

@@ -24,6 +24,7 @@
*/
import { Component, OnInit, OnDestroy, ViewEncapsulation, HostListener } from '@angular/core';
import { Location } from '@angular/common';
import { ActivatedRoute, Router, UrlTree, UrlSegmentGroup, UrlSegment, PRIMARY_OUTLET } from '@angular/router';
import { debounceTime, map, takeUntil } from 'rxjs/operators';
import { UserPreferencesService, ObjectUtils, UploadService, AlfrescoApiService } from '@alfresco/adf-core';
@@ -57,6 +58,8 @@ export class PreviewComponent extends PageComponent implements OnInit, OnDestroy
openWith: Array<ContentActionRef> = [];
contentExtensions: Array<ViewerExtensionRef> = [];
showRightSide = false;
navigateBackAsClose = false;
simplestMode = false;
recentFileFilters = [
'TYPE:"content"',
@@ -92,6 +95,7 @@ export class PreviewComponent extends PageComponent implements OnInit, OnDestroy
private apiService: AlfrescoApiService,
private uploadService: UploadService,
private actions$: Actions,
private location: Location,
store: Store<AppStore>,
extensions: AppExtensionService,
content: ContentManagementService
@@ -111,6 +115,8 @@ export class PreviewComponent extends PageComponent implements OnInit, OnDestroy
this.previewLocation = this.router.url.substr(0, this.router.url.indexOf('/', 1)).replace(/\//g, '');
const routeData = this.route.snapshot.data;
this.navigateBackAsClose = !!routeData.navigateBackAsClose;
this.simplestMode = !!routeData.simplestMode;
if (routeData.navigateMultiple) {
this.navigateMultiple = true;
@@ -202,16 +208,18 @@ export class PreviewComponent extends PageComponent implements OnInit, OnDestroy
}
navigateToFileLocation(shouldNavigate: boolean) {
const shouldSkipNavigation = this.routesSkipNavigation.includes(this.previewLocation);
if (shouldNavigate) {
const route = this.getNavigationCommands(this.previewLocation);
if (this.navigateBackAsClose) {
this.location.back();
} else {
const shouldSkipNavigation = this.routesSkipNavigation.includes(this.previewLocation);
const route = this.getNavigationCommands(this.previewLocation);
if (!shouldSkipNavigation && this.folderId) {
route.push(this.folderId);
if (!shouldSkipNavigation && this.folderId) {
route.push(this.folderId);
}
this.router.navigate(route);
}
this.router.navigate(route);
}
}

View File

@@ -54,6 +54,7 @@ import { LanguagePickerComponent } from '../components/common/language-picker/la
import { LogoutComponent } from '../components/common/logout/logout.component';
import { CurrentUserComponent } from '../components/current-user/current-user.component';
import { AppExtensionService, ExtensionsDataLoaderGuard } from '@alfresco/aca-shared';
import { PreviewComponent } from '../components/preview/preview.component';
export function setupExtensions(service: AppExtensionService): Function {
return () => service.load();
@@ -90,6 +91,7 @@ export class CoreExtensionsModule {
'app.components.tabs.library.metadata': LibraryMetadataTabComponent,
'app.components.tabs.comments': CommentsTabComponent,
'app.components.tabs.versions': VersionsTabComponent,
'app.components.preview': PreviewComponent,
'app.toolbar.toggleInfoDrawer': ToggleInfoDrawerComponent,
'app.toolbar.toggleFavorite': ToggleFavoriteComponent,
'app.toolbar.toggleFavoriteLibrary': ToggleFavoriteLibraryComponent,

View File

@@ -25,7 +25,7 @@
import { Effect, Actions, ofType } from '@ngrx/effects';
import { Injectable } from '@angular/core';
import { map, take } from 'rxjs/operators';
import { map, take, tap } from 'rxjs/operators';
import {
AppStore,
ViewerActionTypes,
@@ -34,7 +34,8 @@ import {
getCurrentFolder,
getAppSelection,
FullscreenViewerAction,
ViewNodeVersionAction
ViewNodeVersionAction,
PluginPreviewAction
} from '@alfresco/aca-shared/store';
import { Router, UrlTree, UrlSegmentGroup, PRIMARY_OUTLET, UrlSegment } from '@angular/router';
import { Store, createSelector } from '@ngrx/store';
@@ -145,6 +146,20 @@ export class ViewerEffects {
})
);
pluginPreview$ = this.actions$.pipe(
ofType<PluginPreviewAction>(ViewerActionTypes.PluginPreview),
tap((action) => {
this.router.navigate([
action.pluginRoute,
{
outlets: {
viewer: ['preview', action.nodeId]
}
}
]);
})
);
private displayPreview(nodeId: string, parentId: string) {
if (!nodeId) {
return;