diff --git a/.changeset/cuddly-donuts-whisper.md b/.changeset/cuddly-donuts-whisper.md new file mode 100644 index 0000000000..fd1b665b99 --- /dev/null +++ b/.changeset/cuddly-donuts-whisper.md @@ -0,0 +1,54 @@ +--- +'@backstage/plugin-explore': patch +--- + +Refactors the explore plugin to be more customizable. This includes the following non-breaking changes: + +- Introduce new `ExploreLayout` page which can be used to create a custom `ExplorePage` +- Refactor `ExplorePage` to use a new `ExploreLayout` component +- Exports existing `DomainExplorerContent`, `GroupsExplorerContent`, & `ToolExplorerContent` components +- Allows `title` props to be customized + +Create a custom explore page in `packages/app/src/components/explore/ExplorePage.tsx`. + +```tsx +import { + DomainExplorerContent, + ExploreLayout, +} from '@backstage/plugin-explore'; +import React from 'react'; +import { InnserSourceExplorerContent } from './InnserSourceExplorerContent'; + +export const ExplorePage = () => { + return ( + + + + + + + + + ); +}; + +export const explorePage = ; +``` + +Now register the new explore page in `packages/app/src/App.tsx`. + +```diff ++ import { explorePage } from './components/explore/ExplorePage'; + +const routes = ( + +- } /> ++ }> ++ {explorePage} ++ + +); +``` diff --git a/plugins/explore/README.md b/plugins/explore/README.md index fea1333e34..8e1cbaed02 100644 --- a/plugins/explore/README.md +++ b/plugins/explore/README.md @@ -33,3 +33,49 @@ import LayersIcon from '@material-ui/icons/Layers'; ``` + +## Customization + +Create a custom explore page in `packages/app/src/components/explore/ExplorePage.tsx`. + +```tsx +import { + DomainExplorerContent, + ExploreLayout, +} from '@backstage/plugin-explore'; +import React from 'react'; +import { InnserSourceExplorerContent } from './InnserSourceExplorerContent'; + +export const ExplorePage = () => { + return ( + + + + + + + + + ); +}; + +export const explorePage = ; +``` + +Now register the new explore page in `packages/app/src/App.tsx`. + +```diff ++ import { explorePage } from './components/explore/ExplorePage'; + +const routes = ( + +- } /> ++ }> ++ {explorePage} ++ + +); +``` diff --git a/plugins/explore/package.json b/plugins/explore/package.json index fd6ff19a93..7a7d923c8d 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -38,9 +38,11 @@ "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", + "@types/react": "^16.9", "classnames": "^2.2.6", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, diff --git a/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.test.tsx b/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.test.tsx new file mode 100644 index 0000000000..8f69ea3527 --- /dev/null +++ b/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.test.tsx @@ -0,0 +1,63 @@ +/* + * Copyright 2020 Spotify AB + * + * 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 { ApiProvider, ApiRegistry } from '@backstage/core'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import { renderInTestApp } from '@backstage/test-utils'; +import { waitFor, getByText } from '@testing-library/react'; +import React from 'react'; +import { DefaultExplorePage } from './DefaultExplorePage'; + +describe('', () => { + const catalogApi: jest.Mocked = { + addLocation: jest.fn(_a => new Promise(() => {})), + getEntities: jest.fn(), + getOriginLocationByEntity: jest.fn(), + getLocationByEntity: jest.fn(), + getLocationById: jest.fn(), + removeLocationById: jest.fn(), + removeEntityByUid: jest.fn(), + getEntityByName: jest.fn(), + }; + + const Wrapper = ({ children }: { children?: React.ReactNode }) => ( + + {children} + + ); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('renders the default explore page', async () => { + catalogApi.getEntities.mockResolvedValue({ items: [] }); + + const { getAllByRole } = await renderInTestApp( + + + , + ); + + await waitFor(() => { + const elements = getAllByRole('tab'); + expect(elements.length).toBe(3); + expect(getByText(elements[0], 'Domains')).toBeInTheDocument(); + expect(getByText(elements[1], 'Groups')).toBeInTheDocument(); + expect(getByText(elements[2], 'Tools')).toBeInTheDocument(); + }); + }); +}); diff --git a/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.tsx b/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.tsx new file mode 100644 index 0000000000..abc73dca31 --- /dev/null +++ b/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.tsx @@ -0,0 +1,45 @@ +/* + * Copyright 2021 Spotify AB + * + * 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 { configApiRef, useApi } from '@backstage/core'; +import { DomainExplorerContent } from '../DomainExplorerContent'; +import { ExploreLayout } from '../ExploreLayout'; +import { GroupsExplorerContent } from '../GroupsExplorerContent'; +import { ToolExplorerContent } from '../ToolExplorerContent'; + +export const DefaultExplorePage = () => { + const configApi = useApi(configApiRef); + const organizationName = + configApi.getOptionalString('organization.name') ?? 'Backstage'; + + return ( + + + + + + + + + + + + ); +}; diff --git a/plugins/explore/src/components/DefaultExplorePage/index.ts b/plugins/explore/src/components/DefaultExplorePage/index.ts new file mode 100644 index 0000000000..b4df272266 --- /dev/null +++ b/plugins/explore/src/components/DefaultExplorePage/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 Spotify AB + * + * 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. + */ + +export { DefaultExplorePage } from './DefaultExplorePage'; diff --git a/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx index 1784587a95..1a93463862 100644 --- a/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx +++ b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx @@ -41,6 +41,12 @@ describe('', () => { ); + const mountedRoutes = { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': catalogEntityRouteRef, + }, + }; + beforeEach(() => { jest.resetAllMocks(); }); @@ -74,11 +80,7 @@ describe('', () => { , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': catalogEntityRouteRef, - }, - }, + mountedRoutes, ); await waitFor(() => { @@ -87,6 +89,19 @@ describe('', () => { }); }); + it('renders a custom title', async () => { + catalogApi.getEntities.mockResolvedValue({ items: [] }); + + const { getByText } = await renderInTestApp( + + + , + mountedRoutes, + ); + + await waitFor(() => expect(getByText('Our Areas')).toBeInTheDocument()); + }); + it('renders empty state', async () => { catalogApi.getEntities.mockResolvedValue({ items: [] }); @@ -94,11 +109,7 @@ describe('', () => { , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': catalogEntityRouteRef, - }, - }, + mountedRoutes, ); await waitFor(() => @@ -114,11 +125,7 @@ describe('', () => { , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': catalogEntityRouteRef, - }, - }, + mountedRoutes, ); await waitFor(() => diff --git a/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.tsx b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.tsx index a12811e486..8217413842 100644 --- a/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.tsx +++ b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.tsx @@ -79,10 +79,16 @@ const Body = () => { ); }; -export const DomainExplorerContent = () => { +type DomainExplorerContentProps = { + title?: string; +}; + +export const DomainExplorerContent = ({ + title, +}: DomainExplorerContentProps) => { return ( - + Discover the domains in your ecosystem. diff --git a/plugins/explore/src/components/ExploreLayout/ExploreLayout.test.tsx b/plugins/explore/src/components/ExploreLayout/ExploreLayout.test.tsx new file mode 100644 index 0000000000..1021ff25d0 --- /dev/null +++ b/plugins/explore/src/components/ExploreLayout/ExploreLayout.test.tsx @@ -0,0 +1,81 @@ +/* + * Copyright 2020 Spotify AB + * + * 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 { renderInTestApp } from '@backstage/test-utils'; +import { waitFor } from '@testing-library/react'; +import React from 'react'; +import { ExploreLayout } from './ExploreLayout'; + +describe('', () => { + const Wrapper = ({ children }: { children?: React.ReactNode }) => ( + <>{children} + ); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('renders an explore tabbed layout page with defaults', async () => { + const { getByText } = await renderInTestApp( + + + +
Tools Content
+
+
+
, + ); + + await waitFor(() => { + expect(getByText('Explore our ecosystem')).toBeInTheDocument(); + expect( + getByText('Discover solutions available in our ecosystem'), + ).toBeInTheDocument(); + }); + }); + + it('renders a custom page title', async () => { + const { getByText } = await renderInTestApp( + + + +
Tools Content
+
+
+
, + ); + + await waitFor(() => + expect(getByText('Explore our universe')).toBeInTheDocument(), + ); + }); + + it('renders a custom page subtitle', async () => { + const { getByText } = await renderInTestApp( + + + +
Tools Content
+
+
+
, + ); + + await waitFor(() => + expect(getByText('Browse the ACME Corp ecosystem')).toBeInTheDocument(), + ); + }); +}); diff --git a/plugins/explore/src/components/ExploreLayout/ExploreLayout.tsx b/plugins/explore/src/components/ExploreLayout/ExploreLayout.tsx new file mode 100644 index 0000000000..7e64ed815c --- /dev/null +++ b/plugins/explore/src/components/ExploreLayout/ExploreLayout.tsx @@ -0,0 +1,102 @@ +/* + * Copyright 2020 Spotify AB + * + * 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 { attachComponentData, Header, Page, RoutedTabs } from '@backstage/core'; +import { TabProps } from '@material-ui/core'; +import { Children, default as React, Fragment, isValidElement } from 'react'; + +// TODO: This layout could be a shared based component if it was possible to create custom TabbedLayouts +// A generalized version of createSubRoutesFromChildren, etc. would be required + +type SubRoute = { + path: string; + title: string; + children: JSX.Element; + tabProps?: TabProps; +}; + +const Route: (props: SubRoute) => null = () => null; + +// This causes all mount points that are discovered within this route to use the path of the route itself +attachComponentData(Route, 'core.gatherMountPoints', true); + +function createSubRoutesFromChildren( + childrenProps: React.ReactNode, +): SubRoute[] { + // Directly comparing child.type with Route will not work with in + // combination with react-hot-loader in storybook + // https://github.com/gaearon/react-hot-loader/issues/304 + const routeType = ( + +
+ + ).type; + + return Children.toArray(childrenProps).flatMap(child => { + if (!isValidElement(child)) { + return []; + } + + if (child.type === Fragment) { + return createSubRoutesFromChildren(child.props.children); + } + + if (child.type !== routeType) { + throw new Error('Child of ExploreLayout must be an ExploreLayout.Route'); + } + + const { path, title, children, tabProps } = child.props; + return [{ path, title, children, tabProps }]; + }); +} + +type ExploreLayoutProps = { + title?: string; + subtitle?: string; + children?: React.ReactNode; +}; + +/** + * Explore is a compound component, which allows you to define a custom layout + * + * @example + * ```jsx + * + * + *
This is rendered under /example/anything-here route
+ *
+ *
+ * ``` + */ +export const ExploreLayout = ({ + title, + subtitle, + children, +}: ExploreLayoutProps) => { + const routes = createSubRoutesFromChildren(children); + + return ( + +
+ + + ); +}; + +ExploreLayout.Route = Route; diff --git a/plugins/explore/src/components/ExploreLayout/index.ts b/plugins/explore/src/components/ExploreLayout/index.ts new file mode 100644 index 0000000000..6cbae79a71 --- /dev/null +++ b/plugins/explore/src/components/ExploreLayout/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 Spotify AB + * + * 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. + */ + +export { ExploreLayout } from './ExploreLayout'; diff --git a/plugins/explore/src/components/ExplorePage/ExplorePage.test.tsx b/plugins/explore/src/components/ExplorePage/ExplorePage.test.tsx new file mode 100644 index 0000000000..9034ee72c0 --- /dev/null +++ b/plugins/explore/src/components/ExplorePage/ExplorePage.test.tsx @@ -0,0 +1,48 @@ +/* + * Copyright 2020 Spotify AB + * + * 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 { renderInTestApp } from '@backstage/test-utils'; +import React from 'react'; +import { useOutlet } from 'react-router'; +import { ExplorePage } from './ExplorePage'; + +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), + useLocation: jest.fn().mockReturnValue({ + search: '', + }), + useOutlet: jest.fn().mockReturnValue('Route Children'), +})); + +jest.mock('../DefaultExplorePage', () => ({ + ...jest.requireActual('../DefaultExplorePage'), + DefaultExplorePage: jest.fn().mockReturnValue('DefaultExplorePageMock'), +})); + +describe('ExplorePage', () => { + it('renders provided router element', async () => { + const { getByText } = await renderInTestApp(); + + expect(getByText('Route Children')).toBeInTheDocument(); + }); + + it('renders default explorer page when no router children are provided', async () => { + (useOutlet as jest.Mock).mockReturnValueOnce(null); + const { getByText } = await renderInTestApp(); + + expect(getByText('DefaultExplorePageMock')).toBeInTheDocument(); + }); +}); diff --git a/plugins/explore/src/components/ExplorePage/ExplorePage.tsx b/plugins/explore/src/components/ExplorePage/ExplorePage.tsx index 3f9394a1ab..e3601614d2 100644 --- a/plugins/explore/src/components/ExplorePage/ExplorePage.tsx +++ b/plugins/explore/src/components/ExplorePage/ExplorePage.tsx @@ -13,22 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { configApiRef, Header, Page, useApi } from '@backstage/core'; + import React from 'react'; -import { ExploreTabs } from './ExploreTabs'; +import { useOutlet } from 'react-router'; +import { DefaultExplorePage } from '../DefaultExplorePage'; export const ExplorePage = () => { - const configApi = useApi(configApiRef); - const organizationName = - configApi.getOptionalString('organization.name') ?? 'Backstage'; - return ( - -
+ const outlet = useOutlet(); - - - ); + return <>{outlet || }; }; diff --git a/plugins/explore/src/components/ExplorePage/ExploreTabs.tsx b/plugins/explore/src/components/ExplorePage/ExploreTabs.tsx deleted file mode 100644 index 0415dd97ae..0000000000 --- a/plugins/explore/src/components/ExplorePage/ExploreTabs.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2021 Spotify AB - * - * 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 { TabbedLayout } from '@backstage/core'; -import React from 'react'; -import { DomainExplorerContent } from '../DomainExplorerContent'; -import { GroupsExplorerContent } from '../GroupsExplorerContent'; -import { ToolExplorerContent } from '../ToolExplorerContent'; - -export const ExploreTabs = () => ( - - - - - - - - - - - -); diff --git a/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.test.tsx b/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.test.tsx index 38c4678d5a..4e92784818 100644 --- a/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.test.tsx +++ b/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.test.tsx @@ -40,6 +40,12 @@ describe('', () => { ); + const mountedRoutes = { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }; + beforeEach(() => { jest.resetAllMocks(); @@ -69,11 +75,7 @@ describe('', () => { , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, - }, + mountedRoutes, ); await waitFor(() => { @@ -81,6 +83,19 @@ describe('', () => { }); }); + it('renders a custom title', async () => { + catalogApi.getEntities.mockResolvedValue({ items: [] }); + + const { getByText } = await renderInTestApp( + + + , + mountedRoutes, + ); + + await waitFor(() => expect(getByText('Our Teams')).toBeInTheDocument()); + }); + it('renders a friendly error if it cannot collect domains', async () => { const catalogError = new Error('Network timeout'); catalogApi.getEntities.mockRejectedValueOnce(catalogError); @@ -89,11 +104,7 @@ describe('', () => { , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, - }, + mountedRoutes, ); await waitFor(() => diff --git a/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.tsx b/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.tsx index c4d46206e4..bf2363f16c 100644 --- a/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.tsx +++ b/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.tsx @@ -13,14 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { Content, ContentHeader, SupportButton } from '@backstage/core'; import React from 'react'; import { GroupsDiagram } from './GroupsDiagram'; -export const GroupsExplorerContent = () => { +type GroupsExplorerContentProps = { + title?: string; +}; + +export const GroupsExplorerContent = ({ + title, +}: GroupsExplorerContentProps) => { return ( - + Explore your groups. diff --git a/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.test.tsx b/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.test.tsx index 125a72eb12..5cc444ace5 100644 --- a/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.test.tsx +++ b/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.test.tsx @@ -80,6 +80,18 @@ describe('', () => { }); }); + it('renders a custom title', async () => { + exploreToolsConfigApi.getTools.mockResolvedValue([]); + + const { getByText } = await renderInTestApp( + + + , + ); + + await waitFor(() => expect(getByText('Our Tools')).toBeInTheDocument()); + }); + it('renders empty state', async () => { exploreToolsConfigApi.getTools.mockResolvedValue([]); diff --git a/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.tsx b/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.tsx index e00606eeb2..8dcf1957d0 100644 --- a/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.tsx +++ b/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { Content, ContentHeader, @@ -61,9 +62,13 @@ const Body = () => { ); }; -export const ToolExplorerContent = () => ( +type ToolExplorerContentProps = { + title?: string; +}; + +export const ToolExplorerContent = ({ title }: ToolExplorerContentProps) => ( - + Discover the tools in your ecosystem. diff --git a/plugins/explore/src/components/index.ts b/plugins/explore/src/components/index.ts new file mode 100644 index 0000000000..6cbae79a71 --- /dev/null +++ b/plugins/explore/src/components/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 Spotify AB + * + * 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. + */ + +export { ExploreLayout } from './ExploreLayout'; diff --git a/plugins/explore/src/extensions.tsx b/plugins/explore/src/extensions.tsx index cdf43d3035..88ea2561fa 100644 --- a/plugins/explore/src/extensions.tsx +++ b/plugins/explore/src/extensions.tsx @@ -14,7 +14,10 @@ * limitations under the License. */ -import { createRoutableExtension } from '@backstage/core'; +import { + createComponentExtension, + createRoutableExtension, +} from '@backstage/core'; import { explorePlugin } from './plugin'; import { exploreRouteRef } from './routes'; @@ -25,3 +28,36 @@ export const ExplorePage = explorePlugin.provide( mountPoint: exploreRouteRef, }), ); + +export const DomainExplorerContent = explorePlugin.provide( + createComponentExtension({ + component: { + lazy: () => + import('./components/DomainExplorerContent').then( + m => m.DomainExplorerContent, + ), + }, + }), +); + +export const GroupsExplorerContent = explorePlugin.provide( + createComponentExtension({ + component: { + lazy: () => + import('./components/GroupsExplorerContent').then( + m => m.GroupsExplorerContent, + ), + }, + }), +); + +export const ToolExplorerContent = explorePlugin.provide( + createComponentExtension({ + component: { + lazy: () => + import('./components/ToolExplorerContent').then( + m => m.ToolExplorerContent, + ), + }, + }), +); diff --git a/plugins/explore/src/index.ts b/plugins/explore/src/index.ts index 70a00f5bbb..bee46a31ec 100644 --- a/plugins/explore/src/index.ts +++ b/plugins/explore/src/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +export { ExploreLayout } from './components'; export * from './extensions'; -export { explorePlugin } from './plugin'; +export { explorePlugin, explorePlugin as plugin } from './plugin'; export * from './routes';