diff --git a/plugins/api-docs/src/components/CatalogApiPluginPage/CatalogApiPluginPage.test.tsx b/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogLayout.tsx
similarity index 51%
rename from plugins/api-docs/src/components/CatalogApiPluginPage/CatalogApiPluginPage.test.tsx
rename to plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogLayout.tsx
index 4bb39b6e8c..d846e2b0e2 100644
--- a/plugins/api-docs/src/components/CatalogApiPluginPage/CatalogApiPluginPage.test.tsx
+++ b/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogLayout.tsx
@@ -14,21 +14,24 @@
* limitations under the License.
*/
-import { lightTheme } from '@backstage/theme';
-import { ThemeProvider } from '@material-ui/core';
-import { render } from '@testing-library/react';
-import mockFetch from 'jest-fetch-mock';
+import { Header, Page, pageTheme } from '@backstage/core';
import React from 'react';
-import CatalogApiPluginPage from './CatalogApiPluginPage';
-describe('CatalogApiPluginPage', () => {
- it('should render', () => {
- mockFetch.mockResponse(() => new Promise(() => {}));
- const rendered = render(
-
-
- ,
- );
- expect(rendered.getByText('Welcome to catalog-api!')).toBeInTheDocument();
- });
-});
+type Props = {
+ children?: React.ReactNode;
+};
+
+const ApiCatalogLayout = ({ children }: Props) => {
+ return (
+
+
+ {children}
+
+ );
+};
+
+export default ApiCatalogLayout;
diff --git a/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.test.tsx b/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.test.tsx
new file mode 100644
index 0000000000..19cbaf6038
--- /dev/null
+++ b/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.test.tsx
@@ -0,0 +1,70 @@
+/*
+ * 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 { Entity } from '@backstage/catalog-model';
+import { ApiProvider, ApiRegistry, storageApiRef } from '@backstage/core';
+// TODO: Circular ref!
+import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog';
+import { MockStorageApi, wrapInTestApp } from '@backstage/test-utils';
+import { render } from '@testing-library/react';
+import React from 'react';
+import { ApiCatalogPage } from './ApiCatalogPage';
+
+describe('ApiCatalogPage', () => {
+ const catalogApi: Partial = {
+ getEntities: () =>
+ Promise.resolve([
+ {
+ apiVersion: 'backstage.io/v1alpha1',
+ kind: 'API',
+ metadata: {
+ name: 'Entity1',
+ },
+ },
+ {
+ apiVersion: 'backstage.io/v1alpha1',
+ kind: 'API',
+ metadata: {
+ name: 'Entity2',
+ },
+ },
+ ] as Entity[]),
+ getLocationByEntity: () =>
+ Promise.resolve({ id: 'id', type: 'github', target: 'url' }),
+ };
+
+ const renderWrapped = (children: React.ReactNode) =>
+ render(
+ wrapInTestApp(
+
+ {children}
+ ,
+ ),
+ );
+
+ // this test right now causes some red lines in the log output when running tests
+ // related to some theme issues in mui-table
+ // https://github.com/mbrn/material-table/issues/1293
+ it('should render', async () => {
+ const { findByText } = renderWrapped();
+ expect(await findByText(/APIs \(2\)/)).toBeInTheDocument();
+ });
+});
diff --git a/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.tsx b/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.tsx
new file mode 100644
index 0000000000..f624ec9f92
--- /dev/null
+++ b/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.tsx
@@ -0,0 +1,45 @@
+/*
+ * 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 { Content, useApi } from '@backstage/core';
+// TODO: Circular ref
+import { catalogApiRef } from '@backstage/plugin-catalog';
+import React from 'react';
+import { useAsync } from 'react-use';
+import { ApiCatalogTable } from '../ApiCatalogTable/ApiCatalogTable';
+import ApiCatalogLayout from './ApiCatalogLayout';
+
+const CatalogPageContents = () => {
+ const catalogApi = useApi(catalogApiRef);
+ const { loading, error, value: matchingEntities } = useAsync(() => {
+ return catalogApi.getEntities({ kind: 'API' });
+ }, [catalogApi]);
+
+ return (
+
+
+
+
+
+ );
+};
+
+export const ApiCatalogPage = () => ;
diff --git a/plugins/api-docs/src/components/ApiCatalogTable/ApiCatalogTable.test.tsx b/plugins/api-docs/src/components/ApiCatalogTable/ApiCatalogTable.test.tsx
new file mode 100644
index 0000000000..67f6562a56
--- /dev/null
+++ b/plugins/api-docs/src/components/ApiCatalogTable/ApiCatalogTable.test.tsx
@@ -0,0 +1,74 @@
+/*
+ * 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 { Entity } from '@backstage/catalog-model';
+import { wrapInTestApp } from '@backstage/test-utils';
+import { render } from '@testing-library/react';
+import * as React from 'react';
+import { ApiCatalogTable } from './ApiCatalogTable';
+
+const entites: Entity[] = [
+ {
+ apiVersion: 'backstage.io/v1alpha1',
+ kind: 'API',
+ metadata: { name: 'api1' },
+ },
+ {
+ apiVersion: 'backstage.io/v1alpha1',
+ kind: 'API',
+ metadata: { name: 'api2' },
+ },
+ {
+ apiVersion: 'backstage.io/v1alpha1',
+ kind: 'API',
+ metadata: { name: 'api3' },
+ },
+];
+
+describe('ApiCatalogTable component', () => {
+ it('should render error message when error is passed in props', async () => {
+ const rendered = render(
+ wrapInTestApp(
+ ,
+ ),
+ );
+ const errorMessage = await rendered.findByText(
+ /Error encountered while fetching catalog entities./,
+ );
+ expect(errorMessage).toBeInTheDocument();
+ });
+
+ it('should display entity names when loading has finished and no error occurred', async () => {
+ const rendered = render(
+ wrapInTestApp(
+ ,
+ ),
+ );
+ expect(rendered.getByText(/APIs \(3\)/)).toBeInTheDocument();
+ expect(rendered.getByText(/api1/)).toBeInTheDocument();
+ expect(rendered.getByText(/api2/)).toBeInTheDocument();
+ expect(rendered.getByText(/api3/)).toBeInTheDocument();
+ });
+});
diff --git a/plugins/api-docs/src/components/ApiCatalogTable/ApiCatalogTable.tsx b/plugins/api-docs/src/components/ApiCatalogTable/ApiCatalogTable.tsx
new file mode 100644
index 0000000000..e30583caed
--- /dev/null
+++ b/plugins/api-docs/src/components/ApiCatalogTable/ApiCatalogTable.tsx
@@ -0,0 +1,89 @@
+/*
+ * 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 { Entity } from '@backstage/catalog-model';
+import { Table, TableColumn } from '@backstage/core';
+import { Link } from '@material-ui/core';
+import { Alert } from '@material-ui/lab';
+import React from 'react';
+import { generatePath, Link as RouterLink } from 'react-router-dom';
+import { entityRoute } from '../../routes';
+
+const columns: TableColumn[] = [
+ {
+ title: 'Name',
+ field: 'metadata.name',
+ highlight: true,
+ render: (entity: any) => (
+
+ {entity.metadata.name}
+
+ ),
+ },
+ {
+ title: 'Description',
+ field: 'metadata.description',
+ },
+];
+
+type CatalogTableProps = {
+ entities: Entity[];
+ titlePreamble: string;
+ loading: boolean;
+ error?: any;
+};
+
+export const ApiCatalogTable = ({
+ entities,
+ loading,
+ error,
+ titlePreamble,
+}: CatalogTableProps) => {
+ if (error) {
+ return (
+