Account for sub-route context inheritance

Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
Eric Peterson
2023-07-19 17:56:17 +02:00
parent 9ae4e7e638
commit 0ed86cc838
2 changed files with 39 additions and 6 deletions
@@ -39,6 +39,7 @@ describe('RouteTracker', () => {
});
const plugin0 = createPlugin({ id: 'home' });
const plugin1 = createPlugin({ id: 'plugin1' });
const plugin2 = createPlugin({ id: 'plugin2' });
const routeObjects: BackstageRouteObject[] = [
{
@@ -61,7 +62,7 @@ describe('RouteTracker', () => {
path: '/path2/:param',
element: <div>hi there</div>,
routeRefs: new Set([routeRef2]),
plugins: new Set(),
plugins: new Set([plugin2]),
caseSensitive: false,
children: [MATCH_ALL_ROUTE],
},
@@ -124,7 +125,7 @@ describe('RouteTracker', () => {
},
context: {
extension: 'App',
pluginId: 'root',
pluginId: 'plugin2',
routeRef: 'route2',
},
subject: '/path2/hello',
@@ -179,7 +180,7 @@ describe('RouteTracker', () => {
});
});
it('should return default context when no plugin/routeRef is on the route', async () => {
it('should return default context when it would have otherwise matched on the root path', async () => {
render(
<MemoryRouter initialEntries={['/not-routable-extension']}>
<TestApiProvider apis={[[analyticsApiRef, mockedAnalytics]]}>
@@ -206,4 +207,28 @@ describe('RouteTracker', () => {
value: undefined,
});
});
it('should return parent route context on navigating to a sub-route', async () => {
render(
<MemoryRouter initialEntries={['/path2/param-value/sub-route']}>
<TestApiProvider apis={[[analyticsApiRef, mockedAnalytics]]}>
<RouteTracker routeObjects={routeObjects} />
</TestApiProvider>
</MemoryRouter>,
);
expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({
action: 'navigate',
attributes: {
param: 'param-value',
},
context: {
extension: 'App',
pluginId: 'plugin2',
routeRef: 'route2',
},
subject: '/path2/param-value/sub-route',
value: undefined,
});
});
});
@@ -38,9 +38,11 @@ const getExtensionContext = (
const matches = matchRoutes(routes, { pathname });
// Of the matching routes, get the last (e.g. most specific) instance of
// the BackstageRouteObject.
const routeMatch = matches?.pop();
// the BackstageRouteObject that contains a routeRef. Filtering by routeRef
// ensures subRouteRefs are aligned to their parent routes' context.
const routeMatch = matches
?.filter(match => match?.route.routeRefs?.size > 0)
.pop();
const routeObject = routeMatch?.route;
// If there is no route object, then allow inheritance of default context.
@@ -48,6 +50,12 @@ const getExtensionContext = (
return undefined;
}
// If the matched route is the root route (no path), and the pathname is
// not the path of the homepage, then inherit from the default context.
if (routeObject.path === '' && pathname !== '/') {
return undefined;
}
// If there is a single route ref, use it.
let routeRef: RouteRef | undefined;
if (routeObject.routeRefs.size === 1) {