이것이 기존의 Catalog Graph 인데, 모든 Kind가 같은 색상으로 아이콘으로 구분되다 보니 가시성이 떨어진다.

Custom UI 를 사용하여 가시성을 향상시킬수 있다. 설명은 공식적으로 여기에 소개되어 있다.
backstage/plugins/catalog-graph/README.md at master · backstage/backstage
Backstage is an open framework for building developer portals - backstage/backstage
github.com
수정사항은 다음과 같다.
우선 CustomUI Rendering Component를 정의한다.
packages/app/src/components/catalog/CustomRenderNode.tsx
import React, { useLayoutEffect, useRef, useState } from 'react';
import { DependencyGraphTypes } from '@backstage/core-components';
import { makeStyles } from '@material-ui/core/styles';
import classNames from 'classnames';
const useStyles = makeStyles(_theme => ({
node: {
stroke: '#000',
strokeWidth: 2,
'&.focused': {
strokeWidth: 3,
},
'&.clickable': {
cursor: 'pointer',
},
// Entity Kind specific styles
'&.system': {
fill: '#F5DC70',
stroke: '#F2CE34',
},
'&.domain': {
fill: '#F5DC70',
stroke: '#F2CE34',
},
'&.component': {
fill: '#85E1FF',
stroke: '#2196F3',
},
'&.service': {
fill: '#85E1FF',
stroke: '#2196F3',
},
'&.api': {
fill: '#98FB98',
stroke: '#4CAF50',
},
'&.group': {
fill: '#FFB366',
stroke: '#FF9800',
},
'&.user': {
fill: '#E1BEE7',
stroke: '#9C27B0',
},
'&.resource': {
fill: '#FFCCBC',
stroke: '#FF6E40',
},
'&.template': {
fill: '#B2DFDB',
stroke: '#009688',
},
'&.unknown': {
fill: '#BDBDBD',
stroke: '#757575',
},
},
text: {
fontSize: 12,
fontFamily: 'Arial, sans-serif',
fill: '#000',
pointerEvents: 'none',
'&.focused': {
fontWeight: 'bold',
},
},
clickable: {
cursor: 'pointer',
},
}));
export const CustomRenderNode = (
props: DependencyGraphTypes.RenderNodeProps<any>,
) => {
const classes = useStyles();
const { node } = props;
const { id } = node;
const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);
const idRef = useRef<SVGTextElement | null>(null);
useLayoutEffect(() => {
// set the width to the length of the ID
if (idRef.current) {
let { height: renderedHeight, width: renderedWidth } =
idRef.current.getBBox();
renderedHeight = Math.round(renderedHeight);
renderedWidth = Math.round(renderedWidth);
if (renderedHeight !== height || renderedWidth !== width) {
setWidth(renderedWidth);
setHeight(renderedHeight);
}
}
}, [width, height]);
const padding = 10;
const paddedWidth = width + padding * 2;
const paddedHeight = height + padding * 2;
// Extract kind from node ID (format: "kind:namespace/name")
const kind = id.split(':')[0]?.toLowerCase();
return (
<g
onClick={node.onClick}
className={classNames(node.onClick && classes.clickable)}
>
<rect
className={classNames(
classes.node,
kind,
node.focused && 'focused',
)}
width={paddedWidth}
height={paddedHeight}
rx={4}
ry={4}
/>
<text
ref={idRef}
className={classNames(classes.text, node.focused && 'focused')}
y={paddedHeight / 2}
x={paddedWidth / 2}
textAnchor="middle"
alignmentBaseline="middle"
>
{id}
</text>
</g>
);
};
그리고 정의한 Component를 필요한 곳에. import한다. 그리고 이렇게 사용한다.
우선 "/catalog-graph" route를 정의한 곳에 적용해보자
packages/app/src/App.tsx
import { CustomRenderNode } from './components/catalog/CustomRenderNode';
...
<Route path="/catalog-graph" element={<CatalogGraphPage renderNode={CustomRenderNode} />} />
...
그리고 EntityPage에도 적용한다.
packages/app/src/components/catalog/EntityPage.tsx
import { CustomRenderNode } from './CustomRenderNode';
...
const overviewContent = (
<Grid container spacing={3} alignItems="stretch">
...
<Grid item md={6} xs={12}>
<EntityCatalogGraphCard variant="gridItem" renderNode={CustomRenderNode} height={400} />
</Grid>
...
</Grid>
);
...
const systemPage = (
<EntityLayout>
<EntityLayout.Route path="/diagram" title="Diagram">
<EntityCatalogGraphCard
variant="gridItem"
renderNode={CustomRenderNode}
direction={Direction.TOP_BOTTOM}
title="System Diagram"
height={700}
relations={[
RELATION_PART_OF,
RELATION_HAS_PART,
RELATION_API_CONSUMED_BY,
RELATION_API_PROVIDED_BY,
RELATION_CONSUMES_API,
RELATION_PROVIDES_API,
RELATION_DEPENDENCY_OF,
RELATION_DEPENDS_ON,
]}
unidirectional={false}
/>
</EntityLayout.Route>
</EntityLayout>
);
...
Full SourceCode는 여기서 확인할 수 있다.
https://github.com/armyost/backstage-armyost
GitHub - armyost/backstage-armyost
Contribute to armyost/backstage-armyost development by creating an account on GitHub.
github.com
이렇게 CustomUI가 씌워졌다.

'Programming > MSA' 카테고리의 다른 글
| Backstage) Custom Relation, Custom Entity 적용하기 (0) | 2026.02.10 |
|---|---|
| Backstage) Install 4. TechDocs 에서 PlantUML Plugin 사용하기 (0) | 2025.12.01 |
| Backstage) Install 3. Theme 바꾸기 (1) | 2025.11.17 |
| Backstage) Install 2. Github App 설치 (0) | 2025.11.16 |
| Backstage) Install 1. Github App 설치 (0) | 2025.11.10 |