diff --git a/.changeset/tame-jokes-bow.md b/.changeset/tame-jokes-bow.md new file mode 100644 index 0000000000..e08cf9ca0c --- /dev/null +++ b/.changeset/tame-jokes-bow.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-graph': patch +--- + +Allow multiple edges with different type (e.g. `ownedBy` and `applicationOwnerBy`) to have the same source and target node. diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/DefaultRenderLabel.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/DefaultRenderLabel.tsx index cde4808f6e..ae01a113dd 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/DefaultRenderLabel.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/DefaultRenderLabel.tsx @@ -38,7 +38,7 @@ export function DefaultRenderLabel({ return ( {relations.map((r, i) => ( - 0 && classes.secondary)}> + {i > 0 && / } {r} diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.test.ts b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.test.ts index 8c7b59b9c4..0a5e43bf37 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.test.ts +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.test.ts @@ -371,12 +371,6 @@ describe('useEntityRelationNodesAndEdges', () => { relations: [RELATION_HAS_PART, RELATION_PART_OF], to: 'b:d/c1', }, - { - from: 'b:d/c', - label: 'visible', - relations: [RELATION_HAS_PART, RELATION_PART_OF], - to: 'b:d/c1', - }, { from: 'b:d/c1', label: 'visible', @@ -389,24 +383,6 @@ describe('useEntityRelationNodesAndEdges', () => { relations: [RELATION_HAS_PART, RELATION_PART_OF], to: 'b:d/c2', }, - { - from: 'b:d/c1', - label: 'visible', - relations: [RELATION_HAS_PART, RELATION_PART_OF], - to: 'b:d/c2', - }, - { - from: 'b:d/c', - label: 'visible', - relations: [RELATION_OWNER_OF, RELATION_OWNED_BY], - to: 'k:d/a1', - }, - { - from: 'b:d/c1', - label: 'visible', - relations: [RELATION_OWNER_OF, RELATION_OWNED_BY], - to: 'k:d/a1', - }, ]); }); diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.ts b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.ts index d2a5138ccb..74aff1b3d0 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.ts +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.ts @@ -146,11 +146,60 @@ export function useEntityRelationNodesAndEdges({ nodeQueue.push(rel.targetRef); visitedNodes.add(rel.targetRef); } + + // if unidirectional add missing relations as entities are only visited once + if (unidirectional) { + const findIndex = edges.findIndex( + edge => + entityRef === edge.from && + rel.targetRef === edge.to && + !edge.relations.includes(rel.type), + ); + if (findIndex >= 0) { + if (mergeRelations) { + const pair = relationPairs.find( + ([l, r]) => l === rel.type || r === rel.type, + ) ?? [rel.type]; + edges[findIndex].relations = [ + ...edges[findIndex].relations, + ...pair, + ]; + } else { + edges[findIndex].relations = [ + ...edges[findIndex].relations, + rel.type, + ]; + } + } + } }); } } - setNodesAndEdges({ nodes, edges }); + // Reduce edges as the dependency graph anyway ignores duplicated edges regarding from / to + // Additionally, this will improve rendering speed for the dependency graph + const finalEdges = edges.reduce((previousEdges, currentEdge) => { + const indexFound = previousEdges.findIndex( + previousEdge => + previousEdge.from === currentEdge.from && + previousEdge.to === currentEdge.to, + ); + if (indexFound >= 0) { + previousEdges[indexFound] = { + ...previousEdges[indexFound], + relations: Array.from( + new Set([ + ...previousEdges[indexFound].relations, + ...currentEdge.relations, + ]), + ), + }; + return previousEdges; + } + return [...previousEdges, currentEdge]; + }, [] as EntityEdge[]); + + setNodesAndEdges({ nodes, edges: finalEdges }); }, 100, [