Remove from public interface and make techdocs specific.

Signed-off-by: Aramis Sennyey <sennyeya@amazon.com>
This commit is contained in:
Aramis Sennyey
2023-03-24 12:35:15 -04:00
parent 383f30f9d6
commit d31664d154
6 changed files with 3 additions and 7 deletions
@@ -46,7 +46,7 @@ import {
useSanitizerTransformer,
useStylesTransformer,
} from '../../transformers';
import { useNavigateUrl } from '@backstage/core-app-api';
import { useNavigateUrl } from './useNavigateUrl';
const MOBILE_MEDIA_QUERY = 'screen and (max-width: 76.1875em)';
@@ -0,0 +1,120 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import {
MockConfigApi,
renderInTestApp,
TestApiProvider,
} from '@backstage/test-utils';
import { resolveUrlToRelative, useNavigateUrl } from './useNavigateUrl';
import { configApiRef } from '@backstage/core-plugin-api';
const navigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => navigate,
}));
describe('resolveUrlToRelative', () => {
it('does nothing when app.baseUrl has no subpath', () => {
const url = 'http://localhost:3000/test';
const baseUrl = 'http://localhost:3000';
expect(resolveUrlToRelative(url, baseUrl)).toBe('/test');
});
it('removes the app.baseUrl subpath when present', () => {
const url = 'http://localhost:3000/instance/test';
const baseUrl = 'http://localhost:3000/instance';
expect(resolveUrlToRelative(url, baseUrl)).toBe('/test');
});
it('removes trailing slashes on the URL when present', () => {
const url = 'http://localhost:3000/test//';
const baseUrl = 'http://localhost:3000';
expect(resolveUrlToRelative(url, baseUrl)).toBe('/test');
});
});
const Component = ({ to }: { to: string }) => {
const navigateTo = useNavigateUrl();
return <>{navigateTo(to)}</>;
};
describe('useNavigateUrl', () => {
beforeEach(() => {
navigate.mockReset();
});
it('navigates to the desired page as expected', async () => {
const baseUrl = 'http://localhost:3000';
await renderInTestApp(
<TestApiProvider
apis={[
[
configApiRef,
new MockConfigApi({
app: {
baseUrl,
},
}),
],
]}
>
<Component to={`${baseUrl}/test`} />
</TestApiProvider>,
);
expect(navigate).toHaveBeenCalledWith('/test');
});
it('handles app.baseUrl subpaths', async () => {
const baseUrl = 'http://localhost:3000/instance';
await renderInTestApp(
<TestApiProvider
apis={[
[
configApiRef,
new MockConfigApi({
app: {
baseUrl,
},
}),
],
]}
>
<Component to={`${baseUrl}/test`} />
</TestApiProvider>,
);
expect(navigate).toHaveBeenCalledWith('/test');
});
it('handles relative urls', async () => {
const baseUrl = 'http://localhost:3000';
await renderInTestApp(
<TestApiProvider
apis={[
[
configApiRef,
new MockConfigApi({
app: {
baseUrl,
},
}),
],
]}
>
<Component to="/test" />
</TestApiProvider>,
);
expect(navigate).toHaveBeenCalledWith('/test');
});
});
@@ -0,0 +1,79 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { configApiRef, useApi } from '@backstage/core-plugin-api';
import { useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
/**
* Resolve a URL to a relative URL given a base URL that may or may not include subpaths.
* @param url - URL to parse into a relative url based on the baseUrl.
* @param baseUrl - Application base url, where the application is currently hosted.
* @returns relative path without any subpaths from website config.
*/
export function resolveUrlToRelative(url: string, baseUrl: string) {
const parsedAppUrl = new URL(baseUrl);
const appUrlPath = `${parsedAppUrl.origin}${parsedAppUrl.pathname.replace(
/\/$/,
'',
)}`;
const relativeUrl = url
.replace(appUrlPath, '')
// Remove any leading and trailing slashes.
.replace(/\/+$/, '')
.replace(/^\/+/, '');
const parsedUrl = new URL(`http://localhost/${relativeUrl}`);
return `${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`;
}
/**
* A helper hook that allows for full internal website urls to be processed through the navigate
* hook provided by `react-router-dom`.
*
* NOTE: This does not support routing to external URLs. That should be done with a `Link` or `a`
* element instead, or just `window.location.href`.
*
* TODO: Update this to use `useRouteRef` instead of `useApi`.
*
* @returns Navigation function that is a wrapper over `react-router-dom`'s
* to support passing full URLs for navigation.
*
* @public
*/
export function useNavigateUrl() {
const navigate = useNavigate();
const configApi = useApi(configApiRef);
const appBaseUrl = configApi.getOptionalString('app.baseUrl');
const navigateFn = useCallback(
(to: string) => {
let url = to;
/**
* This should always be true when running the application, this just allows
* test cases that do not have the configApi set up to run still.
*/
if (appBaseUrl) {
try {
url = resolveUrlToRelative(to, appBaseUrl);
} catch (err) {
// URL passed in was relative.
}
}
navigate(url);
},
[navigate, appBaseUrl],
);
return navigateFn;
}