From a894ea38ce25ec87c3765db5f9318ece184ca427 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Sun, 21 Jun 2020 05:42:18 +0300 Subject: [PATCH] feat: add and use utility for finding closest routes --- .../components/dynamic-layout.component.ts | 7 +++--- .../core/src/lib/services/routes.service.ts | 2 +- .../core/src/lib/tests/route-utils.spec.ts | 24 ++++++++++++++++++- .../core/src/lib/utils/route-utils.ts | 17 +++++++++++++ .../src/lib/providers/route.provider.ts | 2 +- 5 files changed, 46 insertions(+), 6 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts index 6c7de6e6ef..25d49fb169 100644 --- a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts +++ b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts @@ -6,7 +6,7 @@ import { ABP } from '../models'; import { ReplaceableComponents } from '../models/replaceable-components'; import { RoutesService } from '../services/routes.service'; import { ReplaceableComponentsState } from '../states/replaceable-components.state'; -import { getRoutePath } from '../utils/route-utils'; +import { findRoute, getRoutePath } from '../utils/route-utils'; import { takeUntilDestroy } from '../utils/rxjs-utils'; import { TreeNode } from '../utils/tree-utils'; @@ -36,10 +36,11 @@ export class DynamicLayoutComponent implements OnDestroy { router.events.pipe(takeUntilDestroy(this)).subscribe(event => { if (event instanceof NavigationEnd) { let expectedLayout = (route.snapshot.data || {}).layout; - const path = getRoutePath(router); if (!expectedLayout) { - let node = { parent: routes.search({ path }) } as TreeNode; + let node = findRoute(routes, getRoutePath(router)); + node = { parent: node } as TreeNode; + while (node.parent) { node = node.parent; diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index bf3917f5cd..1548e09b79 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -77,7 +77,7 @@ export abstract class AbstractTreeService { return this.publish(flatItems, visibleItems); } - find(predicate: (item: TreeNode) => boolean, tree = this.tree) { + find(predicate: (item: TreeNode) => boolean, tree = this.tree): TreeNode | null { return tree.reduce( (acc, node) => (acc ? acc : predicate(node) ? node : this.find(predicate, node.children)), null, diff --git a/npm/ng-packs/packages/core/src/lib/tests/route-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/route-utils.spec.ts index 41a761b84d..3945a6527d 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/route-utils.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/route-utils.spec.ts @@ -2,13 +2,35 @@ import { Component } from '@angular/core'; import { RouterModule } from '@angular/router'; import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/jest'; import { RouterOutletComponent } from '../components'; -import { getRoutePath } from '../utils/route-utils'; +import { RoutesService } from '../services/routes.service'; +import { findRoute, getRoutePath } from '../utils/route-utils'; // tslint:disable-next-line @Component({ template: '' }) class DummyComponent {} describe('Route Utils', () => { + describe('#findRoute', () => { + const node = { path: '/foo' }; + + test.each` + path | expected | count + ${'/foo/bar/baz'} | ${node} | ${3} + ${'/foo/bar'} | ${node} | ${2} + ${'/foo'} | ${node} | ${1} + ${'/'} | ${null} | ${1} + `( + 'should find $expected in $count turns when path is $path', + async ({ path, expected, count }) => { + const find = jest.fn(cb => (cb(node) ? node : null)); + const routes = ({ find } as any) as RoutesService; + const route = findRoute(routes, path); + expect(route).toBe(expected); + expect(find).toHaveBeenCalledTimes(count); + }, + ); + }); + describe('#getRoutePath', () => { let spectator: SpectatorRouting; const createRouting = createRoutingFactory({ diff --git a/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts index 7ef062986a..56be0300f3 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts @@ -1,4 +1,21 @@ import { PRIMARY_OUTLET, Router, UrlSegmentGroup } from '@angular/router'; +import { ABP } from '../models/common'; +import { RoutesService } from '../services/routes.service'; +import { TreeNode } from './tree-utils'; + +export function findRoute(routes: RoutesService, path: string): TreeNode { + let node = routes.find(route => route.path === path); + + return node || path === '/' + ? node + : findRoute( + routes, + path + .split('/') + .slice(0, -1) + .join('/'), + ); +} export function getRoutePath(router: Router) { const emptyGroup = { segments: [] } as UrlSegmentGroup; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/providers/route.provider.ts b/npm/ng-packs/packages/theme-shared/src/lib/providers/route.provider.ts index 0ffda1ac19..2c71c637fb 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/providers/route.provider.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/providers/route.provider.ts @@ -10,7 +10,7 @@ export function configureRoutes(routes: RoutesService) { return () => { routes.add([ { - path: '', + path: '/', name: eThemeSharedRouteNames.Administration, iconClass: 'fa fa-wrench', order: 1,