[ACA-3182] Add a way to define an extension route as child of a route (#1463)

* [ACA-3182] Add a way to define an extension route as child of a route

* [ACA-3182] Add unit tests

* [ACA-3182] Add license header
This commit is contained in:
arditdomi 2020-05-12 09:39:33 +01:00 committed by GitHub
parent ea0cfaa99c
commit 6dc01c4b17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 156 additions and 38 deletions

54
package-lock.json generated
View File

@ -5,12 +5,12 @@
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"@alfresco/adf-cli": { "@alfresco/adf-cli": {
"version": "3.8.0", "version": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1",
"resolved": "https://registry.npmjs.org/@alfresco/adf-cli/-/adf-cli-3.8.0.tgz", "resolved": "https://registry.npmjs.org/@alfresco/adf-cli/-/adf-cli-3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1.tgz",
"integrity": "sha512-8eMvOGcGc/younoGZKTg9Z2zT1RetnsBrmg9HqLf3hKDBn+wo2B6hd1NBTTWrpdjk9lX1VlbC5I0cdPHMe7CJw==", "integrity": "sha512-j0D6SobqhTbdvCO1wq+hylSBp/sJNsB6yEMfrTbFEtu3j0CiQl7EaWm+lvkQOH1i8W1iGFuzLAbm4WtFeyNr7w==",
"dev": true, "dev": true,
"requires": { "requires": {
"@alfresco/adf-testing": "3.8.0", "@alfresco/adf-testing": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1",
"@angular-devkit/core": "^7.2.15", "@angular-devkit/core": "^7.2.15",
"commander": "^4.0.0", "commander": "^4.0.0",
"ejs": "^2.6.1", "ejs": "^2.6.1",
@ -30,42 +30,42 @@
} }
}, },
"@alfresco/adf-content-services": { "@alfresco/adf-content-services": {
"version": "3.8.0", "version": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1",
"resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-3.8.0.tgz", "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1.tgz",
"integrity": "sha512-+YpSqF8cRFkBozKhkH0TpMHZ4ybYEL3IdQaI7JXOobDd/u2AgGfmmbwBZcuCMYF6YpLkoO9ZWU8IiGraf3kKZw==", "integrity": "sha512-eeCyiwR1ZE5gFLazSDeMOGSxy/ATOILfjwjizjUJHPIRzN7L1RkiuSJvBVYNteMyuhNt8y8gQPqM1VdOwpM5Eg==",
"requires": { "requires": {
"tslib": "^1.9.0" "tslib": "^1.9.0"
} }
}, },
"@alfresco/adf-core": { "@alfresco/adf-core": {
"version": "3.8.0", "version": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1",
"resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-3.8.0.tgz", "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1.tgz",
"integrity": "sha512-RwWa/loMb4KRL2YoUSFXt6b0x3w1anBxzpqYhe6sFt0YACtITjGmyoW3bOJIlQtY1TF9170YrVOv6RaVni+wTw==", "integrity": "sha512-zCStw/o7LkOjthvyZ6hBJpVJMlFe0xuQsFaVgVsm8OXlS8FYY5cuF8oCxMKZ7Z1QmtAHmxpYTXLsWfUljPx1Rw==",
"requires": { "requires": {
"tslib": "^1.9.0" "tslib": "^1.9.0"
} }
}, },
"@alfresco/adf-extensions": { "@alfresco/adf-extensions": {
"version": "3.8.0", "version": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1",
"resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-3.8.0.tgz", "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1.tgz",
"integrity": "sha512-uKG8L+4k1cPHeVFFicBFt0EY7a7xN0AlnrZkPwqr/s5Q/Mif9bqmZqMzIJNOrdJAICg8HnlJi5c5dhOMHAarCg==", "integrity": "sha512-rcyYHlvkP8taLaGArbWEwdo3CI4PbI4J4PMiuqEV+eS/gIXGtrC8KazDqyRpekMbtYgISUdFde+SzatGi1y5xQ==",
"requires": { "requires": {
"tslib": "^1.9.0" "tslib": "^1.9.0"
} }
}, },
"@alfresco/adf-testing": { "@alfresco/adf-testing": {
"version": "3.8.0", "version": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1",
"resolved": "https://registry.npmjs.org/@alfresco/adf-testing/-/adf-testing-3.8.0.tgz", "resolved": "https://registry.npmjs.org/@alfresco/adf-testing/-/adf-testing-3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1.tgz",
"integrity": "sha512-feinvQ62LLpIHca7SnCc6mRK2vhGeK8w+VCmSZlHkcf97YF+nou0JuFi/CQ6aAWWfaQtNZrm9VjXEeUUvh1s1Q==", "integrity": "sha512-FTSz6/BmXl9IQCLirIfYqcwHa3xSYT6fpnUklW3whJAM5yG1xFmMXg9oNGHRaHK89MLShqMjGtg8bQApzb9mUg==",
"dev": true, "dev": true,
"requires": { "requires": {
"tslib": "^1.9.0" "tslib": "^1.9.0"
} }
}, },
"@alfresco/js-api": { "@alfresco/js-api": {
"version": "3.8.0", "version": "3.9.0-60f7d7e3507a85b4118fc326097e53b987530dcc",
"resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-3.8.0.tgz", "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-3.9.0-60f7d7e3507a85b4118fc326097e53b987530dcc.tgz",
"integrity": "sha512-y7MYkK4XrtGJUwmWSXroOnqCfUz7iMCpccO7qtOVrfEqlp8euSw5KkwW+AuLyDtshIKoKaJvATp7YULo4tTL1Q==", "integrity": "sha512-tNjXuT5Mc43xAZ+ZtwTXHfp5BGonvH5CG8vbK5+MKt8gItRnP8rRPCxzT1diTSvaeCLLoBr0QLwdC9HARAs6fg==",
"requires": { "requires": {
"event-emitter": "^0.3.5", "event-emitter": "^0.3.5",
"minimatch": "3.0.4", "minimatch": "3.0.4",
@ -195,7 +195,7 @@
}, },
"chalk": { "chalk": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -631,7 +631,7 @@
}, },
"load-json-file": { "load-json-file": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -678,7 +678,7 @@
}, },
"pify": { "pify": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true "dev": true
}, },
@ -2947,7 +2947,7 @@
}, },
"buffer": { "buffer": {
"version": "4.9.1", "version": "4.9.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -7482,7 +7482,7 @@
}, },
"is-builtin-module": { "is-builtin-module": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
"requires": { "requires": {
"builtin-modules": "^1.0.0" "builtin-modules": "^1.0.0"
@ -10770,7 +10770,7 @@
}, },
"path-browserify": { "path-browserify": {
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", "resolved": "http://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
"integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=",
"dev": true "dev": true
}, },
@ -14580,7 +14580,7 @@
}, },
"vm-browserify": { "vm-browserify": {
"version": "0.0.4", "version": "0.0.4",
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", "resolved": "http://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
"integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -15366,7 +15366,7 @@
}, },
"xmlbuilder": { "xmlbuilder": {
"version": "9.0.7", "version": "9.0.7",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=",
"dev": true "dev": true
}, },

View File

@ -30,10 +30,10 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@alfresco/adf-content-services": "3.8.0", "@alfresco/adf-content-services": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1",
"@alfresco/adf-core": "3.8.0", "@alfresco/adf-core": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1",
"@alfresco/adf-extensions": "3.8.0", "@alfresco/adf-extensions": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1",
"@alfresco/js-api": "3.8.0", "@alfresco/js-api": "3.9.0-60f7d7e3507a85b4118fc326097e53b987530dcc",
"@angular-custom-builders/lite-serve": "0.0.2", "@angular-custom-builders/lite-serve": "0.0.2",
"@angular/animations": "7.2.15", "@angular/animations": "7.2.15",
"@angular/cdk": "^7.3.7", "@angular/cdk": "^7.3.7",
@ -66,8 +66,8 @@
"zone.js": "0.8.29" "zone.js": "0.8.29"
}, },
"devDependencies": { "devDependencies": {
"@alfresco/adf-cli": "3.8.0", "@alfresco/adf-cli": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1",
"@alfresco/adf-testing": "3.8.0", "@alfresco/adf-testing": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1",
"@angular-devkit/build-angular": "~0.13.9", "@angular-devkit/build-angular": "~0.13.9",
"@angular-devkit/build-ng-packagr": "^0.13.10", "@angular-devkit/build-ng-packagr": "^0.13.10",
"@angular/cli": "^7.3.9", "@angular/cli": "^7.3.9",

View File

@ -25,9 +25,17 @@
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { SetInitialStateAction } from '@alfresco/aca-shared/store'; 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', () => { describe('AppComponent', () => {
let component: AppComponent; let component: AppComponent;
let router: Router;
const storeMock: any = { const storeMock: any = {
dispatch: jasmine.createSpy('dispatch') dispatch: jasmine.createSpy('dispatch')
@ -49,9 +57,17 @@ describe('AppComponent', () => {
}; };
beforeAll(() => { beforeAll(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([{ path: 'fake-path', children: [] }])
]
});
router = TestBed.get(Router);
component = new AppComponent( component = new AppComponent(
null, null,
null, router,
null, null,
storeMock, storeMock,
configMock, configMock,
@ -124,4 +140,30 @@ describe('AppComponent', () => {
); );
}); });
}); });
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

@ -52,6 +52,7 @@ import { AppService, ContentApiService } from '@alfresco/aca-shared';
import { DiscoveryEntry, GroupsApi, Group } from '@alfresco/js-api'; import { DiscoveryEntry, GroupsApi, Group } from '@alfresco/js-api';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { INITIAL_APP_STATE } from './store/initial-state'; import { INITIAL_APP_STATE } from './store/initial-state';
import { ExtensionRoute } from './types';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -119,7 +120,8 @@ export class AppComponent implements OnInit, OnDestroy {
this.store.dispatch(new SetCurrentUrlAction(router.url)); this.store.dispatch(new SetCurrentUrlAction(router.url));
}); });
this.router.config.unshift(...this.extensions.getApplicationRoutes()); const extensionRoutes = this.extensions.getApplicationRoutes();
this.mapExtensionRoutes(extensionRoutes);
this.uploadService.fileUploadError.subscribe(error => this.uploadService.fileUploadError.subscribe(error =>
this.onFileUploadedError(error) this.onFileUploadedError(error)
@ -156,6 +158,32 @@ 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() { private async loadUserProfile() {
const groupsApi = new GroupsApi(this.alfrescoApiService.getInstance()); const groupsApi = new GroupsApi(this.alfrescoApiService.getInstance());
const paging = await groupsApi.listGroupMembershipsForPerson('-me-'); const paging = await groupsApi.listGroupMembershipsForPerson('-me-');

View File

@ -25,7 +25,6 @@
import { Injectable, Type } from '@angular/core'; import { Injectable, Type } from '@angular/core';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Route } from '@angular/router';
import { MatIconRegistry } from '@angular/material/icon'; import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser'; import { DomSanitizer } from '@angular/platform-browser';
import { import {
@ -63,7 +62,7 @@ import {
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import { RepositoryInfo, NodeEntry } from '@alfresco/js-api'; import { RepositoryInfo, NodeEntry } from '@alfresco/js-api';
import { ViewerRules } from './viewer.rules'; import { ViewerRules } from './viewer.rules';
import { SettingsGroupRef } from '../types'; import { SettingsGroupRef, ExtensionRoute } from '../types';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -390,7 +389,7 @@ export class AppExtensionService implements RuleContext {
return this.extensions.getComponentById(id); return this.extensions.getComponentById(id);
} }
getApplicationRoutes(): Array<Route> { getApplicationRoutes(): Array<ExtensionRoute> {
return this.extensions.routes.map(route => { return this.extensions.routes.map(route => {
const guards = this.extensions.getAuthGuards( const guards = this.extensions.getAuthGuards(
route.auth && route.auth.length > 0 ? route.auth : this.defaults.auth route.auth && route.auth.length > 0 ? route.auth : this.defaults.auth
@ -401,6 +400,7 @@ export class AppExtensionService implements RuleContext {
component: this.getComponentById(route.layout || this.defaults.layout), component: this.getComponentById(route.layout || this.defaults.layout),
canActivateChild: guards, canActivateChild: guards,
canActivate: guards, canActivate: guards,
parentRoute: route.parentRoute,
children: [ children: [
{ {
path: '', path: '',

View File

@ -0,0 +1,42 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2020 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { ExtensionRoute } from '../types';
export const mockRoutesWithoutParentRoute: Array<ExtensionRoute> = [
{
path: 'extension-path',
component: null,
canActivate: ['fake-guard'],
canActivateChild: ['fake-guard']
}
];
export const mockRoutesWithParentRoute: Array<ExtensionRoute> = [
{
...mockRoutesWithoutParentRoute[0],
parentRoute: 'fake-path'
}
];

View File

@ -23,6 +23,8 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { Route } from '@angular/router';
export interface SettingsGroupRef { export interface SettingsGroupRef {
id: string; id: string;
name: string; name: string;
@ -40,3 +42,7 @@ export interface SettingsParameterRef {
type: 'string' | 'boolean'; type: 'string' | 'boolean';
value?: any; value?: any;
} }
export interface ExtensionRoute extends Route {
parentRoute?: string;
}