Merge pull request #15706 from RoadieHQ/entity-labels-card

add entity labels card
This commit is contained in:
Johan Haals
2023-01-13 15:08:35 +01:00
committed by GitHub
10 changed files with 246 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog': patch
---
Add `EntityLabelsCard` to show the labels for an entity.
@@ -52,6 +52,7 @@ import {
EntityHasSystemsCard,
EntityLayout,
EntityLinksCard,
EntityLabelsCard,
EntityOrphanWarning,
EntityProcessingErrorsPanel,
EntitySwitch,
@@ -59,6 +60,7 @@ import {
isComponentType,
isKind,
isOrphan,
hasLabels,
} from '@internal/plugin-catalog-customized';
import {
Direction,
@@ -364,6 +366,14 @@ const overviewContent = (
<EntityLinksCard />
</Grid>
<EntitySwitch>
<EntitySwitch.Case if={hasLabels}>
<Grid item md={4} xs={12}>
<EntityLabelsCard />
</Grid>
</EntitySwitch.Case>
</EntitySwitch>
{cicdCard}
<EntitySwitch>
@@ -3,6 +3,9 @@ kind: Component
metadata:
name: shuffle-api
description: Shuffle API
labels:
goVersion: go1.15.3
category: music
tags:
- go
spec:
+14
View File
@@ -277,6 +277,17 @@ export const EntityHasSubcomponentsCard: (
// @public (undocumented)
export const EntityHasSystemsCard: (props: HasSystemsCardProps) => JSX.Element;
// @public (undocumented)
export const EntityLabelsCard: (props: EntityLabelsCardProps) => JSX.Element;
// @public (undocumented)
export interface EntityLabelsCardProps {
// (undocumented)
title?: string;
// (undocumented)
variant?: InfoCardVariants;
}
// @public
export const EntityLayout: {
(props: EntityLayoutProps): JSX.Element;
@@ -385,6 +396,9 @@ export interface HasComponentsCardProps {
variant?: InfoCardVariants;
}
// @public
export function hasLabels(entity: Entity): boolean;
// @public (undocumented)
export interface HasResourcesCardProps {
// (undocumented)
@@ -0,0 +1,87 @@
/*
* 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;
title?: string;
}
const useStyles = makeStyles(_ => ({
key: {
fontWeight: 'bold',
},
}));
export const EntityLabelsCard = (props: EntityLabelsCardProps) => {
const { variant, title } = props;
const { entity } = useEntity();
const classes = useStyles();
const columns: TableColumn<{ key: string; value: string }>[] = [
{
render: row => {
return (
<Typography className={classes.key} variant="body2">
{row.key}
</Typography>
);
},
},
{
field: 'value',
},
];
const labels = entity?.metadata?.labels;
return (
<InfoCard title={title || 'Labels'} variant={variant}>
{!labels || Object.keys(labels).length === 0 ? (
<EntityLabelsEmptyState />
) : (
<Table
columns={columns}
data={Object.keys(labels).map(labelKey => ({
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,
}}
/>
)}
</InfoCard>
);
};
@@ -0,0 +1,66 @@
/*
* 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`;
const useStyles = makeStyles<BackstageTheme>(
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 (
<>
<Typography variant="body1">
No labels defined for this entity. You can add labels to your entity
YAML as shown in the highlighted example below:
</Typography>
<div className={classes.code}>
<CodeSnippet
text={ENTITY_YAML}
language="yaml"
showLineNumbers
highlightedNumbers={[3, 4, 5, 6]}
customStyle={{ background: 'inherit', fontSize: '115%' }}
/>
</div>
<Button
variant="contained"
color="primary"
target="_blank"
href="https://backstage.io/docs/features/software-catalog/descriptor-format#labels-optional"
>
Read more
</Button>
</>
);
}
@@ -0,0 +1,29 @@
/*
* Copyright 2023 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 { Entity } from '@backstage/catalog-model';
/**
* Returns true if the given entity has labels annotation given by the
* catalog. For use by EntitySwitch
*
* @public
*/
export function hasLabels(entity: Entity) {
return entity?.metadata?.labels
? Object.keys(entity?.metadata?.labels).some(Boolean)
: false;
}
@@ -0,0 +1,19 @@
/*
* 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';
export * from './conditions';
export type { EntityLabelsCardProps } from './EntityLabelsCard';
+2
View File
@@ -37,6 +37,7 @@ export * from './components/EntityProcessingErrorsPanel';
export * from './components/EntitySwitch';
export * from './components/FilteredEntityLayout';
export * from './overridableComponents';
export * from './components/EntityLabelsCard';
export {
CatalogEntityPage,
CatalogIndexPage,
@@ -50,6 +51,7 @@ export {
EntityHasSubcomponentsCard,
EntityHasSystemsCard,
EntityLinksCard,
EntityLabelsCard,
RelatedEntitiesCard,
} from './plugin';
+11
View File
@@ -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(