diff --git a/.changeset/large-eggs-help.md b/.changeset/large-eggs-help.md
new file mode 100644
index 0000000000..e310ad7645
--- /dev/null
+++ b/.changeset/large-eggs-help.md
@@ -0,0 +1,19 @@
+---
+'@backstage/plugin-explore': minor
+---
+
+Introduce external route for linking to the entity page from the explore plugin.
+
+To use the explore plugin you have to bind the external route in your app:
+
+```typescript
+const app = createApp({
+ ...
+ bindRoutes({ bind }) {
+ ...
+ bind(explorePlugin.externalRoutes, {
+ catalogEntity: catalogPlugin.routes.catalogEntity,
+ });
+ },
+});
+```
diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx
index 5b6f7b95fe..7acde03953 100644
--- a/packages/app/src/App.tsx
+++ b/packages/app/src/App.tsx
@@ -33,7 +33,7 @@ import {
CostInsightsPage,
CostInsightsProjectGrowthInstructionsPage,
} from '@backstage/plugin-cost-insights';
-import { ExplorePage } from '@backstage/plugin-explore';
+import { ExplorePage, explorePlugin } from '@backstage/plugin-explore';
import { GcpProjectsPage } from '@backstage/plugin-gcp-projects';
import { GraphiQLPage } from '@backstage/plugin-graphiql';
import { LighthousePage } from '@backstage/plugin-lighthouse';
@@ -79,6 +79,9 @@ const app = createApp({
bind(apiDocsPlugin.externalRoutes, {
createComponent: scaffolderPlugin.routes.root,
});
+ bind(explorePlugin.externalRoutes, {
+ catalogEntity: catalogPlugin.routes.catalogEntity,
+ });
},
});
diff --git a/plugins/explore/src/components/DomainCard/DomainCard.test.tsx b/plugins/explore/src/components/DomainCard/DomainCard.test.tsx
index 9d409051f6..56a02a3642 100644
--- a/plugins/explore/src/components/DomainCard/DomainCard.test.tsx
+++ b/plugins/explore/src/components/DomainCard/DomainCard.test.tsx
@@ -15,13 +15,13 @@
*/
import { DomainEntity } from '@backstage/catalog-model';
-import { render } from '@testing-library/react';
+import { renderInTestApp } from '@backstage/test-utils';
import React from 'react';
-import { MemoryRouter } from 'react-router-dom';
+import { catalogEntityRouteRef } from '../../routes';
import { DomainCard } from './DomainCard';
describe('', () => {
- it('renders a domain card', () => {
+ it('renders a domain card', async () => {
const entity: DomainEntity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Domain',
@@ -34,9 +34,14 @@ describe('', () => {
owner: 'guest',
},
};
- const { getByText } = render(, {
- wrapper: MemoryRouter,
- });
+ const { getByText } = await renderInTestApp(
+ ,
+ {
+ mountedRoutes: {
+ '/catalog/:namespace/:kind/:name': catalogEntityRouteRef,
+ },
+ },
+ );
expect(getByText('artists')).toBeInTheDocument();
expect(getByText('Everything about artists')).toBeInTheDocument();
diff --git a/plugins/explore/src/components/DomainCard/DomainCard.tsx b/plugins/explore/src/components/DomainCard/DomainCard.tsx
index e5efc543b2..67bee13696 100644
--- a/plugins/explore/src/components/DomainCard/DomainCard.tsx
+++ b/plugins/explore/src/components/DomainCard/DomainCard.tsx
@@ -14,15 +14,14 @@
* limitations under the License.
*/
import { DomainEntity, RELATION_OWNED_BY } from '@backstage/catalog-model';
-import { ItemCard } from '@backstage/core';
+import { ItemCard, useRouteRef } from '@backstage/core';
import {
EntityRefLinks,
- entityRoute,
entityRouteParams,
getEntityRelations,
} from '@backstage/plugin-catalog-react';
import React from 'react';
-import { generatePath } from 'react-router-dom';
+import { catalogEntityRouteRef } from '../../routes';
type DomainCardProps = {
entity: DomainEntity;
@@ -30,6 +29,7 @@ type DomainCardProps = {
export const DomainCard = ({ entity }: DomainCardProps) => {
const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);
+ const catalogEntityRoute = useRouteRef(catalogEntityRouteRef);
return (
{
/>
}
label="Explore"
- // TODO: Use useRouteRef here to generate the path
- href={generatePath(
- `/catalog/${entityRoute.path}`,
- entityRouteParams(entity),
- )}
+ href={catalogEntityRoute(entityRouteParams(entity))}
/>
);
};
diff --git a/plugins/explore/src/components/DomainCard/DomainCardGrid.test.tsx b/plugins/explore/src/components/DomainCard/DomainCardGrid.test.tsx
index bad3ca581b..ee06a50427 100644
--- a/plugins/explore/src/components/DomainCard/DomainCardGrid.test.tsx
+++ b/plugins/explore/src/components/DomainCard/DomainCardGrid.test.tsx
@@ -15,13 +15,13 @@
*/
import { DomainEntity } from '@backstage/catalog-model';
-import { render } from '@testing-library/react';
+import { renderInTestApp } from '@backstage/test-utils';
import React from 'react';
-import { MemoryRouter } from 'react-router-dom';
+import { catalogEntityRouteRef } from '../../routes';
import { DomainCardGrid } from './DomainCardGrid';
describe('', () => {
- it('renders a grid of domain cards', () => {
+ it('renders a grid of domain cards', async () => {
const entities: DomainEntity[] = [
{
apiVersion: 'backstage.io/v1alpha1',
@@ -44,9 +44,14 @@ describe('', () => {
},
},
];
- const { getByText } = render(, {
- wrapper: MemoryRouter,
- });
+ const { getByText } = await renderInTestApp(
+ ,
+ {
+ mountedRoutes: {
+ '/catalog/:namespace/:kind/:name': catalogEntityRouteRef,
+ },
+ },
+ );
expect(getByText('artists')).toBeInTheDocument();
expect(getByText('playback')).toBeInTheDocument();
diff --git a/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx
index f29ad2cd6a..cd3f2847c6 100644
--- a/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx
+++ b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx
@@ -20,6 +20,7 @@ import { catalogApiRef } from '@backstage/plugin-catalog-react';
import { renderInTestApp } from '@backstage/test-utils';
import { waitFor } from '@testing-library/react';
import React from 'react';
+import { catalogEntityRouteRef } from '../../routes';
import { DomainExplorerContent } from './DomainExplorerContent';
describe('', () => {
@@ -71,6 +72,11 @@ describe('', () => {
,
+ {
+ mountedRoutes: {
+ '/catalog/:namespace/:kind/:name': catalogEntityRouteRef,
+ },
+ },
);
await waitFor(() => {
@@ -86,6 +92,11 @@ describe('', () => {
,
+ {
+ mountedRoutes: {
+ '/catalog/:namespace/:kind/:name': catalogEntityRouteRef,
+ },
+ },
);
await waitFor(() =>
@@ -101,6 +112,11 @@ describe('', () => {
,
+ {
+ mountedRoutes: {
+ '/catalog/:namespace/:kind/:name': catalogEntityRouteRef,
+ },
+ },
);
await waitFor(() =>
diff --git a/plugins/explore/src/plugin.ts b/plugins/explore/src/plugin.ts
index 27573eaeb9..c5dd6644e7 100644
--- a/plugins/explore/src/plugin.ts
+++ b/plugins/explore/src/plugin.ts
@@ -16,7 +16,7 @@
import { createApiFactory, createPlugin } from '@backstage/core';
import { exploreToolsConfigRef } from '@backstage/plugin-explore-react';
-import { exploreRouteRef } from './routes';
+import { catalogEntityRouteRef, exploreRouteRef } from './routes';
import { exampleTools } from './util/examples';
export const explorePlugin = createPlugin({
@@ -37,4 +37,7 @@ export const explorePlugin = createPlugin({
routes: {
explore: exploreRouteRef,
},
+ externalRoutes: {
+ catalogEntity: catalogEntityRouteRef,
+ },
});
diff --git a/plugins/explore/src/routes.ts b/plugins/explore/src/routes.ts
index c41a53128f..fc7868c4c9 100644
--- a/plugins/explore/src/routes.ts
+++ b/plugins/explore/src/routes.ts
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import { createRouteRef } from '@backstage/core';
+import { createExternalRouteRef, createRouteRef } from '@backstage/core';
const NoIcon = () => null;
@@ -22,3 +22,8 @@ export const exploreRouteRef = createRouteRef({
icon: NoIcon,
title: 'Explore',
});
+
+export const catalogEntityRouteRef = createExternalRouteRef({
+ id: 'catalog-entity',
+ params: ['namespace', 'kind', 'name'],
+});