diff --git a/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/EmailCardAction.tsx b/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/EmailCardAction.tsx
new file mode 100644
index 0000000000..ed9ac7b9aa
--- /dev/null
+++ b/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/EmailCardAction.tsx
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 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 { Button, Tooltip } from '@material-ui/core';
+import EmailIcon from '@material-ui/icons/Email';
+import React from 'react';
+
+/**
+ * Email Card action link
+ *
+ * @private
+ */
+export const EmailCardAction = ({ email }: { email: string }) => {
+ return (
+
+
+
+ );
+};
diff --git a/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/EntityCardActions.tsx b/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/EntityCardActions.tsx
new file mode 100644
index 0000000000..d021a9f69d
--- /dev/null
+++ b/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/EntityCardActions.tsx
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2022 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 { entityRouteRef } from '../../../routes';
+import { Tooltip } from '@material-ui/core';
+import InfoIcon from '@material-ui/icons/Info';
+import React from 'react';
+import { useRouteRef } from '@backstage/core-plugin-api';
+import { Entity } from '@backstage/catalog-model';
+import { Link } from '@backstage/core-components';
+
+/**
+ * Card actions that show for all entities
+ *
+ * @private
+ */
+export const EntityCardActions = ({ entity }: { entity: Entity }) => {
+ const entityRoute = useRouteRef(entityRouteRef);
+
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+};
diff --git a/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/GroupCardActions.tsx b/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/GroupCardActions.tsx
new file mode 100644
index 0000000000..fca0763703
--- /dev/null
+++ b/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/GroupCardActions.tsx
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 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 { EmailCardAction } from './EmailCardAction';
+import React from 'react';
+import { GroupEntity } from '@backstage/catalog-model';
+
+/**
+ * Card actions that show for a group
+ *
+ * @private
+ */
+export const GroupCardActions = ({ entity }: { entity: GroupEntity }) => {
+ return (
+ <>
+ {entity.spec.profile?.email && (
+
+ )}
+ >
+ );
+};
diff --git a/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/UserCardActions.tsx b/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/UserCardActions.tsx
new file mode 100644
index 0000000000..57801497f6
--- /dev/null
+++ b/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/UserCardActions.tsx
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 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 { EmailCardAction } from './EmailCardAction';
+import React from 'react';
+import { UserEntity } from '@backstage/catalog-model';
+
+/**
+ * Card actions that show for a user
+ *
+ * @private
+ */
+export const UserCardActions = ({ entity }: { entity: UserEntity }) => {
+ return (
+ <>
+ {entity.spec.profile?.email && (
+
+ )}
+ >
+ );
+};
diff --git a/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/index.ts b/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/index.ts
new file mode 100644
index 0000000000..75959026f7
--- /dev/null
+++ b/plugins/catalog-react/src/components/EntityPeekAheadPopover/CardActionComponents/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2022 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.
+ */
+export { EntityCardActions } from './EntityCardActions';
+export { GroupCardActions } from './GroupCardActions';
+export { UserCardActions } from './UserCardActions';
diff --git a/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityNotFoundCard.tsx b/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityNotFoundCard.tsx
new file mode 100644
index 0000000000..08d92cab22
--- /dev/null
+++ b/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityNotFoundCard.tsx
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 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 { Card, CardContent } from '@material-ui/core';
+import { Alert } from '@material-ui/lab';
+import React from 'react';
+
+/**
+ * Entity not found card
+ *
+ * @private
+ */
+export const EntityNotFoundCard = ({
+ entityRef,
+ error,
+}: {
+ entityRef: string;
+ error?: Error;
+}) => {
+ return (
+
+
+
+ {entityRef} was not found {error?.message}
+
+
+
+ );
+};
diff --git a/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.tsx b/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.tsx
index 6e5b75ed58..c6cba8d421 100644
--- a/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.tsx
+++ b/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.tsx
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { entityRouteRef } from '../../routes';
import useAsyncFn from 'react-use/lib/useAsyncFn';
import { catalogApiRef } from '../../api';
import React, { PropsWithChildren, useEffect } from 'react';
@@ -25,7 +24,6 @@ import {
} from 'material-ui-popup-state/hooks';
import {
Box,
- Button,
Card,
CardActions,
CardContent,
@@ -34,19 +32,19 @@ import {
Tooltip,
Typography,
} from '@material-ui/core';
-import { Alert } from '@material-ui/lab';
-import EmailIcon from '@material-ui/icons/Email';
-import InfoIcon from '@material-ui/icons/Info';
-import { useApiHolder, useRouteRef } from '@backstage/core-plugin-api';
+import { useApiHolder } from '@backstage/core-plugin-api';
import {
- isUserEntity,
isGroupEntity,
- UserEntity,
- GroupEntity,
- Entity,
+ isUserEntity,
parseEntityRef,
} from '@backstage/catalog-model';
-import { Link, Progress } from '@backstage/core-components';
+import { Progress } from '@backstage/core-components';
+import {
+ EntityCardActions,
+ UserCardActions,
+ GroupCardActions,
+} from './CardActionComponents';
+import { EntityNotFoundCard } from './EntityNotFoundCard';
/**
* Properties for an entity popover on hover of a component.
@@ -77,80 +75,6 @@ const useStyles = makeStyles(() => {
const maxTagChips = 4;
-const EmailCardAction = ({ email }: { email: string }) => {
- return (
-
-
-
- );
-};
-
-const UserCardActions = ({ entity }: { entity: UserEntity }) => {
- return (
- <>
- {entity.spec.profile?.email && (
-
- )}
- >
- );
-};
-
-const GroupCardActions = ({ entity }: { entity: GroupEntity }) => {
- return (
- <>
- {entity.spec.profile?.email && (
-
- )}
- >
- );
-};
-
-/**
- * Shows an entity popover on hover of a component.
- *
- * @public
- */
-const EntityCardActions = ({ entity }: { entity: Entity }) => {
- const entityRoute = useRouteRef(entityRouteRef);
-
- return (
- <>
-
-
-
-
-
- >
- );
-};
-
-const EntityNotFoundCard = ({
- entityRef,
- error,
-}: {
- entityRef: string;
- error?: Error;
-}) => {
- return (
-
-
-
- {entityRef} was not found {error?.message}
-
-
-
- );
-};
-
/**
* Shows an entity popover on hover of a component.
*
diff --git a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.stories.tsx b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.stories.tsx
index e09bf89382..e82c4ab963 100644
--- a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.stories.tsx
+++ b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.stories.tsx
@@ -16,64 +16,8 @@
import React, { ComponentType } from 'react';
import { EntityRefLink, EntityRefLinkProps } from './EntityRefLink';
-import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils';
-import { catalogApiRef } from '../../api';
-import { CompoundEntityRef } from '@backstage/catalog-model';
+import { wrapInTestApp } from '@backstage/test-utils';
import { entityRouteRef } from '../../routes';
-import { CatalogApi } from '@backstage/catalog-client';
-
-const mockCatalogApi = {
- getEntityByRef: async (entityRef: CompoundEntityRef) => {
- if (
- entityRef.namespace === 'default' &&
- entityRef.name === 'playback' &&
- entityRef.kind === 'component'
- ) {
- return {
- kind: 'Component',
- metadata: {
- name: 'playback',
- namespace: 'default',
- description: 'Details about the playback service',
- },
- };
- }
- if (
- entityRef.namespace === 'default' &&
- entityRef.name === 'fname.lname' &&
- entityRef.kind === 'user'
- ) {
- return {
- kind: 'User',
- metadata: {
- name: 'fname.lname',
- namespace: 'default',
- },
- spec: {
- profile: {
- email: 'fname.lname@example.com',
- },
- },
- };
- }
- if (
- entityRef.namespace === 'default' &&
- entityRef.name === 'slow.catalog.item' &&
- entityRef.kind === 'component'
- ) {
- await new Promise(resolve => setTimeout(resolve, 3000));
- return {
- kind: 'Component',
- metadata: {
- name: 'slow.catalog.item',
- namespace: 'default',
- description: 'Details about the slow.catalog.item service',
- },
- };
- }
- return undefined;
- },
-};
const defaultArgs = {
entityRef: 'component:default/playback',
@@ -83,20 +27,11 @@ export default {
title: 'Catalog /EntityRefLink',
decorators: [
(Story: ComponentType<{}>) =>
- wrapInTestApp(
- <>
-
-
-
- >,
- {
- mountedRoutes: {
- '/catalog/:namespace/:kind/:name': entityRouteRef,
- },
+ wrapInTestApp(, {
+ mountedRoutes: {
+ '/catalog/:namespace/:kind/:name': entityRouteRef,
},
- ),
+ }),
],
};
@@ -104,22 +39,3 @@ export const Default = (args: EntityRefLinkProps) => (
);
Default.args = defaultArgs;
-
-export const User = (args: EntityRefLinkProps) => ;
-User.args = {
- entityRef: 'user:default/fname.lname',
-};
-
-export const NotFound = (args: EntityRefLinkProps) => (
-
-);
-NotFound.args = {
- entityRef: 'user:default/doesnt.exist',
-};
-
-export const SlowCatalogItem = (args: EntityRefLinkProps) => (
-
-);
-SlowCatalogItem.args = {
- entityRef: 'component:default/slow.catalog.item',
-};
diff --git a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx
index de94866bb6..06a632232e 100644
--- a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx
+++ b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx
@@ -25,7 +25,8 @@ import { entityRouteRef } from '../../routes';
import { humanizeEntityRef } from './humanize';
import { Link, LinkProps } from '@backstage/core-components';
import { useRouteRef } from '@backstage/core-plugin-api';
-import { EntityPeekAheadPopover } from '../EntityPeekAheadPopover';
+import { Tooltip } from '@material-ui/core';
+
/**
* Props for {@link EntityRefLink}.
*
@@ -76,13 +77,17 @@ export const EntityRefLink = forwardRef(
{ defaultKind },
);
- return (
-
-
- {children}
- {!children && (title ?? formattedEntityRefTitle)}
-
-
+ const link = (
+
+ {children}
+ {!children && (title ?? formattedEntityRefTitle)}
+
+ );
+
+ return title ? (
+ {link}
+ ) : (
+ link
);
},
) as (props: EntityRefLinkProps) => JSX.Element;
diff --git a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLinks.stories.tsx b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLinks.stories.tsx
new file mode 100644
index 0000000000..176dd24530
--- /dev/null
+++ b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLinks.stories.tsx
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 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, { ComponentType } from 'react';
+import { EntityRefLinks, EntityRefLinksProps } from './EntityRefLinks';
+import { wrapInTestApp } from '@backstage/test-utils';
+import { CompoundEntityRef } from '@backstage/catalog-model';
+import { entityRouteRef } from '../../routes';
+
+const defaultArgs = {
+ entityRefs: ['component:default/playback', 'user:default/fname.lname'],
+};
+
+export default {
+ title: 'Catalog /EntityRefLinks',
+ decorators: [
+ (Story: ComponentType<{}>) =>
+ wrapInTestApp(, {
+ mountedRoutes: {
+ '/catalog/:namespace/:kind/:name': entityRouteRef,
+ },
+ }),
+ ],
+};
+
+export const Default = (
+ args: EntityRefLinksProps,
+) => ;
+Default.args = defaultArgs;