feat: use entityPresentationApi for the node title and the icon
Signed-off-by: David Weber <david.weber@w3tec.ch> Signed-off-by: David Weber <david.weber.schenker@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-graph': patch
|
||||
---
|
||||
|
||||
Use `entityPresentationApi` for the node title and the icon.
|
||||
+5
-3
@@ -47,6 +47,7 @@ describe('<CustomNode />', () => {
|
||||
);
|
||||
|
||||
expect(screen.getByText('kind:namespace/name')).toBeInTheDocument();
|
||||
expect(screen.getByText('namespace/name')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('renders node, skips default namespace', async () => {
|
||||
@@ -73,7 +74,7 @@ describe('<CustomNode />', () => {
|
||||
</svg>,
|
||||
);
|
||||
|
||||
expect(screen.getByText('kind:name')).toBeInTheDocument();
|
||||
expect(screen.getByText('name')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('renders node with onClick', async () => {
|
||||
@@ -102,8 +103,8 @@ describe('<CustomNode />', () => {
|
||||
</svg>,
|
||||
);
|
||||
|
||||
expect(screen.getByText('kind:namespace/name')).toBeInTheDocument();
|
||||
await userEvent.click(screen.getByText('kind:namespace/name'));
|
||||
expect(screen.getByText('namespace/name')).toBeInTheDocument();
|
||||
await userEvent.click(screen.getByText('namespace/name'));
|
||||
expect(onClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@@ -134,5 +135,6 @@ describe('<CustomNode />', () => {
|
||||
);
|
||||
|
||||
expect(screen.getByText('Custom Title')).toBeInTheDocument();
|
||||
expect(screen.getByText('kind:namespace/name')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { DependencyGraphTypes } from '@backstage/core-components';
|
||||
import { useApp } from '@backstage/core-plugin-api';
|
||||
import { humanizeEntityRef } from '@backstage/plugin-catalog-react';
|
||||
import { IconComponent } from '@backstage/core-plugin-api';
|
||||
import { useEntityPresentation } from '@backstage/plugin-catalog-react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import classNames from 'classnames';
|
||||
import React, { useLayoutEffect, useRef, useState } from 'react';
|
||||
import { EntityKindIcon } from './EntityKindIcon';
|
||||
import { EntityIcon } from './EntityIcon';
|
||||
import { EntityNodeData } from './types';
|
||||
import { DEFAULT_NAMESPACE } from '@backstage/catalog-model';
|
||||
|
||||
@@ -64,8 +64,10 @@ export function DefaultRenderNode({
|
||||
const classes = useStyles();
|
||||
const [width, setWidth] = useState(0);
|
||||
const [height, setHeight] = useState(0);
|
||||
const app = useApp();
|
||||
const idRef = useRef<SVGTextElement | null>(null);
|
||||
const entityRefPresentationSnapshot = useEntityPresentation(entity, {
|
||||
defaultNamespace: DEFAULT_NAMESPACE,
|
||||
});
|
||||
|
||||
useLayoutEffect(() => {
|
||||
// set the width to the length of the ID
|
||||
@@ -82,25 +84,14 @@ export function DefaultRenderNode({
|
||||
}
|
||||
}, [width, height]);
|
||||
|
||||
const {
|
||||
kind,
|
||||
metadata: { name, namespace = DEFAULT_NAMESPACE, title },
|
||||
} = entity;
|
||||
|
||||
const hasKindIcon = app.getSystemIcon(
|
||||
`kind:${kind.toLocaleLowerCase('en-US')}`,
|
||||
);
|
||||
const hasKindIcon = !!entityRefPresentationSnapshot.Icon;
|
||||
const padding = 10;
|
||||
const iconSize = height;
|
||||
const paddedIconWidth = hasKindIcon ? iconSize + padding : 0;
|
||||
const paddedWidth = paddedIconWidth + width + padding * 2;
|
||||
const paddedHeight = height + padding * 2;
|
||||
|
||||
const displayTitle =
|
||||
title ??
|
||||
(kind && name && namespace
|
||||
? humanizeEntityRef({ kind, name, namespace })
|
||||
: id);
|
||||
const displayTitle = entityRefPresentationSnapshot.primaryTitle ?? id;
|
||||
|
||||
return (
|
||||
<g onClick={onClick} className={classNames(onClick && classes.clickable)}>
|
||||
@@ -115,8 +106,8 @@ export function DefaultRenderNode({
|
||||
rx={10}
|
||||
/>
|
||||
{hasKindIcon && (
|
||||
<EntityKindIcon
|
||||
kind={kind}
|
||||
<EntityIcon
|
||||
icon={entityRefPresentationSnapshot.Icon as IconComponent}
|
||||
y={padding}
|
||||
x={padding}
|
||||
width={iconSize}
|
||||
@@ -144,6 +135,7 @@ export function DefaultRenderNode({
|
||||
>
|
||||
{displayTitle}
|
||||
</text>
|
||||
<title>{entityRefPresentationSnapshot.entityRef}</title>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
|
||||
+5
-3
@@ -16,12 +16,14 @@
|
||||
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import React from 'react';
|
||||
import { EntityKindIcon } from './EntityKindIcon';
|
||||
import { EntityIcon } from './EntityIcon';
|
||||
import MuiMemoryIcon from '@material-ui/icons/Memory';
|
||||
import { IconComponent } from '@backstage/core-plugin-api';
|
||||
|
||||
describe('<EntityKindIcon />', () => {
|
||||
it('renders without exploding', async () => {
|
||||
const { baseElement } = await renderInTestApp(
|
||||
<EntityKindIcon kind="Component" />,
|
||||
<EntityIcon icon={MuiMemoryIcon as IconComponent} />,
|
||||
);
|
||||
|
||||
expect(baseElement.querySelector('svg')).toBeInTheDocument();
|
||||
@@ -29,7 +31,7 @@ describe('<EntityKindIcon />', () => {
|
||||
|
||||
it('renders without exploding for unknown kind', async () => {
|
||||
const { baseElement } = await renderInTestApp(
|
||||
<EntityKindIcon kind="unknown" />,
|
||||
<EntityIcon icon={undefined} />,
|
||||
);
|
||||
|
||||
expect(baseElement.querySelector('svg')).toBeInTheDocument();
|
||||
+7
-7
@@ -13,23 +13,23 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { useApp } from '@backstage/core-plugin-api';
|
||||
import React from 'react';
|
||||
import SvgIcon from '@material-ui/core/SvgIcon';
|
||||
import { OverridableComponent } from '@material-ui/core/OverridableComponent';
|
||||
import { SvgIconTypeMap } from '@material-ui/core/SvgIcon/SvgIcon';
|
||||
import { IconComponent } from '@backstage/core-plugin-api';
|
||||
|
||||
export function EntityKindIcon({
|
||||
kind,
|
||||
export function EntityIcon({
|
||||
icon,
|
||||
...props
|
||||
}: {
|
||||
kind: string;
|
||||
icon: IconComponent | undefined;
|
||||
x?: number;
|
||||
y?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
className?: string;
|
||||
}) {
|
||||
const app = useApp();
|
||||
const Icon =
|
||||
app.getSystemIcon(`kind:${kind.toLocaleLowerCase('en-US')}`) ?? SvgIcon;
|
||||
const Icon = (icon as OverridableComponent<SvgIconTypeMap>) ?? SvgIcon;
|
||||
return <Icon {...props} />;
|
||||
}
|
||||
Reference in New Issue
Block a user