diff --git a/.changeset/many-books-refuse.md b/.changeset/many-books-refuse.md
new file mode 100644
index 0000000000..8455254439
--- /dev/null
+++ b/.changeset/many-books-refuse.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog': patch
+---
+
+Add `EntityLabelsCard` to show the labels for an entity.
diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx
index 02b00f038c..447183298a 100644
--- a/packages/app/src/components/catalog/EntityPage.tsx
+++ b/packages/app/src/components/catalog/EntityPage.tsx
@@ -52,6 +52,7 @@ import {
EntityHasSystemsCard,
EntityLayout,
EntityLinksCard,
+ EntityLabelsCard,
EntityOrphanWarning,
EntityProcessingErrorsPanel,
EntitySwitch,
@@ -364,6 +365,10 @@ const overviewContent = (
+
+
+
+
{cicdCard}
diff --git a/packages/catalog-model/examples/components/shuffle-api-component.yaml b/packages/catalog-model/examples/components/shuffle-api-component.yaml
index 6328ebdf3b..afac3d472d 100644
--- a/packages/catalog-model/examples/components/shuffle-api-component.yaml
+++ b/packages/catalog-model/examples/components/shuffle-api-component.yaml
@@ -3,6 +3,9 @@ kind: Component
metadata:
name: shuffle-api
description: Shuffle API
+ labels:
+ goVersion: go1.15.3
+ category: music
tags:
- go
spec:
diff --git a/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsCard.tsx b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsCard.tsx
new file mode 100644
index 0000000000..e3bee02c43
--- /dev/null
+++ b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsCard.tsx
@@ -0,0 +1,86 @@
+/*
+ * 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 { useEntity } from '@backstage/plugin-catalog-react';
+import React from 'react';
+import {
+ InfoCard,
+ InfoCardVariants,
+ Table,
+ TableColumn,
+} from '@backstage/core-components';
+import { EntityLabelsEmptyState } from './EntityLabelsEmptyState';
+import { makeStyles, Typography } from '@material-ui/core';
+
+/** @public */
+export interface EntityLabelsCardProps {
+ variant?: InfoCardVariants;
+}
+
+const useStyles = makeStyles(_ => ({
+ key: {
+ fontWeight: 'bold',
+ },
+}));
+
+export const EntityLabelsCard = (props: EntityLabelsCardProps) => {
+ const { variant } = props;
+ const { entity } = useEntity();
+ const classes = useStyles();
+
+ const columns: TableColumn<{ key: string; value: string }>[] = [
+ {
+ render: row => {
+ return (
+
+ {row.key}
+
+ );
+ },
+ },
+ {
+ field: 'value',
+ },
+ ];
+
+ const labels = entity?.metadata?.labels;
+
+ return (
+
+ {!labels || Object.keys(labels).length === 0 ? (
+
+ ) : (
+
({
+ key: labelKey,
+ value: labels[labelKey],
+ }))}
+ options={{
+ search: false,
+ showTitle: true,
+ loadingType: 'linear',
+ header: false,
+ padding: 'dense',
+ pageSize: 5,
+ toolbar: false,
+ paging: Object.keys(labels).length > 5,
+ }}
+ />
+ )}
+
+ );
+};
diff --git a/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx
new file mode 100644
index 0000000000..9fd9f1d3d0
--- /dev/null
+++ b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2020 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 { BackstageTheme } from '@backstage/theme';
+import { Button, makeStyles, Typography } from '@material-ui/core';
+import React from 'react';
+import { CodeSnippet } from '@backstage/core-components';
+
+const ENTITY_YAML = `metadata:
+ name: example
+ labels:
+ javaVersion: 1.2.3`;
+/** @public */
+export type EntityLabelsEmptyStateClassKey = 'code';
+
+const useStyles = makeStyles(
+ theme => ({
+ code: {
+ borderRadius: 6,
+ margin: `${theme.spacing(2)}px 0px`,
+ background: theme.palette.type === 'dark' ? '#444' : '#fff',
+ },
+ }),
+ { name: 'PluginCatalogEntityLabelsEmptyState' },
+);
+
+export function EntityLabelsEmptyState() {
+ const classes = useStyles();
+
+ return (
+ <>
+
+ No labels defined for this entity. You can add links to your entity YAML
+ as shown in the highlighted example below:
+
+
+
+
+
+ >
+ );
+}
diff --git a/plugins/catalog/src/components/EntityLabelsCard/index.ts b/plugins/catalog/src/components/EntityLabelsCard/index.ts
new file mode 100644
index 0000000000..f7629a766d
--- /dev/null
+++ b/plugins/catalog/src/components/EntityLabelsCard/index.ts
@@ -0,0 +1,17 @@
+/*
+ * 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 { EntityLabelsCard } from './EntityLabelsCard';
diff --git a/plugins/catalog/src/index.ts b/plugins/catalog/src/index.ts
index 886039e329..8d32de9a06 100644
--- a/plugins/catalog/src/index.ts
+++ b/plugins/catalog/src/index.ts
@@ -50,6 +50,7 @@ export {
EntityHasSubcomponentsCard,
EntityHasSystemsCard,
EntityLinksCard,
+ EntityLabelsCard,
RelatedEntitiesCard,
} from './plugin';
diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts
index 5419854cb6..c83657b85a 100644
--- a/plugins/catalog/src/plugin.ts
+++ b/plugins/catalog/src/plugin.ts
@@ -126,6 +126,17 @@ export const EntityLinksCard = catalogPlugin.provide(
}),
);
+/** @public */
+export const EntityLabelsCard = catalogPlugin.provide(
+ createComponentExtension({
+ name: 'EntityLabelsCard',
+ component: {
+ lazy: () =>
+ import('./components/EntityLabelsCard').then(m => m.EntityLabelsCard),
+ },
+ }),
+);
+
/** @public */
export const EntityHasSystemsCard: (props: HasSystemsCardProps) => JSX.Element =
catalogPlugin.provide(