From f3fcfad2c89ea06ab73dc34aeae0be7d1b55a28d Mon Sep 17 00:00:00 2001 From: timo Date: Thu, 18 Apr 2024 18:39:16 +0200 Subject: [PATCH] NodeGraph: Fix invisible arrow tips in Editor (#86517) NodeGraphPanel: Namespace marker IDs to fix invisible arrow tips in editor Co-authored-by: Andrej Ocenas --- public/app/plugins/panel/nodeGraph/Edge.tsx | 7 ++++--- public/app/plugins/panel/nodeGraph/NodeGraph.tsx | 13 ++++++++++++- .../app/plugins/panel/nodeGraph/NodeGraphPanel.tsx | 10 ++++++++-- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/public/app/plugins/panel/nodeGraph/Edge.tsx b/public/app/plugins/panel/nodeGraph/Edge.tsx index 9a9459e9c19..b80a22d71d7 100644 --- a/public/app/plugins/panel/nodeGraph/Edge.tsx +++ b/public/app/plugins/panel/nodeGraph/Edge.tsx @@ -11,13 +11,14 @@ export const defaultEdgeColor = '#999'; interface Props { edge: EdgeDatum; hovering: boolean; + svgIdNamespace: string; onClick: (event: MouseEvent, link: EdgeDatum) => void; onMouseEnter: (id: string) => void; onMouseLeave: (id: string) => void; } export const Edge = memo(function Edge(props: Props) { - const { edge, onClick, onMouseEnter, onMouseLeave, hovering } = props; + const { edge, onClick, onMouseEnter, onMouseLeave, hovering, svgIdNamespace } = props; // Not great typing but after we do layout these properties are full objects not just references const { source, target, sourceNodeRadius, targetNodeRadius } = edge as { @@ -47,8 +48,8 @@ export const Edge = memo(function Edge(props: Props) { // in case both are provided const highlightedEdgeColor = edge.color || defaultHighlightedEdgeColor; - const markerId = `triangle-${edge.id}`; - const coloredMarkerId = `triangle-colored-${edge.id}`; + const markerId = `triangle-${svgIdNamespace}-${edge.id}`; + const coloredMarkerId = `triangle-colored-${svgIdNamespace}-${edge.id}`; return ( <> diff --git a/public/app/plugins/panel/nodeGraph/NodeGraph.tsx b/public/app/plugins/panel/nodeGraph/NodeGraph.tsx index f0053aada0f..d49e9edb8eb 100644 --- a/public/app/plugins/panel/nodeGraph/NodeGraph.tsx +++ b/public/app/plugins/panel/nodeGraph/NodeGraph.tsx @@ -111,8 +111,9 @@ interface Props { dataFrames: DataFrame[]; getLinks: (dataFrame: DataFrame, rowIndex: number) => LinkModel[]; nodeLimit?: number; + panelId?: string; } -export function NodeGraph({ getLinks, dataFrames, nodeLimit }: Props) { +export function NodeGraph({ getLinks, dataFrames, nodeLimit, panelId }: Props) { const nodeCountLimit = nodeLimit || defaultNodeCountLimit; const { edges: edgesDataFrames, nodes: nodesDataFrames } = useCategorizeFrames(dataFrames); @@ -122,6 +123,13 @@ export function NodeGraph({ getLinks, dataFrames, nodeLimit }: Props) { const firstNodesDataFrame = nodesDataFrames[0]; const firstEdgesDataFrame = edgesDataFrames[0]; + // Ensure we use unique IDs for the marker tip elements, since IDs are global + // in the entire HTML document. This prevents hidden tips when an earlier + // occurence is hidden (editor is open in front of an existing node graph + // panel) or when the earlier tips have different properties (color, size, or + // shape for example). + const svgIdNamespace = panelId || 'nodegraphpanel'; + // TODO we should be able to allow multiple dataframes for both edges and nodes, could be issue with node ids which in // that case should be unique or figure a way to link edges and nodes dataframes together. const processed = useMemo( @@ -215,6 +223,7 @@ export function NodeGraph({ getLinks, dataFrames, nodeLimit }: Props) { onClick={onEdgeOpen} onMouseEnter={setEdgeHover} onMouseLeave={clearEdgeHover} + svgIdNamespace={svgIdNamespace} /> )} , link: EdgeDatum) => void; onMouseEnter: (id: string) => void; onMouseLeave: (id: string) => void; @@ -351,6 +361,7 @@ const Edges = memo(function Edges(props: EdgesProps) { onClick={props.onClick} onMouseEnter={props.onMouseEnter} onMouseLeave={props.onMouseLeave} + svgIdNamespace={props.svgIdNamespace} /> ))} diff --git a/public/app/plugins/panel/nodeGraph/NodeGraphPanel.tsx b/public/app/plugins/panel/nodeGraph/NodeGraphPanel.tsx index c1f256dda52..feb7e18e160 100644 --- a/public/app/plugins/panel/nodeGraph/NodeGraphPanel.tsx +++ b/public/app/plugins/panel/nodeGraph/NodeGraphPanel.tsx @@ -1,5 +1,5 @@ import memoizeOne from 'memoize-one'; -import React from 'react'; +import React, { useId } from 'react'; import { PanelProps } from '@grafana/data'; @@ -11,6 +11,8 @@ import { getNodeGraphDataFrames } from './utils'; export const NodeGraphPanel = ({ width, height, data, options }: PanelProps) => { const getLinks = useLinks(data.timeRange); + const panelId = useId(); + if (!data || !data.series.length) { return (
@@ -22,7 +24,11 @@ export const NodeGraphPanel = ({ width, height, data, options }: PanelProps - +
); };