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

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

commit 58ed6abeb997e2ba24fa0bf9e893cc3559639bcd
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon May 18 09:12:34 2026 +0200

    TUI: move tab badge counters below labels, centred on row 2
    
    Previously the badge (e.g. "(12)") was appended inline after the label text,
    causing every tab's position to shift as counts changed. Now labels occupy
    row 0 at a fixed width and badge counters are rendered on row 1, centred
    under their tab. The two-row area was already allocated by the layout.
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
---
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  | 117 +++++++++++++--------
 1 file changed, 74 insertions(+), 43 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
index 0c20ff224d2d..09dc0a54493d 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
@@ -1077,25 +1077,86 @@ public class CamelMonitor extends CamelCommand {
         int historyCount = hasSelection ? historyEntries.size() : 0;
         boolean hasTraces = hasSelection && !traces.get().isEmpty();
 
+        // Row 0: label-only titles — fixed width so the tab bar never shifts 
when badges appear
+        Line[] labels = {
+                Line.from(" 1 Overview "),
+                Line.from(" 2 Log "),
+                Line.from(" 3 Routes "),
+                Line.from(" 4 Consumers "),
+                Line.from(" 5 Endpoints "),
+                Line.from(" 6 Health "),
+                Line.from(" 7 Last "),
+                Line.from(" 8 Trace "),
+                Line.from(" 9 Circuit Breaker "),
+        };
+
         Tabs tabs = Tabs.builder()
-                .titles(
-                        badge(" 1 Overview ", activeCount),
-                        Line.from(" 2 Log "),
-                        badge(" 3 Routes ", routeCount),
-                        badge(" 4 Consumers ", consumerCount),
-                        badge(" 5 Endpoints ", endpointCount),
-                        badgeHealth(" 6 Health ", healthCount, 
healthDownCount),
-                        badge(" 7 Last ", historyCount),
-                        hasTraces
-                                ? Line.from(Span.raw(" 8 Trace "), 
Span.styled("(*)", Style.EMPTY.fg(Color.YELLOW).bold()),
-                                        Span.raw(" "))
-                                : Line.from(" 8 Trace "),
-                        badgeCb(" 9 Circuit Breaker ", cbCount, cbOpenCount))
+                .titles(labels)
                 .highlightStyle(Style.EMPTY.fg(Color.rgb(0xF6, 0x91, 
0x23)).bold())
                 .divider(Span.styled(" | ", Style.EMPTY.dim()))
                 .build();
 
         frame.renderStatefulWidget(tabs, area, tabsState);
+
+        // Row 1: badge counters centered below each tab label
+        if (area.height() >= 2) {
+            int badgeY = area.y() + 1;
+            int dividerW = CharWidth.of(" | ");
+
+            String[] badgeTexts = { "", "", "", "", "", "", "", "", "" };
+            Style[] badgeStyles = new Style[labels.length];
+            Style yellow = Style.EMPTY.fg(Color.YELLOW).bold();
+            Style red = Style.EMPTY.fg(Color.LIGHT_RED).bold();
+            for (int j = 0; j < badgeStyles.length; j++) {
+                badgeStyles[j] = yellow;
+            }
+
+            if (activeCount > 0) {
+                badgeTexts[0] = "(" + activeCount + ")";
+            }
+            // tab 1 (Log) — no badge
+            if (routeCount > 0) {
+                badgeTexts[2] = "(" + routeCount + ")";
+            }
+            if (consumerCount > 0) {
+                badgeTexts[3] = "(" + consumerCount + ")";
+            }
+            if (endpointCount > 0) {
+                badgeTexts[4] = "(" + endpointCount + ")";
+            }
+            if (healthDownCount > 0) {
+                badgeTexts[5] = "(" + healthDownCount + " DOWN)";
+                badgeStyles[5] = red;
+            } else if (healthCount > 0) {
+                badgeTexts[5] = "(" + healthCount + ")";
+            }
+            if (historyCount > 0) {
+                badgeTexts[6] = "(" + historyCount + ")";
+            }
+            if (hasTraces) {
+                badgeTexts[7] = "(*)";
+            }
+            if (cbOpenCount > 0) {
+                badgeTexts[8] = "(" + cbOpenCount + " OPEN)";
+                badgeStyles[8] = red;
+            } else if (cbCount > 0) {
+                badgeTexts[8] = "(" + cbCount + ")";
+            }
+
+            int tabX = 0;
+            for (int i = 0; i < labels.length; i++) {
+                if (i > 0) {
+                    tabX += dividerW;
+                }
+                int tabW = labels[i].width();
+                if (!badgeTexts[i].isEmpty()) {
+                    int badgeW = CharWidth.of(badgeTexts[i]);
+                    int startX = area.x() + tabX + Math.max(0, (tabW - badgeW) 
/ 2);
+                    frame.buffer().setString(startX, badgeY, badgeTexts[i], 
badgeStyles[i]);
+                }
+                tabX += tabW;
+            }
+        }
     }
 
     private void renderContent(Frame frame, Rect area) {
@@ -4054,36 +4115,6 @@ public class CamelMonitor extends CamelCommand {
         return Cell.from(Span.styled(" ".repeat(leftPad) + text, style));
     }
 
-    private static Line badgeCb(String label, long total, long open) {
-        if (open > 0) {
-            return Line.from(
-                    Span.raw(label),
-                    Span.styled("(" + open + " OPEN)", 
Style.EMPTY.fg(Color.LIGHT_RED).bold()),
-                    Span.raw(" "));
-        }
-        return badge(label, total);
-    }
-
-    private static Line badgeHealth(String label, long total, long down) {
-        if (down > 0) {
-            return Line.from(
-                    Span.raw(label),
-                    Span.styled("(" + down + " DOWN)", 
Style.EMPTY.fg(Color.LIGHT_RED).bold()),
-                    Span.raw(" "));
-        }
-        return badge(label, total);
-    }
-
-    private static Line badge(String label, long count) {
-        if (count > 0) {
-            return Line.from(
-                    Span.raw(label),
-                    Span.styled("(" + count + ")", 
Style.EMPTY.fg(Color.YELLOW).bold()),
-                    Span.raw(" "));
-        }
-        return Line.from(label);
-    }
-
     private static final Style HINT_KEY_STYLE = 
Style.EMPTY.fg(Color.YELLOW).bold();
 
     private static void hint(List<Span> spans, String key, String label) {

Reply via email to