diff --git a/package-lock.json b/package-lock.json index d937ee206..06c196c77 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,12 +5,12 @@ "requires": true, "dependencies": { "@alfresco/adf-cli": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@alfresco/adf-cli/-/adf-cli-3.8.0.tgz", - "integrity": "sha512-8eMvOGcGc/younoGZKTg9Z2zT1RetnsBrmg9HqLf3hKDBn+wo2B6hd1NBTTWrpdjk9lX1VlbC5I0cdPHMe7CJw==", + "version": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1", + "resolved": "https://registry.npmjs.org/@alfresco/adf-cli/-/adf-cli-3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1.tgz", + "integrity": "sha512-j0D6SobqhTbdvCO1wq+hylSBp/sJNsB6yEMfrTbFEtu3j0CiQl7EaWm+lvkQOH1i8W1iGFuzLAbm4WtFeyNr7w==", "dev": true, "requires": { - "@alfresco/adf-testing": "3.8.0", + "@alfresco/adf-testing": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1", "@angular-devkit/core": "^7.2.15", "commander": "^4.0.0", "ejs": "^2.6.1", @@ -30,42 +30,42 @@ } }, "@alfresco/adf-content-services": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-3.8.0.tgz", - "integrity": "sha512-+YpSqF8cRFkBozKhkH0TpMHZ4ybYEL3IdQaI7JXOobDd/u2AgGfmmbwBZcuCMYF6YpLkoO9ZWU8IiGraf3kKZw==", + "version": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1.tgz", + "integrity": "sha512-eeCyiwR1ZE5gFLazSDeMOGSxy/ATOILfjwjizjUJHPIRzN7L1RkiuSJvBVYNteMyuhNt8y8gQPqM1VdOwpM5Eg==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/adf-core": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-3.8.0.tgz", - "integrity": "sha512-RwWa/loMb4KRL2YoUSFXt6b0x3w1anBxzpqYhe6sFt0YACtITjGmyoW3bOJIlQtY1TF9170YrVOv6RaVni+wTw==", + "version": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1.tgz", + "integrity": "sha512-zCStw/o7LkOjthvyZ6hBJpVJMlFe0xuQsFaVgVsm8OXlS8FYY5cuF8oCxMKZ7Z1QmtAHmxpYTXLsWfUljPx1Rw==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/adf-extensions": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-3.8.0.tgz", - "integrity": "sha512-uKG8L+4k1cPHeVFFicBFt0EY7a7xN0AlnrZkPwqr/s5Q/Mif9bqmZqMzIJNOrdJAICg8HnlJi5c5dhOMHAarCg==", + "version": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1", + "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1.tgz", + "integrity": "sha512-rcyYHlvkP8taLaGArbWEwdo3CI4PbI4J4PMiuqEV+eS/gIXGtrC8KazDqyRpekMbtYgISUdFde+SzatGi1y5xQ==", "requires": { "tslib": "^1.9.0" } }, "@alfresco/adf-testing": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@alfresco/adf-testing/-/adf-testing-3.8.0.tgz", - "integrity": "sha512-feinvQ62LLpIHca7SnCc6mRK2vhGeK8w+VCmSZlHkcf97YF+nou0JuFi/CQ6aAWWfaQtNZrm9VjXEeUUvh1s1Q==", + "version": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1", + "resolved": "https://registry.npmjs.org/@alfresco/adf-testing/-/adf-testing-3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1.tgz", + "integrity": "sha512-FTSz6/BmXl9IQCLirIfYqcwHa3xSYT6fpnUklW3whJAM5yG1xFmMXg9oNGHRaHK89MLShqMjGtg8bQApzb9mUg==", "dev": true, "requires": { "tslib": "^1.9.0" } }, "@alfresco/js-api": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-3.8.0.tgz", - "integrity": "sha512-y7MYkK4XrtGJUwmWSXroOnqCfUz7iMCpccO7qtOVrfEqlp8euSw5KkwW+AuLyDtshIKoKaJvATp7YULo4tTL1Q==", + "version": "3.9.0-60f7d7e3507a85b4118fc326097e53b987530dcc", + "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-3.9.0-60f7d7e3507a85b4118fc326097e53b987530dcc.tgz", + "integrity": "sha512-tNjXuT5Mc43xAZ+ZtwTXHfp5BGonvH5CG8vbK5+MKt8gItRnP8rRPCxzT1diTSvaeCLLoBr0QLwdC9HARAs6fg==", "requires": { "event-emitter": "^0.3.5", "minimatch": "3.0.4", @@ -195,7 +195,7 @@ }, "chalk": { "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=", "dev": true, "optional": true, @@ -631,7 +631,7 @@ }, "load-json-file": { "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=", "dev": true, "requires": { @@ -678,7 +678,7 @@ }, "pify": { "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=", "dev": true }, @@ -2947,7 +2947,7 @@ }, "buffer": { "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=", "dev": true, "requires": { @@ -7482,7 +7482,7 @@ }, "is-builtin-module": { "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=", "requires": { "builtin-modules": "^1.0.0" @@ -10770,7 +10770,7 @@ }, "path-browserify": { "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=", "dev": true }, @@ -14580,7 +14580,7 @@ }, "vm-browserify": { "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=", "dev": true, "requires": { @@ -15366,7 +15366,7 @@ }, "xmlbuilder": { "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=", "dev": true }, diff --git a/package.json b/package.json index 8651b6f7f..6d820fccd 100644 --- a/package.json +++ b/package.json @@ -30,10 +30,10 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "3.8.0", - "@alfresco/adf-core": "3.8.0", - "@alfresco/adf-extensions": "3.8.0", - "@alfresco/js-api": "3.8.0", + "@alfresco/adf-content-services": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1", + "@alfresco/adf-core": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1", + "@alfresco/adf-extensions": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1", + "@alfresco/js-api": "3.9.0-60f7d7e3507a85b4118fc326097e53b987530dcc", "@angular-custom-builders/lite-serve": "0.0.2", "@angular/animations": "7.2.15", "@angular/cdk": "^7.3.7", @@ -66,8 +66,8 @@ "zone.js": "0.8.29" }, "devDependencies": { - "@alfresco/adf-cli": "3.8.0", - "@alfresco/adf-testing": "3.8.0", + "@alfresco/adf-cli": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1", + "@alfresco/adf-testing": "3.9.0-8ef91ce98d8d0e20127b826fccec830077585fb1", "@angular-devkit/build-angular": "~0.13.9", "@angular-devkit/build-ng-packagr": "^0.13.10", "@angular/cli": "^7.3.9", diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 047b93c95..06dd2c927 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -25,9 +25,17 @@ import { AppComponent } from './app.component'; 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; + let router: Router; const storeMock: any = { dispatch: jasmine.createSpy('dispatch') @@ -49,9 +57,17 @@ describe('AppComponent', () => { }; beforeAll(() => { + TestBed.configureTestingModule({ + imports: [ + RouterTestingModule.withRoutes([{ path: 'fake-path', children: [] }]) + ] + }); + + router = TestBed.get(Router); + component = new AppComponent( null, - null, + router, null, storeMock, 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'] + }); + }); + }); }); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 9f9b24f93..d855490ad 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -52,6 +52,7 @@ import { AppService, ContentApiService } from '@alfresco/aca-shared'; import { DiscoveryEntry, GroupsApi, Group } from '@alfresco/js-api'; import { Subject } from 'rxjs'; import { INITIAL_APP_STATE } from './store/initial-state'; +import { ExtensionRoute } from './types'; @Component({ selector: 'app-root', @@ -119,7 +120,8 @@ export class AppComponent implements OnInit, OnDestroy { 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.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() { const groupsApi = new GroupsApi(this.alfrescoApiService.getInstance()); const paging = await groupsApi.listGroupMembershipsForPerson('-me-'); diff --git a/src/app/extensions/extension.service.ts b/src/app/extensions/extension.service.ts index 892d4a639..156fd7023 100644 --- a/src/app/extensions/extension.service.ts +++ b/src/app/extensions/extension.service.ts @@ -25,7 +25,6 @@ import { Injectable, Type } from '@angular/core'; import { Store } from '@ngrx/store'; -import { Route } from '@angular/router'; import { MatIconRegistry } from '@angular/material/icon'; import { DomSanitizer } from '@angular/platform-browser'; import { @@ -63,7 +62,7 @@ import { import { BehaviorSubject, Observable } from 'rxjs'; import { RepositoryInfo, NodeEntry } from '@alfresco/js-api'; import { ViewerRules } from './viewer.rules'; -import { SettingsGroupRef } from '../types'; +import { SettingsGroupRef, ExtensionRoute } from '../types'; @Injectable({ providedIn: 'root' @@ -390,7 +389,7 @@ export class AppExtensionService implements RuleContext { return this.extensions.getComponentById(id); } - getApplicationRoutes(): Array { + getApplicationRoutes(): Array { return this.extensions.routes.map(route => { const guards = this.extensions.getAuthGuards( 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), canActivateChild: guards, canActivate: guards, + parentRoute: route.parentRoute, children: [ { path: '', diff --git a/src/app/mock/extension-routes.mock.ts b/src/app/mock/extension-routes.mock.ts new file mode 100644 index 000000000..3b8e8ed54 --- /dev/null +++ b/src/app/mock/extension-routes.mock.ts @@ -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 . + */ + +import { ExtensionRoute } from '../types'; + +export const mockRoutesWithoutParentRoute: Array = [ + { + path: 'extension-path', + component: null, + canActivate: ['fake-guard'], + canActivateChild: ['fake-guard'] + } +]; + +export const mockRoutesWithParentRoute: Array = [ + { + ...mockRoutesWithoutParentRoute[0], + parentRoute: 'fake-path' + } +]; diff --git a/src/app/types.ts b/src/app/types.ts index ff0fdfebb..4345efa61 100644 --- a/src/app/types.ts +++ b/src/app/types.ts @@ -23,6 +23,8 @@ * along with Alfresco. If not, see . */ +import { Route } from '@angular/router'; + export interface SettingsGroupRef { id: string; name: string; @@ -40,3 +42,7 @@ export interface SettingsParameterRef { type: 'string' | 'boolean'; value?: any; } + +export interface ExtensionRoute extends Route { + parentRoute?: string; +}