diff --git a/.changeset/old-fishes-drum.md b/.changeset/old-fishes-drum.md
new file mode 100644
index 0000000000..cb6bf6c05e
--- /dev/null
+++ b/.changeset/old-fishes-drum.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-api-docs': patch
+---
+
+Add actions props to the ApiExplorerPage
diff --git a/plugins/api-docs/api-report.md b/plugins/api-docs/api-report.md
index 74a0dc07dd..de36857945 100644
--- a/plugins/api-docs/api-report.md
+++ b/plugins/api-docs/api-report.md
@@ -5,6 +5,7 @@
```ts
///
+import { Action } from '@material-table/core';
import { ApiEntity } from '@backstage/catalog-model';
import { ApiRef } from '@backstage/core-plugin-api';
import { BackstagePlugin } from '@backstage/core-plugin-api';
@@ -58,9 +59,20 @@ export { apiDocsPlugin as plugin };
export const ApiExplorerPage: ({
initiallySelectedFilter,
columns,
+ actions,
}: {
initiallySelectedFilter?: UserListFilterKind | undefined;
columns?: TableColumn[] | undefined;
+ actions?:
+ | (
+ | Action
+ | {
+ action: (rowData: CatalogTableRow) => Action;
+ position: string;
+ }
+ | ((rowData: CatalogTableRow) => Action)
+ )[]
+ | undefined;
}) => JSX.Element;
// Warning: (ae-missing-release-tag) "ApiTypeTitle" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
diff --git a/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.test.tsx b/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.test.tsx
index 518c3c7001..d0b7523ead 100644
--- a/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.test.tsx
+++ b/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.test.tsx
@@ -15,7 +15,11 @@
*/
import { Entity, RELATION_MEMBER_OF } from '@backstage/catalog-model';
-import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react';
+import {
+ CatalogApi,
+ catalogApiRef,
+ entityRouteRef,
+} from '@backstage/plugin-catalog-react';
import { MockStorageApi, wrapInTestApp } from '@backstage/test-utils';
import { render } from '@testing-library/react';
import React from 'react';
@@ -32,6 +36,9 @@ import {
ConfigApi,
configApiRef,
} from '@backstage/core-plugin-api';
+import { TableColumn, TableProps } from '@backstage/core-components';
+import DashboardIcon from '@material-ui/icons/Dashboard';
+import { CatalogTableRow } from '@backstage/plugin-catalog';
describe('ApiCatalogPage', () => {
const catalogApi: Partial = {
@@ -46,14 +53,6 @@ describe('ApiCatalogPage', () => {
},
spec: { type: 'openapi' },
},
- {
- apiVersion: 'backstage.io/v1alpha1',
- kind: 'API',
- metadata: {
- name: 'Entity2',
- },
- spec: { type: 'openapi' },
- },
] as Entity[],
}),
getLocationByEntity: () =>
@@ -96,6 +95,11 @@ describe('ApiCatalogPage', () => {
>
{children}
,
+ {
+ mountedRoutes: {
+ '/catalog/:namespace/:kind/:name': entityRouteRef,
+ },
+ },
),
);
@@ -106,4 +110,82 @@ describe('ApiCatalogPage', () => {
const { findByText } = renderWrapped();
expect(await findByText(/My Company API Explorer/)).toBeInTheDocument();
});
+
+ it('should render the default column of the grid', async () => {
+ const { getAllByRole } = renderWrapped();
+
+ const columnHeader = getAllByRole('button').filter(
+ c => c.tagName === 'SPAN',
+ );
+ const columnHeaderLabels = columnHeader.map(c => c.textContent);
+
+ expect(columnHeaderLabels).toEqual([
+ 'Name',
+ 'System',
+ 'Owner',
+ 'Type',
+ 'Lifecycle',
+ 'Description',
+ 'Tags',
+ 'Actions',
+ ]);
+ });
+
+ it('should render the custom column passed as prop', async () => {
+ const columns: TableColumn[] = [
+ { title: 'Foo', field: 'entity.foo' },
+ { title: 'Bar', field: 'entity.bar' },
+ { title: 'Baz', field: 'entity.spec.lifecycle' },
+ ];
+ const { getAllByRole } = renderWrapped(
+ ,
+ );
+
+ const columnHeader = getAllByRole('button').filter(
+ c => c.tagName === 'SPAN',
+ );
+ const columnHeaderLabels = columnHeader.map(c => c.textContent);
+
+ expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']);
+ });
+
+ it('should render the default actions of an item in the grid', async () => {
+ const { findByTitle, findByText } = await renderWrapped(
+ ,
+ );
+ expect(await findByText(/All \(1\)/)).toBeInTheDocument();
+ expect(await findByTitle(/View/)).toBeInTheDocument();
+ expect(await findByTitle(/View/)).toBeInTheDocument();
+ expect(await findByTitle(/Edit/)).toBeInTheDocument();
+ expect(await findByTitle(/Add to favorites/)).toBeInTheDocument();
+ });
+
+ it('should render the custom actions of an item passed as prop', async () => {
+ const actions: TableProps['actions'] = [
+ () => {
+ return {
+ icon: () => ,
+ tooltip: 'Foo Action',
+ disabled: false,
+ onClick: () => jest.fn(),
+ };
+ },
+ () => {
+ return {
+ icon: () => ,
+ tooltip: 'Bar Action',
+ disabled: true,
+ onClick: () => jest.fn(),
+ };
+ },
+ ];
+
+ const { findByTitle, findByText } = await renderWrapped(
+ ,
+ );
+ expect(await findByText(/All \(1\)/)).toBeInTheDocument();
+ expect(await findByTitle(/Foo Action/)).toBeInTheDocument();
+ expect(await findByTitle(/Bar Action/)).toBeInTheDocument();
+ expect((await findByTitle(/Bar Action/)).firstChild).toBeDisabled();
+ });
});
diff --git a/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.tsx b/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.tsx
index 2f74aaa166..f28574145e 100644
--- a/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.tsx
+++ b/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.tsx
@@ -21,6 +21,7 @@ import {
PageWithHeader,
SupportButton,
TableColumn,
+ TableProps,
} from '@backstage/core-components';
import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';
import {
@@ -56,11 +57,13 @@ const defaultColumns: TableColumn[] = [
type ApiExplorerPageProps = {
initiallySelectedFilter?: UserListFilterKind;
columns?: TableColumn[];
+ actions?: TableProps['actions'];
};
export const ApiExplorerPage = ({
initiallySelectedFilter = 'all',
columns,
+ actions,
}: ApiExplorerPageProps) => {
const configApi = useApi(configApiRef);
const generatedSubtitle = `${
@@ -94,7 +97,10 @@ export const ApiExplorerPage = ({
-
+