diff --git a/.changeset/clean-hotels-tan.md b/.changeset/clean-hotels-tan.md new file mode 100644 index 0000000000..b3ac0ead54 --- /dev/null +++ b/.changeset/clean-hotels-tan.md @@ -0,0 +1,7 @@ +--- +'@backstage/core-components': patch +--- + +Allow to configure zooming for ``. `zoom` can either be +`enabled`, `disabled`, or `enable-on-click`. The latter requires the user to +click into the diagram to enable zooming. diff --git a/.changeset/five-phones-exist.md b/.changeset/five-phones-exist.md new file mode 100644 index 0000000000..1812769a7a --- /dev/null +++ b/.changeset/five-phones-exist.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog-graph': patch +--- + +Make zooming configurable for `` and disable it by default. +This resolves an issue that scrolling on the entity page is sometimes captured +by the graph making the page hard to use. diff --git a/packages/core-components/src/components/DependencyGraph/DependencyGraph.stories.tsx b/packages/core-components/src/components/DependencyGraph/DependencyGraph.stories.tsx index 0b97059754..e81988976c 100644 --- a/packages/core-components/src/components/DependencyGraph/DependencyGraph.stories.tsx +++ b/packages/core-components/src/components/DependencyGraph/DependencyGraph.stories.tsx @@ -51,6 +51,32 @@ export const Default = () => ( ); +export const ZoomDisabled = () => ( +
+ +
+); + +export const ZoomEnableOnClick = () => ( +
+ +
+); + export const BottomToTop = () => (
& { renderNode?: RenderNodeFunction; renderLabel?: RenderLabelFunction; defs?: SVGDefsElement | SVGDefsElement[]; + zoom?: 'enabled' | 'disabled' | 'enable-on-click'; }; const WORKSPACE_ID = 'workspace'; @@ -80,6 +81,7 @@ export function DependencyGraph(props: DependencyGraphProps) { edgeWeight = 1, renderLabel, defs, + zoom = 'enabled', ...svgProps } = props; const theme: BackstageTheme = useTheme(); @@ -110,28 +112,37 @@ export function DependencyGraph(props: DependencyGraphProps) { // Set up zooming + panning const container = d3Selection.select(node); const workspace = d3Selection.select(node.getElementById(WORKSPACE_ID)); - const zoom = d3Zoom - .zoom() - .scaleExtent([1, 10]) - .on('zoom', event => { - event.transform.x = Math.min( - 0, - Math.max( - event.transform.x, - maxWidth - maxWidth * event.transform.k, - ), - ); - event.transform.y = Math.min( - 0, - Math.max( - event.transform.y, - maxHeight - maxHeight * event.transform.k, - ), - ); - workspace.attr('transform', event.transform); - }); - container.call(zoom); + function enableZoom() { + container.call( + d3Zoom + .zoom() + .scaleExtent([1, 10]) + .on('zoom', event => { + event.transform.x = Math.min( + 0, + Math.max( + event.transform.x, + maxWidth - maxWidth * event.transform.k, + ), + ); + event.transform.y = Math.min( + 0, + Math.max( + event.transform.y, + maxHeight - maxHeight * event.transform.k, + ), + ); + workspace.attr('transform', event.transform); + }), + ); + } + + if (zoom === 'enabled') { + enableZoom(); + } else if (zoom === 'enable-on-click') { + container.on('click', () => enableZoom()); + } const { width: newContainerWidth, height: newContainerHeight } = node.getBoundingClientRect(); @@ -142,7 +153,7 @@ export function DependencyGraph(props: DependencyGraphProps) { setContainerHeight(newContainerHeight); } }, 100), - [containerHeight, containerWidth, maxWidth, maxHeight], + [containerHeight, containerWidth, maxWidth, maxHeight, zoom], ); const setNodesAndEdges = React.useCallback(() => { diff --git a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx index abb10d4008..5ac8a89539 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx @@ -27,11 +27,11 @@ import React, { MouseEvent, useCallback } from 'react'; import { useNavigate } from 'react-router'; import { catalogEntityRouteRef, catalogGraphRouteRef } from '../../routes'; import { + ALL_RELATION_PAIRS, Direction, EntityNode, EntityRelationsGraph, RelationPairs, - ALL_RELATION_PAIRS, } from '../EntityRelationsGraph'; const useStyles = makeStyles({ @@ -58,6 +58,7 @@ export const CatalogGraphCard = ({ direction = Direction.LEFT_RIGHT, height, title = 'Relations', + zoom = 'enable-on-click', }: { variant?: InfoCardVariants; relationPairs?: RelationPairs; @@ -69,6 +70,7 @@ export const CatalogGraphCard = ({ direction?: Direction; height?: number; title?: string; + zoom?: 'enabled' | 'disabled' | 'enable-on-click'; }) => { const { entity } = useEntity(); const entityName = getEntityName(entity); @@ -118,6 +120,7 @@ export const CatalogGraphCard = ({ onNodeClick={onNodeClick} className={classes.graph} relationPairs={relationPairs} + zoom={zoom} /> ); diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx index 0ad50a8174..f5f1ced541 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx @@ -231,6 +231,7 @@ export const CatalogGraphPage = ({ direction={direction} relationPairs={relationPairs} className={classes.graph} + zoom="enabled" /> diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.tsx index 0f1e72d8b2..76cd44394a 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.tsx @@ -24,7 +24,7 @@ import classNames from 'classnames'; import React, { MouseEvent, useEffect, useMemo } from 'react'; import { CustomLabel } from './CustomLabel'; import { CustomNode } from './CustomNode'; -import { RelationPairs, ALL_RELATION_PAIRS } from './relations'; +import { ALL_RELATION_PAIRS, RelationPairs } from './relations'; import { Direction, EntityNode } from './types'; import { useEntityRelationNodesAndEdges } from './useEntityRelationNodesAndEdges'; @@ -75,6 +75,7 @@ export const EntityRelationsGraph = ({ onNodeClick, relationPairs = ALL_RELATION_PAIRS, className, + zoom = 'enabled', }: { rootEntityNames: EntityName | EntityName[]; maxDepth?: number; @@ -86,6 +87,7 @@ export const EntityRelationsGraph = ({ onNodeClick?: (value: EntityNode, event: MouseEvent) => void; relationPairs?: RelationPairs; className?: string; + zoom?: 'enabled' | 'disabled' | 'enable-on-click'; }) => { const theme = useTheme(); const classes = useStyles(); @@ -130,6 +132,7 @@ export const EntityRelationsGraph = ({ paddingY={theme.spacing(4)} labelPosition={DependencyGraphTypes.LabelPosition.RIGHT} labelOffset={theme.spacing(1)} + zoom={zoom} /> )}