From f2641eabb57f23013e84b7c52dd2439a8b61ed20 Mon Sep 17 00:00:00 2001
From: Aramis Sennyey
Date: Tue, 29 Nov 2022 12:54:18 -0500
Subject: [PATCH] reset basePath
Signed-off-by: Aramis Sennyey
---
packages/core-app-api/src/app/AppManager.tsx | 5 +-
packages/core-app-api/src/app/types.ts | 4 -
.../core-app-api/src/routing/RouteResolver.ts | 16 +--
.../src/components/Link/Link.test.tsx | 99 ++++++++++++++++++-
.../src/components/Link/Link.tsx | 2 +-
5 files changed, 110 insertions(+), 16 deletions(-)
diff --git a/packages/core-app-api/src/app/AppManager.tsx b/packages/core-app-api/src/app/AppManager.tsx
index 9b3dc841d0..571eaf72e0 100644
--- a/packages/core-app-api/src/app/AppManager.tsx
+++ b/packages/core-app-api/src/app/AppManager.tsx
@@ -332,6 +332,7 @@ export class AppManager implements BackstageApp {
routeParents={routing.parents}
routeObjects={routing.objects}
routeBindings={routeBindings}
+ basePath={getBasePath(loadedConfig.api)}
>
+
{children}
@@ -437,7 +438,7 @@ export class AppManager implements BackstageApp {
}
return (
-
+
<>{children}>
diff --git a/packages/core-app-api/src/app/types.ts b/packages/core-app-api/src/app/types.ts
index b548533df3..70022534a1 100644
--- a/packages/core-app-api/src/app/types.ts
+++ b/packages/core-app-api/src/app/types.ts
@@ -60,10 +60,6 @@ export type ErrorBoundaryFallbackProps = {
resetError: () => void;
};
-export type RouterProps = {
- basename: string;
-};
-
/**
* A set of replaceable core components that are part of every Backstage app.
*
diff --git a/packages/core-app-api/src/routing/RouteResolver.ts b/packages/core-app-api/src/routing/RouteResolver.ts
index 1b23aa30f1..f17c549bc6 100644
--- a/packages/core-app-api/src/routing/RouteResolver.ts
+++ b/packages/core-app-api/src/routing/RouteResolver.ts
@@ -214,13 +214,15 @@ export class RouteResolver {
// Next we figure out the base path, which is the combination of the common parent path
// between our current location and our target location, as well as the additional path
// that is the difference between the parent path and the base of our target location.
- const basePath = resolveBasePath(
- targetRef,
- relativeSourceLocation,
- this.routePaths,
- this.routeParents,
- this.routeObjects,
- );
+ const basePath =
+ this.appBasePath +
+ resolveBasePath(
+ targetRef,
+ relativeSourceLocation,
+ this.routePaths,
+ this.routeParents,
+ this.routeObjects,
+ );
const routeFunc: RouteFunc = (...[params]) => {
return joinPaths(basePath, generatePath(targetPath, params));
diff --git a/packages/core-components/src/components/Link/Link.test.tsx b/packages/core-components/src/components/Link/Link.test.tsx
index 7be8753b34..c18812d897 100644
--- a/packages/core-components/src/components/Link/Link.test.tsx
+++ b/packages/core-components/src/components/Link/Link.test.tsx
@@ -21,9 +21,11 @@ import {
TestApiProvider,
wrapInTestApp,
} from '@backstage/test-utils';
-import { analyticsApiRef } from '@backstage/core-plugin-api';
-import { isExternalUri, Link } from './Link';
+import { analyticsApiRef, configApiRef } from '@backstage/core-plugin-api';
+import { isExternalUri, Link, useResolvedPath } from './Link';
import { Route, Routes } from 'react-router';
+import { ConfigReader } from '@backstage/config';
+import { renderHook, WrapperComponent } from '@testing-library/react-hooks';
describe('', () => {
it('navigates using react-router', async () => {
@@ -105,6 +107,58 @@ describe('', () => {
});
});
+ describe('resolves a sub-path correctly', () => {
+ it('when it starts with base path', async () => {
+ const testString = 'This is test string';
+ const linkText = 'Navigate!';
+ const configApi = new ConfigReader({
+ app: { baseUrl: 'http://localhost:3000/example' },
+ });
+
+ const { getByText } = render(
+ wrapInTestApp(
+
+ {linkText}
+
+ {testString}
} />
+
+ ,
+ ),
+ );
+
+ expect(() => getByText(testString)).toThrow();
+ fireEvent.click(getByText(linkText));
+ await waitFor(() => {
+ expect(getByText(testString)).toBeInTheDocument();
+ });
+ });
+
+ it('when it does not start with base path', async () => {
+ const testString = 'This is test string';
+ const linkText = 'Navigate!';
+ const configApi = new ConfigReader({
+ app: { baseUrl: 'http://localhost:3000/example' },
+ });
+
+ const { getByText } = render(
+ wrapInTestApp(
+
+ {linkText}
+
+ {testString}} />
+
+ ,
+ ),
+ );
+
+ expect(() => getByText(testString)).toThrow();
+ fireEvent.click(getByText(linkText));
+ await waitFor(() => {
+ expect(getByText(testString)).toBeInTheDocument();
+ });
+ });
+ });
+
describe('isExternalUri', () => {
it.each([
[true, 'http://'],
@@ -130,4 +184,45 @@ describe('', () => {
expect(isExternalUri(uri)).toBe(expected);
});
});
+
+ describe('useResolvedPath', () => {
+ const wrapper: WrapperComponent<{}> = ({ children }) => {
+ const configApi = new ConfigReader({
+ app: { baseUrl: 'http://localhost:3000/example' },
+ });
+ return (
+
+ {children}
+
+ );
+ };
+
+ describe('concatenate base path', () => {
+ it('when uri is internal and does not start with base path', () => {
+ const path = '/catalog/default/component/artist-lookup';
+ const { result } = renderHook(() => useResolvedPath(path), {
+ wrapper,
+ });
+ expect(result.current).toBe('/example'.concat(path));
+ });
+ });
+
+ describe('does not concatenate base path', () => {
+ it('when uri is external', () => {
+ const path = 'https://stackoverflow.com/questions/1/example';
+ const { result } = renderHook(() => useResolvedPath(path), {
+ wrapper,
+ });
+ expect(result.current).toBe(path);
+ });
+
+ it('when uri already starts with base path', () => {
+ const path = '/example/catalog/default/component/artist-lookup';
+ const { result } = renderHook(() => useResolvedPath(path), {
+ wrapper,
+ });
+ expect(result.current).toBe(path);
+ });
+ });
+ });
});
diff --git a/packages/core-components/src/components/Link/Link.tsx b/packages/core-components/src/components/Link/Link.tsx
index 239f6382c4..66b7453abd 100644
--- a/packages/core-components/src/components/Link/Link.tsx
+++ b/packages/core-components/src/components/Link/Link.tsx
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import { useAnalytics } from '@backstage/core-plugin-api';
+import { configApiRef, useAnalytics, useApi } from '@backstage/core-plugin-api';
import classnames from 'classnames';
// eslint-disable-next-line no-restricted-imports
import MaterialLink, {