From f57b5efb31cdab8203346b0598ad74b65cb5a70a Mon Sep 17 00:00:00 2001 From: master <> Date: Sat, 28 Mar 2026 20:44:20 +0200 Subject: [PATCH] Improve topology layout spacing and edge label readability - Increase LayerSpacing from 60 to 120 and NodeSpacing from 40 to 60 for wider promotion arrows between environments - Increase CompoundPadding from 30 to 40 for better region container separation - Replace inline edge labels with tooltip callout pattern: truncated text in a background box with dashed leader line to the edge - Edge labels capped at 30 chars with ellipsis Co-Authored-By: Claude Opus 4.6 (1M context) --- .../Services/TopologyLayoutService.cs | 6 +- .../topology/topology-graph.component.ts | 63 +++++++++++++++++-- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/src/Platform/StellaOps.Platform.WebService/Services/TopologyLayoutService.cs b/src/Platform/StellaOps.Platform.WebService/Services/TopologyLayoutService.cs index bf0328cc2..76592112f 100644 --- a/src/Platform/StellaOps.Platform.WebService/Services/TopologyLayoutService.cs +++ b/src/Platform/StellaOps.Platform.WebService/Services/TopologyLayoutService.cs @@ -143,8 +143,10 @@ public sealed class TopologyLayoutService new ElkLayoutOptions { Direction = direction, - NodeSpacing = 40, - LayerSpacing = 60, + NodeSpacing = 60, + LayerSpacing = 120, + CompoundPadding = 40, + CompoundHeaderHeight = 32, Effort = effort, }, cancellationToken).ConfigureAwait(false); diff --git a/src/Web/StellaOps.Web/src/app/features/topology/topology-graph.component.ts b/src/Web/StellaOps.Web/src/app/features/topology/topology-graph.component.ts index 6a16d77fe..d8147f3d1 100644 --- a/src/Web/StellaOps.Web/src/app/features/topology/topology-graph.component.ts +++ b/src/Web/StellaOps.Web/src/app/features/topology/topology-graph.component.ts @@ -106,11 +106,28 @@ import { [attr.marker-end]="selectedEdgeId() === edge.id ? 'url(#arrow-promotion-selected)' : 'url(#arrow-promotion)'" /> @if (edge.label) { + + + {{ edge.label }} + >{{ truncateEdgeLabel(edge.label) }} } } @@ -341,8 +358,32 @@ import { stroke-width: 2.5; } + .edge-leader { + stroke: var(--color-text-muted); + stroke-width: 0.5; + stroke-dasharray: 2 2; + opacity: 0.5; + pointer-events: none; + } + + .edge-group:hover .edge-leader { + opacity: 0.8; + } + + .edge-label-bg { + fill: var(--color-surface-primary); + stroke: var(--color-border-primary); + stroke-width: 0.5; + opacity: 0.9; + pointer-events: none; + } + + .edge-group--selected .edge-label-bg { + stroke: var(--color-brand-primary); + } + .edge-label { - font-size: 9px; + font-size: 8px; fill: var(--color-text-muted); text-anchor: middle; pointer-events: none; @@ -553,7 +594,21 @@ export class TopologyGraphComponent { } getEdgeLabelY(edge: TopologyRoutedEdge): number { - return this.edgeMidpoint(edge).y - 6; + return this.edgeMidpoint(edge).y - 22; + } + + getEdgeLabelAnchorY(edge: TopologyRoutedEdge): number { + return this.edgeMidpoint(edge).y; + } + + getEdgeLabelWidth(edge: TopologyRoutedEdge): number { + const label = this.truncateEdgeLabel(edge.label); + return label.length * 4.5; + } + + truncateEdgeLabel(label: string | undefined | null): string { + if (!label) return ''; + return label.length > 30 ? label.substring(0, 29) + '\u2026' : label; } truncate(text: string | undefined | null, max: number): string {