This is an automated email from the ASF dual-hosted git repository. zqr10159 pushed a commit to branch 2.0.0 in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
commit 446b18b603a0c308474a35d57142c5168ea3f745 Author: Logic <[email protected]> AuthorDate: Sun May 31 08:06:19 2026 +0800 fix(web-next): suppress empty topology legends --- web-next/app/topology/page.test.tsx | 3 + web-next/app/topology/topology-page.tsx | 135 ++++++++++++---------- web-next/packages/hertzbeat-ui/src/index.test.tsx | 13 +++ web-next/packages/hertzbeat-ui/src/index.tsx | 4 + 4 files changed, 92 insertions(+), 63 deletions(-) diff --git a/web-next/app/topology/page.test.tsx b/web-next/app/topology/page.test.tsx index 33ffd36fbd..07fde71da5 100644 --- a/web-next/app/topology/page.test.tsx +++ b/web-next/app/topology/page.test.tsx @@ -1677,6 +1677,9 @@ describe('topology page', () => { expect(html).toContain('data-hz-topology-empty-meta-owner="hertzbeat-ui-empty-meta"'); expect(html).toContain('data-hz-topology-empty-source-owner="hertzbeat-ui-empty-source"'); expect(html).toContain('data-hz-topology-empty-time-scope-owner="hertzbeat-ui-empty-time-scope"'); + expect(html).not.toContain('data-topology-g6-legend-owner="hertzbeat-ui-g6-legend-dock"'); + expect(html).not.toContain('data-hz-ui="topology-legend"'); + expect(html).not.toContain('data-hz-topology-legend-section='); expect(html).not.toContain('data-topology-node-id="svc-checkout"'); expect(html).not.toContain('checkout-api'); expect(html).not.toContain('redis'); diff --git a/web-next/app/topology/topology-page.tsx b/web-next/app/topology/topology-page.tsx index ea04862bef..62209c2af4 100644 --- a/web-next/app/topology/topology-page.tsx +++ b/web-next/app/topology/topology-page.tsx @@ -1152,71 +1152,80 @@ export default function TopologyPage({ }, [topologyG6Graph.nodes, t] ); + const topologyHasVisibleNodes = topologyG6Graph.nodes.length > 0; + const topologyHasVisibleGraphEvidence = topologyHasVisibleNodes || topologyG6Graph.edges.length > 0; const topologyLegendSections = React.useMemo( - () => [ - { - id: 'node-type', - label: t('topology.legend.node-type'), - items: topologyLegendNodeTypeItems - }, - { - id: 'status', - label: t('topology.legend.status'), - items: [ - { - id: 'healthy-node', - label: t('topology.legend.status.healthy'), - color: '#22c55e', - visualSource: 'hertzbeat-status-token' as const, - value: t('topology.legend.status.healthy-value') - }, - { - id: 'warning-node', - label: t('topology.legend.status.warning'), - color: '#f59e0b', - visualSource: 'hertzbeat-status-token' as const, - value: t('topology.legend.status.warning-value') - }, - { - id: 'critical-node', - label: t('topology.legend.status.critical'), - color: '#ef4444', - visualSource: 'hertzbeat-status-token' as const, - value: t('topology.legend.status.critical-value') - } - ] - }, - { - id: 'interaction', - label: t('topology.legend.interaction'), - items: [ - { - id: 'selected-node', - label: t('topology.legend.interaction.selected-node'), - color: '#e5edf8', - visualSource: 'hertzbeat-interaction-token' as const, - value: t('topology.legend.interaction.selected-node-value') - }, - { - id: 'directional-edge', - label: t('topology.legend.interaction.directional-edge'), - color: '#94a3b8', - pattern: 'solid' as const, - visualSource: 'hertzbeat-edge-token' as const, - value: t('topology.legend.interaction.directional-edge-value') - }, - { - id: 'dimmed-edge', - label: t('topology.legend.interaction.dimmed-edge'), - color: '#94a3b8', - pattern: 'muted' as const, - visualSource: 'hertzbeat-edge-token' as const, - value: t('topology.legend.interaction.dimmed-edge-value') - } - ] + () => { + const sections = [ + { + id: 'node-type', + label: t('topology.legend.node-type'), + items: topologyLegendNodeTypeItems + } + ]; + if (topologyHasVisibleNodes) { + sections.push({ + id: 'status', + label: t('topology.legend.status'), + items: [ + { + id: 'healthy-node', + label: t('topology.legend.status.healthy'), + color: '#22c55e', + visualSource: 'hertzbeat-status-token' as const, + value: t('topology.legend.status.healthy-value') + }, + { + id: 'warning-node', + label: t('topology.legend.status.warning'), + color: '#f59e0b', + visualSource: 'hertzbeat-status-token' as const, + value: t('topology.legend.status.warning-value') + }, + { + id: 'critical-node', + label: t('topology.legend.status.critical'), + color: '#ef4444', + visualSource: 'hertzbeat-status-token' as const, + value: t('topology.legend.status.critical-value') + } + ] + }); + } + if (topologyHasVisibleGraphEvidence) { + sections.push({ + id: 'interaction', + label: t('topology.legend.interaction'), + items: [ + { + id: 'selected-node', + label: t('topology.legend.interaction.selected-node'), + color: '#e5edf8', + visualSource: 'hertzbeat-interaction-token' as const, + value: t('topology.legend.interaction.selected-node-value') + }, + { + id: 'directional-edge', + label: t('topology.legend.interaction.directional-edge'), + color: '#94a3b8', + pattern: 'solid' as const, + visualSource: 'hertzbeat-edge-token' as const, + value: t('topology.legend.interaction.directional-edge-value') + }, + { + id: 'dimmed-edge', + label: t('topology.legend.interaction.dimmed-edge'), + color: '#94a3b8', + pattern: 'muted' as const, + visualSource: 'hertzbeat-edge-token' as const, + value: t('topology.legend.interaction.dimmed-edge-value') + } + ] + }); } - ], - [t, topologyLegendNodeTypeItems] + return sections; + }, + [t, topologyHasVisibleGraphEvidence, topologyHasVisibleNodes, topologyLegendNodeTypeItems] ); const topologyEdgeIds = React.useMemo( () => new Set(map.edges.map(edge => edge.id)), diff --git a/web-next/packages/hertzbeat-ui/src/index.test.tsx b/web-next/packages/hertzbeat-ui/src/index.test.tsx index fa75a423af..3768abb6b1 100644 --- a/web-next/packages/hertzbeat-ui/src/index.test.tsx +++ b/web-next/packages/hertzbeat-ui/src/index.test.tsx @@ -5285,6 +5285,19 @@ describe('@hertzbeat/ui', () => { expect(html).toContain('data-hz-topology-legend-item="healthy-node"'); }); + it('does not render a topology legend shell when every section is empty', () => { + const html = renderToStaticMarkup( + <HzTopologyLegend + title="Legend" + boundary="flush" + density="canvas-dock" + sections={[{ id: 'node-type', label: 'Node type', items: [] }]} + /> + ); + + expect(html).toBe(''); + }); + it('renders a topology detail drawer for edge evidence and cross-signal handoffs', () => { const html = renderToStaticMarkup( <HzTopologyDetailDrawer diff --git a/web-next/packages/hertzbeat-ui/src/index.tsx b/web-next/packages/hertzbeat-ui/src/index.tsx index 9d2cf77344..c6455ec437 100644 --- a/web-next/packages/hertzbeat-ui/src/index.tsx +++ b/web-next/packages/hertzbeat-ui/src/index.tsx @@ -11206,6 +11206,10 @@ export function HzTopologyLegend({ const isCanvasDock = density === 'canvas-dock'; const visibleSections = sections.filter(section => section.items.length > 0); + if (visibleSections.length === 0) { + return null; + } + return ( <section {...props} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
