Merge pull request #3818 from backstage/mob/gratherobj
core-api: gather all relevant route refs into each route object
This commit is contained in:
@@ -15,7 +15,11 @@
|
||||
*/
|
||||
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { routePathCollector, routeParentCollector } from './collectors';
|
||||
import {
|
||||
routePathCollector,
|
||||
routeParentCollector,
|
||||
routeObjectCollector,
|
||||
} from './collectors';
|
||||
|
||||
import {
|
||||
traverseElementTree,
|
||||
@@ -86,6 +90,16 @@ function sortedEntries<T>(map: Map<RouteRef, T>): [RouteRef, T][] {
|
||||
);
|
||||
}
|
||||
|
||||
function routeObj(path: string, refs: RouteRef[], children: any[] = []) {
|
||||
return {
|
||||
path: path,
|
||||
caseSensitive: false,
|
||||
element: null,
|
||||
routeRefs: new Set(refs),
|
||||
children: children,
|
||||
};
|
||||
}
|
||||
|
||||
describe('discovery', () => {
|
||||
it('should collect routes', () => {
|
||||
const list = [
|
||||
@@ -124,12 +138,13 @@ describe('discovery', () => {
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const { routes, routeParents } = traverseElementTree({
|
||||
const { routes, routeParents, routeObjects } = traverseElementTree({
|
||||
root,
|
||||
discoverers: [childDiscoverer, routeElementDiscoverer],
|
||||
collectors: {
|
||||
routes: routePathCollector,
|
||||
routeParents: routeParentCollector,
|
||||
routeObjects: routeObjectCollector,
|
||||
},
|
||||
});
|
||||
expect(sortedEntries(routes)).toEqual([
|
||||
@@ -146,6 +161,17 @@ describe('discovery', () => {
|
||||
[ref4, undefined],
|
||||
[ref5, ref1],
|
||||
]);
|
||||
expect(routeObjects).toEqual([
|
||||
routeObj(
|
||||
'/foo',
|
||||
[ref1],
|
||||
[
|
||||
routeObj('/bar/:id', [ref2], [routeObj('/baz', [ref3])]),
|
||||
routeObj('/blop', [ref5]),
|
||||
],
|
||||
),
|
||||
routeObj('/divsoup', [ref4]),
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle all react router Route patterns', () => {
|
||||
@@ -216,12 +242,13 @@ describe('discovery', () => {
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const { routes, routeParents } = traverseElementTree({
|
||||
const { routes, routeParents, routeObjects } = traverseElementTree({
|
||||
root,
|
||||
discoverers: [childDiscoverer, routeElementDiscoverer],
|
||||
collectors: {
|
||||
routes: routePathCollector,
|
||||
routeParents: routeParentCollector,
|
||||
routeObjects: routeObjectCollector,
|
||||
},
|
||||
});
|
||||
expect(sortedEntries(routes)).toEqual([
|
||||
@@ -238,6 +265,10 @@ describe('discovery', () => {
|
||||
[ref4, ref3],
|
||||
[ref5, ref3],
|
||||
]);
|
||||
expect(routeObjects).toEqual([
|
||||
routeObj('/foo', [ref1, ref2]),
|
||||
routeObj('/bar', [ref3], [routeObj('/baz', [ref4, ref5])]),
|
||||
]);
|
||||
});
|
||||
|
||||
it('should use the route aggregator but stop when encountering explicit path', () => {
|
||||
@@ -258,12 +289,13 @@ describe('discovery', () => {
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const { routes, routeParents } = traverseElementTree({
|
||||
const { routes, routeParents, routeObjects } = traverseElementTree({
|
||||
root,
|
||||
discoverers: [childDiscoverer, routeElementDiscoverer],
|
||||
collectors: {
|
||||
routes: routePathCollector,
|
||||
routeParents: routeParentCollector,
|
||||
routeObjects: routeObjectCollector,
|
||||
},
|
||||
});
|
||||
expect(sortedEntries(routes)).toEqual([
|
||||
@@ -280,6 +312,19 @@ describe('discovery', () => {
|
||||
[ref4, ref3],
|
||||
[ref5, ref1],
|
||||
]);
|
||||
expect(routeObjects).toEqual([
|
||||
routeObj(
|
||||
'/foo',
|
||||
[ref1],
|
||||
[
|
||||
routeObj(
|
||||
'/bar',
|
||||
[ref2, ref5],
|
||||
[routeObj('/baz', [ref3], [routeObj('/blop', [ref4])])],
|
||||
),
|
||||
],
|
||||
),
|
||||
]);
|
||||
});
|
||||
|
||||
it('should stop gathering mount points after encountering explicit path', () => {
|
||||
|
||||
@@ -111,9 +111,10 @@ export const routeParentCollector = createCollector(
|
||||
|
||||
export const routeObjectCollector = createCollector(
|
||||
() => Array<BackstageRouteObject>(),
|
||||
(acc, node, parent, parentChildArr: BackstageRouteObject[] = acc) => {
|
||||
(acc, node, parent, parentObj: BackstageRouteObject | undefined) => {
|
||||
const parentChildren = parentObj?.children ?? acc;
|
||||
if (parent?.props.element === node) {
|
||||
return parentChildArr;
|
||||
return parentObj;
|
||||
}
|
||||
|
||||
const path: string | undefined = node.props?.path;
|
||||
@@ -121,20 +122,40 @@ export const routeObjectCollector = createCollector(
|
||||
|
||||
const routeRef = getMountPoint(node);
|
||||
if (routeRef) {
|
||||
const children: BackstageRouteObject[] = [];
|
||||
if (!path) {
|
||||
throw new Error(`No path found for mount point ${routeRef}`);
|
||||
if (path) {
|
||||
const newObject: BackstageRouteObject = {
|
||||
caseSensitive,
|
||||
path,
|
||||
element: null,
|
||||
routeRefs: new Set([routeRef]),
|
||||
children: [],
|
||||
};
|
||||
parentChildren.push(newObject);
|
||||
return newObject;
|
||||
}
|
||||
parentChildArr.push({
|
||||
|
||||
parentObj?.routeRefs.add(routeRef);
|
||||
}
|
||||
|
||||
const isGatherer = getComponentData<boolean>(
|
||||
node,
|
||||
'core.gatherMountPoints',
|
||||
);
|
||||
if (isGatherer) {
|
||||
if (!path) {
|
||||
throw new Error('Mount point gatherer must have a path');
|
||||
}
|
||||
const newObject: BackstageRouteObject = {
|
||||
caseSensitive,
|
||||
path,
|
||||
element: null,
|
||||
routeRef,
|
||||
children,
|
||||
});
|
||||
return children;
|
||||
routeRefs: new Set(),
|
||||
children: [],
|
||||
};
|
||||
parentChildren.push(newObject);
|
||||
return newObject;
|
||||
}
|
||||
|
||||
return parentChildArr;
|
||||
return parentObj;
|
||||
},
|
||||
);
|
||||
|
||||
@@ -60,8 +60,8 @@ class RouteResolver {
|
||||
currentRouteRef;
|
||||
currentRouteRef = this.routeParents.get(currentRouteRef)
|
||||
) {
|
||||
matchIndex = match.findIndex(
|
||||
m => (m.route as BackstageRouteObject).routeRef === currentRouteRef,
|
||||
matchIndex = match.findIndex(m =>
|
||||
(m.route as BackstageRouteObject).routeRefs.has(currentRouteRef!),
|
||||
);
|
||||
if (matchIndex !== -1) {
|
||||
break;
|
||||
|
||||
@@ -62,5 +62,5 @@ export interface BackstageRouteObject {
|
||||
children?: BackstageRouteObject[];
|
||||
element: React.ReactNode;
|
||||
path: string;
|
||||
routeRef: AnyRouteRef;
|
||||
routeRefs: Set<AnyRouteRef>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user