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

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

commit 82cb469eb1b6f881d65b1be65040e3776a4909ff
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Jul 27 20:06:57 2026 +0200

    camel-tui: Kafka tab master-detail layout with full error display
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../dsl/jbang/core/commands/tui/KafkaTab.java      | 70 ++++++++++++++++++++--
 1 file changed, 64 insertions(+), 6 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/KafkaTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/KafkaTab.java
index 945ab7f1b289..f162ef19d7ca 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/KafkaTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/KafkaTab.java
@@ -21,13 +21,17 @@ import java.util.List;
 import java.util.Locale;
 
 import dev.tamboui.layout.Constraint;
+import dev.tamboui.layout.Layout;
 import dev.tamboui.layout.Rect;
 import dev.tamboui.style.Style;
 import dev.tamboui.terminal.Frame;
+import dev.tamboui.text.Line;
 import dev.tamboui.text.Span;
+import dev.tamboui.text.Text;
 import dev.tamboui.widgets.block.Block;
 import dev.tamboui.widgets.block.BorderType;
 import dev.tamboui.widgets.block.Borders;
+import dev.tamboui.widgets.paragraph.Paragraph;
 import dev.tamboui.widgets.table.Cell;
 import dev.tamboui.widgets.table.Row;
 import dev.tamboui.widgets.table.Table;
@@ -61,6 +65,15 @@ class KafkaTab extends AbstractTableTab {
         List<KafkaConsumerInfo> sorted = new ArrayList<>(info.kafkaConsumers);
         sorted.sort(this::sortKafka);
 
+        List<Rect> chunks = Layout.vertical()
+                .constraints(Constraint.fill(), Constraint.length(7))
+                .split(area);
+
+        renderTable(frame, chunks.get(0), sorted);
+        renderDetail(frame, chunks.get(1), sorted);
+    }
+
+    private void renderTable(Frame frame, Rect area, List<KafkaConsumerInfo> 
sorted) {
         List<Row> rows = new ArrayList<>();
         for (KafkaConsumerInfo ki : sorted) {
             String state = ki.state != null ? ki.state : "";
@@ -83,8 +96,8 @@ class KafkaTab extends AbstractTableTab {
                     Cell.from(topic),
                     rightCell(partition, 9),
                     rightCell(offset, 10),
-                    Cell.from(Span.styled(error, error.isEmpty() ? Style.EMPTY 
: Theme.error())),
-                    Cell.from(Span.styled(uri, Style.EMPTY.dim()))));
+                    Cell.from(Span.styled(uri, Style.EMPTY.dim())),
+                    Cell.from(Span.styled(error, error.isEmpty() ? Style.EMPTY 
: Theme.error()))));
         }
 
         if (rows.isEmpty()) {
@@ -100,8 +113,8 @@ class KafkaTab extends AbstractTableTab {
                         Cell.from(Span.styled(sortLabel("TOPIC", "topic"), 
sortStyle("topic"))),
                         rightCell("PARTITION", 9, Style.EMPTY.bold()),
                         rightCell("OFFSET", 10, Style.EMPTY.bold()),
-                        Cell.from(Span.styled("ERROR", Style.EMPTY.bold())),
-                        Cell.from(Span.styled("ENDPOINT", 
Style.EMPTY.bold()))))
+                        Cell.from(Span.styled("ENDPOINT", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("ERROR", Style.EMPTY.bold()))))
                 .widths(
                         Constraint.length(20),
                         Constraint.length(12),
@@ -109,7 +122,7 @@ class KafkaTab extends AbstractTableTab {
                         Constraint.length(20),
                         Constraint.length(9),
                         Constraint.length(10),
-                        Constraint.length(30),
+                        Constraint.length(25),
                         Constraint.fill())
                 .highlightStyle(Theme.selectionBg())
                 .highlightSpacing(Table.HighlightSpacing.ALWAYS)
@@ -122,6 +135,51 @@ class KafkaTab extends AbstractTableTab {
         renderScrollbar(frame, sorted.size());
     }
 
+    private void renderDetail(Frame frame, Rect area, List<KafkaConsumerInfo> 
sorted) {
+        Integer sel = tableState.selected();
+        if (sel == null || sel < 0 || sel >= sorted.size()) {
+            frame.renderWidget(
+                    Paragraph.builder()
+                            .text(Text.from(Line.from(Span.styled(" Select a 
consumer", Style.EMPTY.dim()))))
+                            
.block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL)
+                                    .title(" Detail ").build())
+                            .build(),
+                    area);
+            return;
+        }
+
+        KafkaConsumerInfo ki = sorted.get(sel);
+        List<Line> lines = new ArrayList<>();
+
+        if (ki.groupId != null && !ki.groupId.isEmpty()) {
+            lines.add(Line.from(
+                    Span.styled("  Group-ID: ", Theme.muted()),
+                    Span.styled(ki.groupId, Style.EMPTY.fg(Theme.baseFg()))));
+        }
+        if (ki.uri != null && !ki.uri.isEmpty()) {
+            lines.add(Line.from(
+                    Span.styled("  Endpoint: ", Theme.muted()),
+                    Span.styled(ki.uri, Style.EMPTY.fg(Theme.baseFg()))));
+        }
+        if (ki.lastError != null && !ki.lastError.isEmpty()) {
+            lines.add(Line.from(
+                    Span.styled("  Error:    ", Theme.muted()),
+                    Span.styled(ki.lastError, Theme.error())));
+        }
+
+        String title = ki.routeId != null ? " " + ki.routeId + " " : " Detail 
";
+
+        frame.renderWidget(
+                Paragraph.builder()
+                        .text(Text.from(lines.isEmpty()
+                                ? List.of(Line.from(Span.styled(" No details", 
Style.EMPTY.dim())))
+                                : lines))
+                        
.block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL)
+                                .title(title).build())
+                        .build(),
+                area);
+    }
+
     private int sortKafka(KafkaConsumerInfo a, KafkaConsumerInfo b) {
         int result = switch (sort) {
             case "state" -> compareStr(a.state, b.state);
@@ -179,8 +237,8 @@ class KafkaTab extends AbstractTableTab {
                 - **TOPIC** — Topic of the last consumed record
                 - **PARTITION** — Partition number of the last consumed record
                 - **OFFSET** — Offset of the last consumed record
+                - **ENDPOINT** — Camel endpoint URI for this consumer
                 - **ERROR** — Last error message if the consumer is unhealthy
-                - **ENDPOINT** — Full Camel endpoint URI for this consumer
 
                 ## What to Look For
 

Reply via email to