This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch feature/CAMEL-23672-tui-diagram
in repository https://gitbox.apache.org/repos/asf/camel.git

commit decec6c8e1587864e5d9df4143d131644e39c9f0
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Jun 4 09:52:18 2026 +0200

    CAMEL-23672: camel-tui - Route diagram external styling and description mode
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../jbang/core/commands/tui/DiagramSupport.java    | 24 ++++++++-
 .../dsl/jbang/core/commands/tui/DiagramTab.java    |  4 +-
 .../commands/tui/diagram/RouteDiagramWidget.java   | 62 +++++++++++++++++++---
 3 files changed, 80 insertions(+), 10 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
index 0b9d6635a401..5a8b3b7e4913 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
@@ -858,6 +858,23 @@ class DiagramSupport {
         return endpoints;
     }
 
+    private Map<String, String> computeRouteDescriptions() {
+        Map<String, String> descriptions = new HashMap<>();
+        for (var entry : routeLayouts.entrySet()) {
+            var lr = entry.getValue();
+            for (var node : lr.nodes) {
+                if ("route".equals(node.type) && node.treeNode != null) {
+                    String desc = node.treeNode.info.description;
+                    if (desc != null && !desc.isBlank()) {
+                        descriptions.put(entry.getKey(), desc);
+                    }
+                    break;
+                }
+            }
+        }
+        return descriptions;
+    }
+
     private static String findFromUri(RouteDiagramLayoutEngine.LayoutRoute lr) 
{
         for (var node : lr.nodes) {
             if ("from".equals(node.type) && node.treeNode != null) {
@@ -879,9 +896,11 @@ class DiagramSupport {
         Rect inner = block.inner(area);
         int nw = RouteDiagramLayoutEngine.DEFAULT_BOX_WIDTH * 
RouteDiagramLayoutEngine.SCALE;
         Map<String, String> linkable = 
computeLinkableEndpoints(currentRouteId);
+        Map<String, String> routeDescs = showDescription ? 
computeRouteDescriptions() : Collections.emptyMap();
 
         var widget = new 
org.apache.camel.dsl.jbang.core.commands.tui.diagram.RouteDiagramWidget(
-                routeLayout, nw, selectedEipNodeIndex, scrollX, scrollY, 
metrics, linkable);
+                routeLayout, nw, selectedEipNodeIndex, scrollX, scrollY, 
metrics, linkable,
+                showDescription, routeDescs);
 
         int totalRows = widget.getTotalRows();
         int totalCols = widget.getTotalCols();
@@ -896,7 +915,8 @@ class DiagramSupport {
         scrollX = Math.min(scrollX, maxHScroll);
 
         var finalWidget = new 
org.apache.camel.dsl.jbang.core.commands.tui.diagram.RouteDiagramWidget(
-                routeLayout, nw, selectedEipNodeIndex, scrollX, scrollY, 
metrics, linkable);
+                routeLayout, nw, selectedEipNodeIndex, scrollX, scrollY, 
metrics, linkable,
+                showDescription, routeDescs);
 
         List<Rect> vChunks = Layout.vertical()
                 .constraints(Constraint.fill(), Constraint.length(1))
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
index f48e7854eabe..c293f444f309 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
@@ -572,13 +572,13 @@ class DiagramTab implements MonitorTab {
                             long ago = now - 
stat.lastCompletedExchangeTimestamp;
                             lines.add(Line.from(
                                     Span.styled("   success: ", 
Style.EMPTY.dim()),
-                                    Span.raw(TimeUtils.printDuration(ago, 
true))));
+                                    Span.raw(TimeUtils.printDuration(ago, 
false))));
                         }
                         if (stat.lastFailedExchangeTimestamp > 0) {
                             long ago = now - stat.lastFailedExchangeTimestamp;
                             lines.add(Line.from(
                                     Span.styled("   fail:    ", 
Style.EMPTY.dim()),
-                                    Span.styled(TimeUtils.printDuration(ago, 
true),
+                                    Span.styled(TimeUtils.printDuration(ago, 
false),
                                             Style.EMPTY.fg(Color.LIGHT_RED))));
                         }
                     }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/diagram/RouteDiagramWidget.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/diagram/RouteDiagramWidget.java
index 4b616eb51af8..ae2adf1d1c4a 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/diagram/RouteDiagramWidget.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/diagram/RouteDiagramWidget.java
@@ -58,6 +58,10 @@ public class RouteDiagramWidget implements Widget {
     private final boolean showMetrics;
     private final Map<String, String> linkableEndpoints;
 
+    private final boolean showDescription;
+    private final Map<String, String> routeDescriptions;
+    private final String currentRouteLabel;
+
     private final List<EipNodeBox> nodeBoxes = new ArrayList<>();
 
     public record EipNodeBox(String nodeId, String type, int startRow, int 
endRow, int startCol, int endCol,
@@ -69,13 +73,22 @@ public class RouteDiagramWidget implements Widget {
                               int selectedNodeIndex, int scrollX, int scrollY,
                               boolean showMetrics) {
         this(layoutRoute, nodeWidth, selectedNodeIndex, scrollX, scrollY, 
showMetrics,
-             Collections.emptyMap());
+             Collections.emptyMap(), false, Collections.emptyMap());
     }
 
     public RouteDiagramWidget(
                               LayoutRoute layoutRoute, int nodeWidth,
                               int selectedNodeIndex, int scrollX, int scrollY,
                               boolean showMetrics, Map<String, String> 
linkableEndpoints) {
+        this(layoutRoute, nodeWidth, selectedNodeIndex, scrollX, scrollY, 
showMetrics,
+             linkableEndpoints, false, Collections.emptyMap());
+    }
+
+    public RouteDiagramWidget(
+                              LayoutRoute layoutRoute, int nodeWidth,
+                              int selectedNodeIndex, int scrollX, int scrollY,
+                              boolean showMetrics, Map<String, String> 
linkableEndpoints,
+                              boolean showDescription, Map<String, String> 
routeDescriptions) {
         this.layoutRoute = layoutRoute;
         this.nodeWidth = nodeWidth;
         this.boxWidth = Math.max(MIN_BOX_WIDTH, nodeWidth / X_DIVISOR);
@@ -84,6 +97,20 @@ public class RouteDiagramWidget implements Widget {
         this.scrollY = scrollY;
         this.showMetrics = showMetrics;
         this.linkableEndpoints = linkableEndpoints;
+        this.showDescription = showDescription;
+        this.routeDescriptions = routeDescriptions;
+        if (showDescription) {
+            String desc = null;
+            for (LayoutNode ln : layoutRoute.nodes) {
+                if ("route".equals(ln.type) && ln.treeNode != null) {
+                    desc = ln.treeNode.info.description;
+                    break;
+                }
+            }
+            this.currentRouteLabel = (desc != null && !desc.isBlank()) ? desc 
: layoutRoute.routeId;
+        } else {
+            this.currentRouteLabel = null;
+        }
     }
 
     public List<EipNodeBox> getNodeBoxes() {
@@ -208,9 +235,10 @@ public class RouteDiagramWidget implements Widget {
 
         StatInfo stat = resolveStatInfo(to);
         long total = stat != null ? stat.exchangesTotal : 0;
-        boolean dashed = (showMetrics && total == 0) || isExternalEndpoint(to);
+        boolean external = isExternalEndpoint(to);
+        boolean dashed = (showMetrics && total == 0) || external;
 
-        drawArrowPath(buffer, area, fromCx, fromBottom, toCx, toTop, dashed);
+        drawArrowPath(buffer, area, fromCx, fromBottom, toCx, toTop, dashed, 
external);
         drawCounters(buffer, area, toCx, toTop, stat);
     }
 
@@ -224,18 +252,27 @@ public class RouteDiagramWidget implements Widget {
         long total = stat != null ? stat.exchangesTotal : 0;
         boolean dashed = showMetrics && total == 0;
 
-        drawArrowPath(buffer, area, fromCx, fromRow, toCx, toTop, dashed);
+        drawArrowPath(buffer, area, fromCx, fromRow, toCx, toTop, dashed, 
false);
         drawCounters(buffer, area, toCx, toTop, stat);
     }
 
-    private void drawArrowPath(Buffer buffer, Rect area, int fromCx, int 
fromRow, int toCx, int toRow, boolean dashed) {
+    private void drawArrowPath(
+            Buffer buffer, Rect area, int fromCx, int fromRow, int toCx, int 
toRow,
+            boolean dashed, boolean external) {
         if (fromRow >= toRow) {
             return;
         }
 
         char vChar = dashed ? DASH_V : V;
         char hChar = dashed ? DASH_H : H;
-        Style edgeStyle = dashed ? Style.EMPTY.fg(Color.DARK_GRAY) : 
Style.EMPTY.fg(Color.GRAY);
+        Style edgeStyle;
+        if (external) {
+            edgeStyle = Style.EMPTY.fg(EXTERNAL_COLOR);
+        } else if (dashed) {
+            edgeStyle = Style.EMPTY.fg(Color.DARK_GRAY);
+        } else {
+            edgeStyle = Style.EMPTY.fg(Color.GRAY);
+        }
 
         if (fromCx == toCx) {
             for (int r = fromRow; r < toRow - 1; r++) {
@@ -338,6 +375,19 @@ public class RouteDiagramWidget implements Widget {
 
     private List<String> rewrapText(LayoutNode node, int maxWidth) {
         String label = String.join("", node.wrappedLines);
+        if (showDescription) {
+            if ("from".equals(node.type) && currentRouteLabel != null) {
+                label = currentRouteLabel;
+            } else {
+                String linkedRouteId = findLinkedRouteId(node);
+                if (linkedRouteId != null) {
+                    String desc = routeDescriptions.get(linkedRouteId);
+                    if (desc != null && !desc.isBlank()) {
+                        label = desc;
+                    }
+                }
+            }
+        }
         return wrapText(label, maxWidth);
     }
 

Reply via email to