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


The following commit(s) were added to refs/heads/main by this push:
     new 2c53ecd29bd3 CAMEL-23512: Fix TamboUI API misuse in 
camel-jbang-plugin-tui (#23200)
2c53ecd29bd3 is described below

commit 2c53ecd29bd3787885d4b0287e8e1de6012d3a3f
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu May 14 08:26:57 2026 +0200

    CAMEL-23512: Fix TamboUI API misuse in camel-jbang-plugin-tui (#23200)
    
    * CAMEL-23512: Fix TamboUI API misuse in camel-jbang-plugin-tui
    
    - Replace deprecated KeyEvent.character() with ke.string() for proper 
Unicode support
    - Use CharWidth for display width calculations instead of String.length()
    - Fix TuiHelper.truncate() to use CharWidth.truncateWithEllipsis()
    - Fix CamelCatalogTui.wrapText() and flowFields() to use CharWidth
    - Fix CamelMonitor diagram width calculation to use CharWidth
    - Enable mouse capture in CamelMonitor for diagram scrolling
    - Move TableState for processors and route header to class fields
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    
    * CAMEL-23512: Use TamboUI semantic key bindings instead of raw KeyCode 
checks
    
    Replace raw KeyCode checks with semantic binding methods so vim/emacs
    key bindings are respected automatically via TamboUI's binding system.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    
    * CAMEL-23512: Replace vim g/G keys with Home/End in Log tab
    
    Use standard Home/End keys for jump-to-top and jump-to-end in the
    log viewer instead of vim-style g/G for consistency with normal users.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    
    * CAMEL-23512: Use Block with Borders.TOP_ONLY for catalog separator
    
    Replace manual Unicode box-drawing character repetition with TamboUI's
    Block widget using Borders.TOP_ONLY for idiomatic separator rendering.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    
    * CAMEL-23512: Use Style.EMPTY constant instead of Style.create()
    
    Avoid unnecessary method call overhead by using the Style.EMPTY
    constant directly instead of the Style.create() factory method
    which just returns EMPTY.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    
    * CAMEL-23512: Use Paragraph scroll and word wrap for catalog description
    
    Replace manual line slicing and custom wrapText() method with
    Paragraph's built-in scroll() and Overflow.WRAP_WORD support.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    
    * CAMEL-23512: Deduplicate footer rendering with hint helper methods
    
    Extract hint(), hintLast(), and hintRefresh() helpers to eliminate
    repeated Span.styled/Span.raw patterns across all six tab footers.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    
    * CAMEL-23512: Move blocking I/O off the render thread
    
    Move refreshData() and loadDiagramForSelectedRoute() to background
    threads using TuiRunner.scheduler() to prevent UI freezes.
    
    - refreshData() now runs on the scheduler thread with AtomicBoolean
      guard against overlapping refreshes; results swapped to render thread
    - loadDiagramForSelectedRoute() shows loading state immediately, then
      runs file I/O, polling, and diagram rendering on the scheduler thread;
      diagram state applied atomically via runOnRenderThread()
    - Convert logLines/filteredLogEntries to swap-on-write pattern for
      thread-safe reads from the render thread
    - pollJsonResponse() Thread.sleep loop no longer blocks the render thread
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    
    * CAMEL-23512: Use default scrollbar style for diagram scrollbars
    
    Remove custom orange thumb color from vertical scrollbar so both
    vertical and horizontal scrollbars use the same default style.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    
    * CAMEL-23512: Reorder Log tab footer to group navigation hints
    
    Place PgUp/PgDn and Home/End next to each other in the Log tab
    footer for consistent grouping of navigation keys.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
---
 .../jbang/core/commands/tui/CamelCatalogTui.java   | 153 ++---
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  | 647 +++++++++++----------
 .../dsl/jbang/core/commands/tui/TuiHelper.java     |   5 +-
 3 files changed, 405 insertions(+), 400 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelCatalogTui.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelCatalogTui.java
index cbd2e3022b0c..7e8aef4c3b3b 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelCatalogTui.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelCatalogTui.java
@@ -28,6 +28,7 @@ import dev.tamboui.style.Color;
 import dev.tamboui.style.Overflow;
 import dev.tamboui.style.Style;
 import dev.tamboui.terminal.Frame;
+import dev.tamboui.text.CharWidth;
 import dev.tamboui.text.Line;
 import dev.tamboui.text.Span;
 import dev.tamboui.text.Text;
@@ -37,6 +38,7 @@ import dev.tamboui.tui.event.KeyCode;
 import dev.tamboui.tui.event.KeyEvent;
 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;
@@ -267,7 +269,7 @@ public class CamelCatalogTui extends CamelCommand {
             }
 
             // Escape: clear filter first, then go back, then quit
-            if (ke.isKey(KeyCode.ESCAPE)) {
+            if (ke.isCancel()) {
                 if (focus == FOCUS_OPTIONS && (!optionFilter.isEmpty() || 
optionFullText)) {
                     optionFilter.setLength(0);
                     optionFullText = false;
@@ -290,7 +292,7 @@ public class CamelCatalogTui extends CamelCommand {
             }
 
             // Backspace: delete from active filter
-            if (ke.isKey(KeyCode.BACKSPACE)) {
+            if (ke.isDeleteBackward()) {
                 if (focus == FOCUS_LIST && !componentFilter.isEmpty()) {
                     componentFilter.deleteCharAt(componentFilter.length() - 1);
                     applyComponentFilter();
@@ -302,7 +304,7 @@ public class CamelCatalogTui extends CamelCommand {
             }
 
             // Panel switching — only when no active filter on current panel
-            if (ke.isKey(KeyCode.TAB)) {
+            if (ke.isFocusNext()) {
                 if (focus == FOCUS_LIST) {
                     focus = FOCUS_OPTIONS;
                 } else {
@@ -311,19 +313,19 @@ public class CamelCatalogTui extends CamelCommand {
                 descriptionScroll = 0;
                 return true;
             }
-            if (ke.isKey(KeyCode.RIGHT) && focus == FOCUS_LIST) {
+            if (ke.isRight() && focus == FOCUS_LIST) {
                 focus = FOCUS_OPTIONS;
                 descriptionScroll = 0;
                 return true;
             }
-            if (ke.isKey(KeyCode.LEFT) && focus == FOCUS_OPTIONS) {
+            if (ke.isLeft() && focus == FOCUS_OPTIONS) {
                 focus = FOCUS_LIST;
                 descriptionScroll = 0;
                 return true;
             }
 
             // Enter drills into options
-            if (ke.isKey(KeyCode.ENTER) && focus == FOCUS_LIST) {
+            if (ke.isConfirm() && focus == FOCUS_LIST) {
                 focus = FOCUS_OPTIONS;
                 descriptionScroll = 0;
                 return true;
@@ -350,11 +352,11 @@ public class CamelCatalogTui extends CamelCommand {
                 }
                 return true;
             }
-            if (ke.isKey(KeyCode.PAGE_UP)) {
+            if (ke.isPageUp()) {
                 descriptionScroll = Math.max(0, descriptionScroll - 5);
                 return true;
             }
-            if (ke.isKey(KeyCode.PAGE_DOWN)) {
+            if (ke.isPageDown()) {
                 descriptionScroll += 5;
                 return true;
             }
@@ -374,10 +376,10 @@ public class CamelCatalogTui extends CamelCommand {
             // Typing filters the active panel
             if (ke.code() == KeyCode.CHAR) {
                 if (focus == FOCUS_LIST) {
-                    componentFilter.append(ke.character());
+                    componentFilter.append(ke.string());
                     applyComponentFilter();
                 } else {
-                    optionFilter.append(ke.character());
+                    optionFilter.append(ke.string());
                     applyOptionFilter();
                 }
                 return true;
@@ -410,10 +412,10 @@ public class CamelCatalogTui extends CamelCommand {
 
     private void renderHeader(Frame frame, Rect area) {
         Line titleLine = Line.from(
-                Span.styled(" Camel Catalog", 
Style.create().fg(Color.rgb(0xF6, 0x91, 0x23)).bold()),
+                Span.styled(" Camel Catalog", Style.EMPTY.fg(Color.rgb(0xF6, 
0x91, 0x23)).bold()),
                 Span.raw("  "),
                 Span.styled(filteredComponents.size() + "/" + 
allComponents.size() + " components",
-                        Style.create().fg(Color.CYAN)));
+                        Style.EMPTY.fg(Color.CYAN)));
 
         Block headerBlock = Block.builder()
                 .borderType(BorderType.ROUNDED)
@@ -439,8 +441,8 @@ public class CamelCatalogTui extends CamelCommand {
         List<Row> rows = new ArrayList<>();
         for (ComponentInfo comp : filteredComponents) {
             Style nameStyle = comp.deprecated
-                    ? Style.create().fg(Color.RED).dim()
-                    : Style.create().fg(Color.CYAN);
+                    ? Style.EMPTY.fg(Color.RED).dim()
+                    : Style.EMPTY.fg(Color.CYAN);
             String label = comp.name;
             if (comp.deprecated) {
                 label = label + " (deprecated)";
@@ -449,12 +451,12 @@ public class CamelCatalogTui extends CamelCommand {
         }
 
         if (rows.isEmpty()) {
-            rows.add(Row.from(Cell.from(Span.styled("No matching components", 
Style.create().dim()))));
+            rows.add(Row.from(Cell.from(Span.styled("No matching components", 
Style.EMPTY.dim()))));
         }
 
         Style borderStyle = focus == FOCUS_LIST
-                ? Style.create().fg(Color.rgb(0xF6, 0x91, 0x23))
-                : Style.create();
+                ? Style.EMPTY.fg(Color.rgb(0xF6, 0x91, 0x23))
+                : Style.EMPTY;
 
         String modePrefix = componentFullText ? "/" : "";
         String listTitle = componentFilter.isEmpty() && !componentFullText
@@ -464,7 +466,7 @@ public class CamelCatalogTui extends CamelCommand {
         Table table = Table.builder()
                 .rows(rows)
                 .widths(Constraint.fill())
-                .highlightStyle(Style.create().fg(Color.WHITE).bold().onBlue())
+                .highlightStyle(Style.EMPTY.fg(Color.WHITE).bold().onBlue())
                 .highlightSpacing(Table.HighlightSpacing.ALWAYS)
                 .block(Block.builder()
                         .borderType(BorderType.ROUNDED)
@@ -478,8 +480,8 @@ public class CamelCatalogTui extends CamelCommand {
 
     private void renderOptionsTable(Frame frame, Rect area) {
         Style borderStyle = focus == FOCUS_OPTIONS
-                ? Style.create().fg(Color.rgb(0xF6, 0x91, 0x23))
-                : Style.create();
+                ? Style.EMPTY.fg(Color.rgb(0xF6, 0x91, 0x23))
+                : Style.EMPTY;
 
         String optModePrefix = optionFullText ? "/" : "";
         String optTitle = optionFilter.isEmpty() && !optionFullText
@@ -491,7 +493,7 @@ public class CamelCatalogTui extends CamelCommand {
             frame.renderWidget(
                     Paragraph.builder()
                             .text(Text.from(Line.from(
-                                    Span.styled(emptyMsg, 
Style.create().dim()))))
+                                    Span.styled(emptyMsg, Style.EMPTY.dim()))))
                             .block(Block.builder()
                                     .borderType(BorderType.ROUNDED)
                                     .borderStyle(borderStyle)
@@ -508,11 +510,11 @@ public class CamelCatalogTui extends CamelCommand {
         }
 
         Row header = Row.from(
-                Cell.from(Span.styled("NAME", Style.create().bold())),
-                Cell.from(Span.styled("TYPE", Style.create().bold())),
-                Cell.from(Span.styled("REQ", Style.create().bold())),
-                Cell.from(Span.styled("DEFAULT", Style.create().bold())),
-                Cell.from(Span.styled("KIND", Style.create().bold())));
+                Cell.from(Span.styled("NAME", Style.EMPTY.bold())),
+                Cell.from(Span.styled("TYPE", Style.EMPTY.bold())),
+                Cell.from(Span.styled("REQ", Style.EMPTY.bold())),
+                Cell.from(Span.styled("DEFAULT", Style.EMPTY.bold())),
+                Cell.from(Span.styled("KIND", Style.EMPTY.bold())));
 
         Table table = Table.builder()
                 .rows(rows)
@@ -523,7 +525,7 @@ public class CamelCatalogTui extends CamelCommand {
                         Constraint.length(4),
                         Constraint.length(12),
                         Constraint.fill())
-                .highlightStyle(Style.create().fg(Color.WHITE).bold().onBlue())
+                .highlightStyle(Style.EMPTY.fg(Color.WHITE).bold().onBlue())
                 .highlightSpacing(Table.HighlightSpacing.ALWAYS)
                 .block(Block.builder()
                         .borderType(BorderType.ROUNDED)
@@ -536,9 +538,11 @@ public class CamelCatalogTui extends CamelCommand {
     }
 
     private void renderSeparator(Frame frame, Rect area) {
-        String line = "\u2500".repeat(Math.max(0, area.width()));
         frame.renderWidget(
-                Paragraph.from(Line.from(Span.styled(line, 
Style.create().fg(Color.DARK_GRAY)))),
+                Block.builder()
+                        .borders(Borders.TOP_ONLY)
+                        .borderStyle(Style.EMPTY.fg(Color.DARK_GRAY))
+                        .build(),
                 area);
     }
 
@@ -573,7 +577,9 @@ public class CamelCatalogTui extends CamelCommand {
                 flowFields(lines, fields, wrapWidth, opt);
 
                 lines.add(Line.from(Span.raw("")));
-                wrapText(lines, opt.description, wrapWidth, Style.create());
+                if (opt.description != null && !opt.description.isEmpty()) {
+                    lines.add(Line.from(Span.raw(" " + opt.description)));
+                }
             } else {
                 title = " Description ";
             }
@@ -598,32 +604,19 @@ public class CamelCatalogTui extends CamelCommand {
                 flowFields(lines, fields, wrapWidth, null);
 
                 lines.add(Line.from(Span.raw("")));
-                wrapText(lines, comp.description, wrapWidth, Style.create());
+                if (comp.description != null && !comp.description.isEmpty()) {
+                    lines.add(Line.from(Span.raw(" " + comp.description)));
+                }
             } else {
                 title = " Description ";
             }
         }
 
-        // Apply scroll
-        int innerHeight = Math.max(1, area.height() - 2);
-        int maxScroll = Math.max(0, lines.size() - innerHeight);
-        if (descriptionScroll > maxScroll) {
-            descriptionScroll = maxScroll;
-        }
-        List<Line> visible;
-        if (descriptionScroll > 0) {
-            int end = Math.min(descriptionScroll + innerHeight, lines.size());
-            visible = lines.subList(descriptionScroll, end);
-        } else if (lines.size() > innerHeight) {
-            visible = lines.subList(0, innerHeight);
-        } else {
-            visible = lines;
-        }
-
         frame.renderWidget(
                 Paragraph.builder()
-                        .text(Text.from(visible))
-                        .overflow(Overflow.CLIP)
+                        .text(Text.from(lines))
+                        .overflow(Overflow.WRAP_WORD)
+                        .scroll(descriptionScroll)
                         .block(Block.builder()
                                 .borderType(BorderType.ROUNDED)
                                 .title(title)
@@ -634,34 +627,34 @@ public class CamelCatalogTui extends CamelCommand {
 
     private Row optionToRow(OptionInfo opt) {
         Style nameStyle = opt.required
-                ? Style.create().fg(Color.CYAN).bold()
-                : Style.create().fg(Color.CYAN);
+                ? Style.EMPTY.fg(Color.CYAN).bold()
+                : Style.EMPTY.fg(Color.CYAN);
 
         return Row.from(
                 Cell.from(Span.styled(opt.name, nameStyle)),
-                Cell.from(Span.styled(opt.type, Style.create().dim())),
+                Cell.from(Span.styled(opt.type, Style.EMPTY.dim())),
                 Cell.from(opt.required
-                        ? Span.styled("*", Style.create().fg(Color.RED).bold())
+                        ? Span.styled("*", Style.EMPTY.fg(Color.RED).bold())
                         : Span.raw("")),
-                Cell.from(Span.styled(opt.defaultValue, Style.create().dim())),
-                Cell.from(Span.styled(opt.kind != null ? opt.kind : "", 
Style.create().dim())));
+                Cell.from(Span.styled(opt.defaultValue, Style.EMPTY.dim())),
+                Cell.from(Span.styled(opt.kind != null ? opt.kind : "", 
Style.EMPTY.dim())));
     }
 
     private void renderFooter(Frame frame, Rect area) {
         Line footer = Line.from(
-                Span.styled(" Type", Style.create().fg(Color.YELLOW).bold()),
+                Span.styled(" Type", Style.EMPTY.fg(Color.YELLOW).bold()),
                 Span.raw(" name filter  "),
-                Span.styled("/", Style.create().fg(Color.YELLOW).bold()),
+                Span.styled("/", Style.EMPTY.fg(Color.YELLOW).bold()),
                 Span.raw(" full-text  "),
-                Span.styled("Esc", Style.create().fg(Color.YELLOW).bold()),
+                Span.styled("Esc", Style.EMPTY.fg(Color.YELLOW).bold()),
                 Span.raw(" clear/back/quit  "),
-                Span.styled("\u2191\u2193", 
Style.create().fg(Color.YELLOW).bold()),
+                Span.styled("\u2191\u2193", 
Style.EMPTY.fg(Color.YELLOW).bold()),
                 Span.raw(" navigate  "),
-                Span.styled("\u2190\u2192", 
Style.create().fg(Color.YELLOW).bold()),
+                Span.styled("\u2190\u2192", 
Style.EMPTY.fg(Color.YELLOW).bold()),
                 Span.raw("/"),
-                Span.styled("Tab", Style.create().fg(Color.YELLOW).bold()),
+                Span.styled("Tab", Style.EMPTY.fg(Color.YELLOW).bold()),
                 Span.raw(" panels  "),
-                Span.styled("PgUp/Dn", Style.create().fg(Color.YELLOW).bold()),
+                Span.styled("PgUp/Dn", Style.EMPTY.fg(Color.YELLOW).bold()),
                 Span.raw(" scroll"));
 
         frame.renderWidget(Paragraph.from(footer), area);
@@ -677,10 +670,10 @@ public class CamelCatalogTui extends CamelCommand {
         for (String[] field : fields) {
             String label = field[0] + ": ";
             String value = field[1];
-            int fieldLen = label.length() + value.length();
+            int fieldLen = CharWidth.of(label) + CharWidth.of(value);
 
             // If adding this field would exceed width, flush current line
-            if (!currentSpans.isEmpty() && currentLen + gap.length() + 
fieldLen > maxWidth) {
+            if (!currentSpans.isEmpty() && currentLen + CharWidth.of(gap) + 
fieldLen > maxWidth) {
                 lines.add(Line.from(currentSpans));
                 currentSpans = new ArrayList<>();
                 currentLen = 1;
@@ -688,25 +681,25 @@ public class CamelCatalogTui extends CamelCommand {
 
             if (!currentSpans.isEmpty()) {
                 currentSpans.add(Span.raw(gap));
-                currentLen += gap.length();
+                currentLen += CharWidth.of(gap);
             } else {
                 currentSpans.add(Span.raw(" "));
             }
 
-            currentSpans.add(Span.styled(label, 
Style.create().fg(Color.YELLOW).bold()));
+            currentSpans.add(Span.styled(label, 
Style.EMPTY.fg(Color.YELLOW).bold()));
 
             // Apply special styling for certain values
             Style valueStyle;
             if ("DEPRECATED".equals(value)) {
-                valueStyle = Style.create().fg(Color.RED).bold();
+                valueStyle = Style.EMPTY.fg(Color.RED).bold();
             } else if (opt != null && "Required".equals(field[0]) && 
opt.required) {
-                valueStyle = Style.create().fg(Color.RED).bold();
+                valueStyle = Style.EMPTY.fg(Color.RED).bold();
             } else if (opt != null && "Name".equals(field[0])) {
-                valueStyle = Style.create().fg(Color.CYAN).bold();
+                valueStyle = Style.EMPTY.fg(Color.CYAN).bold();
             } else if ("Label".equals(field[0]) || "Values".equals(field[0])) {
-                valueStyle = Style.create().fg(Color.CYAN);
+                valueStyle = Style.EMPTY.fg(Color.CYAN);
             } else {
-                valueStyle = Style.create();
+                valueStyle = Style.EMPTY;
             }
             currentSpans.add(Span.styled(value, valueStyle));
             currentLen += fieldLen;
@@ -717,24 +710,6 @@ public class CamelCatalogTui extends CamelCommand {
         }
     }
 
-    private static void wrapText(List<Line> lines, String text, int width, 
Style style) {
-        if (text == null || text.isEmpty()) {
-            return;
-        }
-        int pos = 0;
-        while (pos < text.length()) {
-            int end = Math.min(pos + width, text.length());
-            if (end < text.length() && end > pos) {
-                int lastSpace = text.lastIndexOf(' ', end);
-                if (lastSpace > pos) {
-                    end = lastSpace + 1;
-                }
-            }
-            lines.add(Line.from(Span.styled(" " + text.substring(pos, 
end).trim(), style)));
-            pos = end;
-        }
-    }
-
     // ---- Data Classes ----
 
     static class ComponentInfo {
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 8b3f9e9a3fc4..0984a3e65fff 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
@@ -32,6 +32,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -49,12 +50,13 @@ import dev.tamboui.style.Color;
 import dev.tamboui.style.Overflow;
 import dev.tamboui.style.Style;
 import dev.tamboui.terminal.Frame;
+import dev.tamboui.text.CharWidth;
 import dev.tamboui.text.Line;
 import dev.tamboui.text.Span;
 import dev.tamboui.text.Text;
+import dev.tamboui.tui.TuiConfig;
 import dev.tamboui.tui.TuiRunner;
 import dev.tamboui.tui.event.Event;
-import dev.tamboui.tui.event.KeyCode;
 import dev.tamboui.tui.event.KeyEvent;
 import dev.tamboui.tui.event.MouseEvent;
 import dev.tamboui.tui.event.MouseEventKind;
@@ -131,6 +133,8 @@ public class CamelMonitor extends CamelCommand {
     private final TableState routeTableState = new TableState();
     private final TableState healthTableState = new TableState();
     private final TableState endpointTableState = new TableState();
+    private final TableState processorTableState = new TableState();
+    private final TableState routeHeaderTableState = new TableState();
     private final TabsState tabsState = new TabsState(TAB_OVERVIEW);
 
     // Sparkline: throughput history per PID (one point per second)
@@ -148,8 +152,8 @@ public class CamelMonitor extends CamelCommand {
     private boolean showOnlyDown;
 
     // Log state
-    private final List<String> logLines = new ArrayList<>();
-    private final List<LogEntry> filteredLogEntries = new ArrayList<>();
+    private List<String> logLines = new ArrayList<>();
+    private volatile List<LogEntry> filteredLogEntries = new ArrayList<>();
     private final TableState logTableState = new TableState();
     private boolean logFollowMode = true;
     private boolean showLogTrace = true;
@@ -187,6 +191,9 @@ public class CamelMonitor extends CamelCommand {
     private int diagramCropH = -1;
 
     private volatile long lastRefresh;
+    private final AtomicBoolean refreshInProgress = new AtomicBoolean(false);
+    private final AtomicBoolean diagramLoading = new AtomicBoolean(false);
+    private TuiRunner runner;
 
     private ClassLoader classLoader;
 
@@ -203,16 +210,19 @@ public class CamelMonitor extends CamelCommand {
         Thread.currentThread().setContextClassLoader(classLoader);
         TuiHelper.preloadClasses(classLoader);
 
-        // Initial data load
-        refreshData();
+        // Initial data load (synchronous before TUI starts)
+        refreshDataSync();
 
-        try (var tui = TuiRunner.create()) {
+        try (var tui = 
TuiRunner.create(TuiConfig.builder().mouseCapture(true).build())) {
+            this.runner = tui;
             // Intercept Ctrl+C: quit the TUI cleanly instead of letting
             // the JVM tear down the classloader while we're still running
             Signal.handle(new Signal("INT"), sig -> tui.quit());
             tui.run(
                     this::handleEvent,
                     this::render);
+        } finally {
+            this.runner = null;
         }
         return 0;
     }
@@ -234,7 +244,7 @@ public class CamelMonitor extends CamelCommand {
         }
         if (event instanceof KeyEvent ke) {
             // Global keys
-            if (ke.isQuit() || ke.isCharIgnoreCase('q') || 
ke.isKey(KeyCode.ESCAPE)) {
+            if (ke.isQuit() || ke.isCharIgnoreCase('q') || ke.isCancel()) {
                 if (showDiagram) {
                     showDiagram = false;
                     diagramImageData = null;
@@ -276,7 +286,7 @@ public class CamelMonitor extends CamelCommand {
             }
 
             // Tab cycling
-            if (ke.isKey(KeyCode.TAB)) {
+            if (ke.isFocusNext()) {
                 int next = (tabsState.selected() + 1) % NUM_TABS;
                 if (next != TAB_OVERVIEW) {
                     selectCurrentIntegration();
@@ -305,7 +315,7 @@ public class CamelMonitor extends CamelCommand {
                 }
                 return true;
             }
-            if (ke.isKey(KeyCode.PAGE_UP)) {
+            if (ke.isPageUp()) {
                 if (showDiagram && tab == TAB_ROUTES) {
                     diagramScroll = Math.max(0, diagramScroll - 20);
                 } else if (tab == TAB_LOG) {
@@ -316,7 +326,7 @@ public class CamelMonitor extends CamelCommand {
                 }
                 return true;
             }
-            if (ke.isKey(KeyCode.PAGE_DOWN)) {
+            if (ke.isPageDown()) {
                 if (showDiagram && tab == TAB_ROUTES) {
                     diagramScroll += 20;
                 } else if (tab == TAB_LOG) {
@@ -338,14 +348,14 @@ public class CamelMonitor extends CamelCommand {
                     return true;
                 }
             }
-            if (ke.isKey(KeyCode.HOME)) {
+            if (ke.isHome()) {
                 if (showDiagram && tab == TAB_ROUTES) {
                     diagramScroll = 0;
                     diagramScrollX = 0;
                     return true;
                 }
             }
-            if (ke.isKey(KeyCode.END)) {
+            if (ke.isEnd()) {
                 if (showDiagram && tab == TAB_ROUTES) {
                     diagramScroll = Integer.MAX_VALUE;
                     return true;
@@ -353,7 +363,7 @@ public class CamelMonitor extends CamelCommand {
             }
 
             // Enter to drill into selected integration
-            if (ke.isKey(KeyCode.ENTER) && tab == TAB_OVERVIEW) {
+            if (ke.isConfirm() && tab == TAB_OVERVIEW) {
                 selectCurrentIntegration();
                 if (selectedPid != null) {
                     tabsState.select(TAB_ROUTES);
@@ -400,39 +410,39 @@ public class CamelMonitor extends CamelCommand {
             if (tab == TAB_LOG) {
                 if (ke.isCharIgnoreCase('t')) {
                     showLogTrace = !showLogTrace;
-                    applyLogFilters();
+                    filteredLogEntries = applyLogFilters(logLines);
                     return true;
                 }
                 if (ke.isCharIgnoreCase('d')) {
                     showLogDebug = !showLogDebug;
-                    applyLogFilters();
+                    filteredLogEntries = applyLogFilters(logLines);
                     return true;
                 }
                 if (ke.isCharIgnoreCase('i')) {
                     showLogInfo = !showLogInfo;
-                    applyLogFilters();
+                    filteredLogEntries = applyLogFilters(logLines);
                     return true;
                 }
                 if (ke.isCharIgnoreCase('w')) {
                     showLogWarn = !showLogWarn;
-                    applyLogFilters();
+                    filteredLogEntries = applyLogFilters(logLines);
                     return true;
                 }
                 if (ke.isCharIgnoreCase('e')) {
                     showLogError = !showLogError;
-                    applyLogFilters();
+                    filteredLogEntries = applyLogFilters(logLines);
                     return true;
                 }
                 if (ke.isCharIgnoreCase('f')) {
                     logFollowMode = !logFollowMode;
                     return true;
                 }
-                if (ke.isChar('g')) {
+                if (ke.isHome()) {
                     logFollowMode = false;
                     logTableState.select(0);
                     return true;
                 }
-                if (ke.isChar('G')) {
+                if (ke.isEnd()) {
                     logFollowMode = true;
                     return true;
                 }
@@ -563,11 +573,11 @@ public class CamelMonitor extends CamelCommand {
         long activeCount = infos.stream().filter(i -> !i.vanishing).count();
 
         Line titleLine = Line.from(
-                Span.styled(" Camel Monitor", 
Style.create().fg(Color.rgb(0xF6, 0x91, 0x23)).bold()),
+                Span.styled(" Camel Monitor", Style.EMPTY.fg(Color.rgb(0xF6, 
0x91, 0x23)).bold()),
                 Span.raw("  "),
-                Span.styled(camelVersion != null ? "v" + camelVersion : "", 
Style.create().fg(Color.GREEN)),
+                Span.styled(camelVersion != null ? "v" + camelVersion : "", 
Style.EMPTY.fg(Color.GREEN)),
                 Span.raw("  "),
-                Span.styled(activeCount + " integration(s)", 
Style.create().fg(Color.CYAN)));
+                Span.styled(activeCount + " integration(s)", 
Style.EMPTY.fg(Color.CYAN)));
 
         Block headerBlock = Block.builder()
                 .borderType(BorderType.ROUNDED)
@@ -589,8 +599,8 @@ public class CamelMonitor extends CamelCommand {
                         " 4 Endpoints" + sel + " ",
                         " 5 Log" + sel + " ",
                         " 6 Trace" + sel + " ")
-                .highlightStyle(Style.create().fg(Color.rgb(0xF6, 0x91, 
0x23)).bold())
-                .divider(Span.styled(" | ", Style.create().dim()))
+                .highlightStyle(Style.EMPTY.fg(Color.rgb(0xF6, 0x91, 
0x23)).bold())
+                .divider(Span.styled(" | ", Style.EMPTY.dim()))
                 .build();
 
         frame.renderStatefulWidget(tabs, area, tabsState);
@@ -630,7 +640,7 @@ public class CamelMonitor extends CamelCommand {
                 long elapsed = System.currentTimeMillis() - info.vanishStart;
                 float fade = 1.0f - Math.min(1.0f, (float) elapsed / 
VANISH_DURATION_MS);
                 int gray = (int) (100 * fade);
-                Style dimStyle = Style.create().fg(Color.indexed(232 + 
Math.min(gray / 4, 23)));
+                Style dimStyle = Style.EMPTY.fg(Color.indexed(232 + 
Math.min(gray / 4, 23)));
 
                 rows.add(Row.from(
                         Cell.from(Span.styled(info.pid, dimStyle)),
@@ -638,7 +648,7 @@ public class CamelMonitor extends CamelCommand {
                         Cell.from(Span.styled("", dimStyle)),
                         Cell.from(Span.styled("", dimStyle)),
                         Cell.from(Span.styled("", dimStyle)),
-                        Cell.from(Span.styled("\u2716 Stopped", 
Style.create().fg(Color.RED).dim())),
+                        Cell.from(Span.styled("\u2716 Stopped", 
Style.EMPTY.fg(Color.RED).dim())),
                         Cell.from(Span.styled("", dimStyle)),
                         Cell.from(Span.styled(info.ago != null ? info.ago : 
"", dimStyle)),
                         Cell.from(Span.styled("", dimStyle)),
@@ -652,9 +662,9 @@ public class CamelMonitor extends CamelCommand {
                         Cell.from(Span.styled("", dimStyle))));
             } else {
                 Style statusStyle = switch (extractState(info.state)) {
-                    case "Started" -> Style.create().fg(Color.GREEN);
-                    case "Stopped" -> Style.create().fg(Color.RED);
-                    default -> Style.create().fg(Color.YELLOW);
+                    case "Started" -> Style.EMPTY.fg(Color.GREEN);
+                    case "Stopped" -> Style.EMPTY.fg(Color.RED);
+                    default -> Style.EMPTY.fg(Color.YELLOW);
                 };
 
                 String platformDisplay = info.platform != null ? info.platform 
: "";
@@ -662,13 +672,13 @@ public class CamelMonitor extends CamelCommand {
                     platformDisplay += " " + info.platformVersion;
                 }
 
-                Style failStyle = info.failed > 0 ? 
Style.create().fg(Color.RED).bold() : Style.create();
+                Style failStyle = info.failed > 0 ? 
Style.EMPTY.fg(Color.RED).bold() : Style.EMPTY;
 
                 String sinceLastDisplay = formatSinceLast(info);
 
                 rows.add(Row.from(
                         Cell.from(info.pid),
-                        Cell.from(Span.styled(info.name != null ? info.name : 
"", Style.create().fg(Color.CYAN))),
+                        Cell.from(Span.styled(info.name != null ? info.name : 
"", Style.EMPTY.fg(Color.CYAN))),
                         Cell.from(info.camelVersion != null ? 
info.camelVersion : ""),
                         Cell.from(platformDisplay),
                         Cell.from(info.ready != null ? info.ready : ""),
@@ -688,23 +698,23 @@ public class CamelMonitor extends CamelCommand {
         }
 
         Row header = Row.from(
-                Cell.from(Span.styled("PID", Style.create().bold())),
-                Cell.from(Span.styled("NAME", Style.create().bold())),
-                Cell.from(Span.styled("CAMEL", Style.create().bold())),
-                Cell.from(Span.styled("PLATFORM", Style.create().bold())),
-                Cell.from(Span.styled("READY", Style.create().bold())),
-                Cell.from(Span.styled("STATUS", Style.create().bold())),
-                Cell.from(Span.styled("RELOAD", Style.create().bold())),
-                Cell.from(Span.styled("AGE", Style.create().bold())),
-                Cell.from(Span.styled("ROUTE", Style.create().bold())),
-                Cell.from(Span.styled("MSG/S", Style.create().bold())),
-                Cell.from(Span.styled("TOTAL", Style.create().bold())),
-                Cell.from(Span.styled("FAIL", Style.create().bold())),
-                Cell.from(Span.styled("INFLIGHT", Style.create().bold())),
-                Cell.from(Span.styled("LAST", Style.create().bold())),
-                Cell.from(Span.styled("SINCE-LAST", Style.create().bold())),
-                Cell.from(Span.styled("HEAP", Style.create().bold())),
-                Cell.from(Span.styled("THREADS", Style.create().bold())));
+                Cell.from(Span.styled("PID", Style.EMPTY.bold())),
+                Cell.from(Span.styled("NAME", Style.EMPTY.bold())),
+                Cell.from(Span.styled("CAMEL", Style.EMPTY.bold())),
+                Cell.from(Span.styled("PLATFORM", Style.EMPTY.bold())),
+                Cell.from(Span.styled("READY", Style.EMPTY.bold())),
+                Cell.from(Span.styled("STATUS", Style.EMPTY.bold())),
+                Cell.from(Span.styled("RELOAD", Style.EMPTY.bold())),
+                Cell.from(Span.styled("AGE", Style.EMPTY.bold())),
+                Cell.from(Span.styled("ROUTE", Style.EMPTY.bold())),
+                Cell.from(Span.styled("MSG/S", Style.EMPTY.bold())),
+                Cell.from(Span.styled("TOTAL", Style.EMPTY.bold())),
+                Cell.from(Span.styled("FAIL", Style.EMPTY.bold())),
+                Cell.from(Span.styled("INFLIGHT", Style.EMPTY.bold())),
+                Cell.from(Span.styled("LAST", Style.EMPTY.bold())),
+                Cell.from(Span.styled("SINCE-LAST", Style.EMPTY.bold())),
+                Cell.from(Span.styled("HEAP", Style.EMPTY.bold())),
+                Cell.from(Span.styled("THREADS", Style.EMPTY.bold())));
 
         Table table = Table.builder()
                 .rows(rows)
@@ -727,7 +737,7 @@ public class CamelMonitor extends CamelCommand {
                         Constraint.length(12),
                         Constraint.length(14),
                         Constraint.length(10))
-                .highlightStyle(Style.create().fg(Color.WHITE).bold().onBlue())
+                .highlightStyle(Style.EMPTY.fg(Color.WHITE).bold().onBlue())
                 .highlightSpacing(Table.HighlightSpacing.ALWAYS)
                 .block(Block.builder().borderType(BorderType.ROUNDED).title(" 
Integrations ").build())
                 .build();
@@ -763,7 +773,7 @@ public class CamelMonitor extends CamelCommand {
                     .max(maxTp > 0 ? maxTp + 2 : 2)
                     .barWidth(1)
                     .barGap(0)
-                    .barStyle(Style.create().fg(Color.GREEN))
+                    .barStyle(Style.EMPTY.fg(Color.GREEN))
                     
.block(Block.builder().borderType(BorderType.ROUNDED).title(chartTitle).build())
                     .build();
 
@@ -804,15 +814,15 @@ public class CamelMonitor extends CamelCommand {
         List<Row> routeRows = new ArrayList<>();
         for (RouteInfo route : sortedRoutes) {
             Style stateStyle = "Started".equals(route.state)
-                    ? Style.create().fg(Color.GREEN)
-                    : Style.create().fg(Color.RED);
+                    ? Style.EMPTY.fg(Color.GREEN)
+                    : Style.EMPTY.fg(Color.RED);
 
             Style failStyle = route.failed > 0
-                    ? Style.create().fg(Color.RED).bold()
-                    : Style.create();
+                    ? Style.EMPTY.fg(Color.RED).bold()
+                    : Style.EMPTY;
 
             routeRows.add(Row.from(
-                    Cell.from(Span.styled(route.routeId != null ? 
route.routeId : "", Style.create().fg(Color.CYAN))),
+                    Cell.from(Span.styled(route.routeId != null ? 
route.routeId : "", Style.EMPTY.fg(Color.CYAN))),
                     Cell.from(route.from != null ? route.from : ""),
                     Cell.from(Span.styled(route.state != null ? route.state : 
"", stateStyle)),
                     Cell.from(route.uptime != null ? route.uptime : ""),
@@ -825,11 +835,11 @@ public class CamelMonitor extends CamelCommand {
         Table routeTable = Table.builder()
                 .rows(routeRows)
                 .header(Row.from(
-                        Cell.from(Span.styled("ROUTE", Style.create().bold())),
-                        Cell.from(Span.styled("FROM", Style.create().bold())),
-                        Cell.from(Span.styled("STATE", Style.create().bold())),
-                        Cell.from(Span.styled("UPTIME", 
Style.create().bold())),
-                        Cell.from(Span.styled("THRUPUT", 
Style.create().bold())),
+                        Cell.from(Span.styled("ROUTE", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("FROM", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("STATE", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("UPTIME", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("THRUPUT", Style.EMPTY.bold())),
                         Cell.from(Span.styled(routeSortLabel("TOTAL", 
"total"), routeSortStyle("total"))),
                         Cell.from(Span.styled(routeSortLabel("FAILED", 
"failed"), routeSortStyle("failed"))),
                         Cell.from(Span.styled(routeSortLabel("MEAN/MAX", 
"mean"), routeSortStyle("mean")))))
@@ -842,7 +852,7 @@ public class CamelMonitor extends CamelCommand {
                         Constraint.length(8),
                         Constraint.length(8),
                         Constraint.length(12))
-                .highlightStyle(Style.create().fg(Color.WHITE).bold().onBlue())
+                .highlightStyle(Style.EMPTY.fg(Color.WHITE).bold().onBlue())
                 .highlightSpacing(Table.HighlightSpacing.ALWAYS)
                 .block(Block.builder().borderType(BorderType.ROUNDED)
                         .title(" Routes [" + info.name + "] sort:" + routeSort 
+ " ").build())
@@ -863,7 +873,7 @@ public class CamelMonitor extends CamelCommand {
             } else {
                 frame.renderWidget(
                         Paragraph.builder()
-                                .text(Text.from(Line.from(Span.styled("No 
routes", Style.create().dim()))))
+                                .text(Text.from(Line.from(Span.styled("No 
routes", Style.EMPTY.dim()))))
                                 
.block(Block.builder().borderType(BorderType.ROUNDED).title(" Processors 
").build())
                                 .build(),
                         chunks.get(1));
@@ -892,22 +902,22 @@ public class CamelMonitor extends CamelCommand {
 
     private Style routeSortStyle(String column) {
         return routeSort.equals(column)
-                ? Style.create().fg(Color.YELLOW).bold()
-                : Style.create().bold();
+                ? Style.EMPTY.fg(Color.YELLOW).bold()
+                : Style.EMPTY.bold();
     }
 
     private void renderProcessors(Frame frame, Rect area, RouteInfo route) {
         List<Row> rows = new ArrayList<>();
         for (ProcessorInfo proc : route.processors) {
             String indent = "  ".repeat(proc.level);
-            Style nameStyle = proc.failed > 0 ? Style.create().fg(Color.RED) : 
Style.create().fg(Color.CYAN);
+            Style nameStyle = proc.failed > 0 ? Style.EMPTY.fg(Color.RED) : 
Style.EMPTY.fg(Color.CYAN);
 
             rows.add(Row.from(
                     Cell.from(Span.styled(indent + (proc.id != null ? proc.id 
: ""), nameStyle)),
                     Cell.from(proc.processor != null ? proc.processor : ""),
                     Cell.from(String.valueOf(proc.total)),
                     Cell.from(proc.failed > 0
-                            ? Span.styled(String.valueOf(proc.failed), 
Style.create().fg(Color.RED))
+                            ? Span.styled(String.valueOf(proc.failed), 
Style.EMPTY.fg(Color.RED))
                             : Span.raw("0")),
                     Cell.from(proc.meanTime + "ms"),
                     Cell.from(proc.maxTime + "ms"),
@@ -917,13 +927,13 @@ public class CamelMonitor extends CamelCommand {
         Table table = Table.builder()
                 .rows(rows)
                 .header(Row.from(
-                        Cell.from(Span.styled("PROCESSOR", 
Style.create().bold())),
-                        Cell.from(Span.styled("TYPE", Style.create().bold())),
-                        Cell.from(Span.styled("TOTAL", Style.create().bold())),
-                        Cell.from(Span.styled("FAILED", 
Style.create().bold())),
-                        Cell.from(Span.styled("MEAN", Style.create().bold())),
-                        Cell.from(Span.styled("MAX", Style.create().bold())),
-                        Cell.from(Span.styled("LAST", Style.create().bold()))))
+                        Cell.from(Span.styled("PROCESSOR", 
Style.EMPTY.bold())),
+                        Cell.from(Span.styled("TYPE", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("TOTAL", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("FAILED", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("MEAN", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("MAX", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("LAST", Style.EMPTY.bold()))))
                 .widths(
                         Constraint.fill(),
                         Constraint.length(15),
@@ -936,7 +946,7 @@ public class CamelMonitor extends CamelCommand {
                         .title(" Processors [" + route.routeId + "] ").build())
                 .build();
 
-        frame.renderStatefulWidget(table, area, new TableState());
+        frame.renderStatefulWidget(table, area, processorTableState);
     }
 
     private void renderRouteHeader(Frame frame, Rect area, IntegrationInfo 
info) {
@@ -953,13 +963,13 @@ public class CamelMonitor extends CamelCommand {
         List<Row> rows = new ArrayList<>();
         if (route != null) {
             Style stateStyle = "Started".equals(route.state)
-                    ? Style.create().fg(Color.GREEN)
-                    : Style.create().fg(Color.RED);
+                    ? Style.EMPTY.fg(Color.GREEN)
+                    : Style.EMPTY.fg(Color.RED);
             Style failStyle = route.failed > 0
-                    ? Style.create().fg(Color.RED).bold()
-                    : Style.create();
+                    ? Style.EMPTY.fg(Color.RED).bold()
+                    : Style.EMPTY;
             rows.add(Row.from(
-                    Cell.from(Span.styled(route.routeId != null ? 
route.routeId : "", Style.create().fg(Color.CYAN))),
+                    Cell.from(Span.styled(route.routeId != null ? 
route.routeId : "", Style.EMPTY.fg(Color.CYAN))),
                     Cell.from(route.from != null ? route.from : ""),
                     Cell.from(Span.styled(route.state != null ? route.state : 
"", stateStyle)),
                     Cell.from(route.uptime != null ? route.uptime : ""),
@@ -972,14 +982,14 @@ public class CamelMonitor extends CamelCommand {
         Table table = Table.builder()
                 .rows(rows)
                 .header(Row.from(
-                        Cell.from(Span.styled("ROUTE", Style.create().bold())),
-                        Cell.from(Span.styled("FROM", Style.create().bold())),
-                        Cell.from(Span.styled("STATE", Style.create().bold())),
-                        Cell.from(Span.styled("UPTIME", 
Style.create().bold())),
-                        Cell.from(Span.styled("THRUPUT", 
Style.create().bold())),
-                        Cell.from(Span.styled("TOTAL", Style.create().bold())),
-                        Cell.from(Span.styled("FAILED", 
Style.create().bold())),
-                        Cell.from(Span.styled("MEAN/MAX", 
Style.create().bold()))))
+                        Cell.from(Span.styled("ROUTE", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("FROM", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("STATE", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("UPTIME", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("THRUPUT", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("TOTAL", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("FAILED", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("MEAN/MAX", 
Style.EMPTY.bold()))))
                 .widths(
                         Constraint.length(12),
                         Constraint.fill(),
@@ -989,12 +999,12 @@ public class CamelMonitor extends CamelCommand {
                         Constraint.length(8),
                         Constraint.length(8),
                         Constraint.length(12))
-                .highlightStyle(Style.create().fg(Color.WHITE).bold().onBlue())
+                .highlightStyle(Style.EMPTY.fg(Color.WHITE).bold().onBlue())
                 .block(Block.builder().borderType(BorderType.ROUNDED)
                         .title(" Route [" + info.name + "] ").build())
                 .build();
 
-        frame.renderStatefulWidget(table, area, new TableState());
+        frame.renderStatefulWidget(table, area, routeHeaderTableState);
     }
 
     private void renderDiagram(Frame frame, Rect area) {
@@ -1011,7 +1021,7 @@ public class CamelMonitor extends CamelCommand {
         // Compute max width for horizontal scrolling
         int maxWidth = 0;
         for (String line : diagramLines) {
-            maxWidth = Math.max(maxWidth, line.length());
+            maxWidth = Math.max(maxWidth, CharWidth.of(line));
         }
 
         Rect inner = block.inner(area);
@@ -1059,9 +1069,7 @@ public class CamelMonitor extends CamelCommand {
         diagramVScrollState.viewportContentLength(visibleLines);
         diagramVScrollState.position(diagramScroll);
         frame.renderStatefulWidget(
-                Scrollbar.builder()
-                        .thumbStyle(Style.create().fg(Color.rgb(0xF6, 0x91, 
0x23)))
-                        .build(),
+                Scrollbar.builder().build(),
                 hChunks.get(1), diagramVScrollState);
 
         // Render horizontal scrollbar
@@ -1140,9 +1148,7 @@ public class CamelMonitor extends CamelCommand {
         diagramVScrollState.viewportContentLength(viewRows);
         diagramVScrollState.position(diagramScroll);
         frame.renderStatefulWidget(
-                Scrollbar.builder()
-                        .thumbStyle(Style.create().fg(Color.rgb(0xF6, 0x91, 
0x23)))
-                        .build(),
+                Scrollbar.builder().build(),
                 hChunks.get(1), diagramVScrollState);
 
         // Render horizontal scrollbar
@@ -1163,27 +1169,27 @@ public class CamelMonitor extends CamelCommand {
         while (idx < text.length()) {
             int open = text.indexOf('[', idx);
             if (open < 0) {
-                spans.add(Span.styled(text.substring(idx), 
Style.create().fg(Color.WHITE)));
+                spans.add(Span.styled(text.substring(idx), 
Style.EMPTY.fg(Color.WHITE)));
                 break;
             }
             int close = text.indexOf(']', open);
             if (close < 0) {
-                spans.add(Span.styled(text.substring(idx), 
Style.create().fg(Color.WHITE)));
+                spans.add(Span.styled(text.substring(idx), 
Style.EMPTY.fg(Color.WHITE)));
                 break;
             }
             if (open > idx) {
-                spans.add(Span.styled(text.substring(idx, open), 
Style.create().fg(Color.GRAY)));
+                spans.add(Span.styled(text.substring(idx, open), 
Style.EMPTY.fg(Color.GRAY)));
             }
             String tag = text.substring(open + 1, close);
             Color tagColor = getDiagramNodeColor(tag);
-            spans.add(Span.styled("[" + tag + "]", 
Style.create().fg(tagColor).bold()));
+            spans.add(Span.styled("[" + tag + "]", 
Style.EMPTY.fg(tagColor).bold()));
 
             int afterTag = close + 1;
             int nextOpen = text.indexOf('[', afterTag);
             int nextNewline = text.length();
             int labelEnd = nextOpen >= 0 ? nextOpen : nextNewline;
             if (afterTag < labelEnd) {
-                spans.add(Span.styled(text.substring(afterTag, labelEnd), 
Style.create().fg(Color.WHITE)));
+                spans.add(Span.styled(text.substring(afterTag, labelEnd), 
Style.EMPTY.fg(Color.WHITE)));
             }
             idx = labelEnd;
         }
@@ -1213,12 +1219,16 @@ public class CamelMonitor extends CamelCommand {
     }
 
     private void loadDiagramForSelectedRoute() {
-        if (selectedPid == null) {
+        if (selectedPid == null || runner == null) {
+            return;
+        }
+        if (!diagramLoading.compareAndSet(false, true)) {
             return;
         }
 
         IntegrationInfo info = findSelectedIntegration();
         if (info == null || info.routes.isEmpty()) {
+            diagramLoading.set(false);
             return;
         }
 
@@ -1233,7 +1243,31 @@ public class CamelMonitor extends CamelCommand {
             selectedRoute = sortedRoutes.get(0);
         }
 
-        Path outputFile = getOutputFile(selectedPid);
+        // Capture state needed by the background thread
+        String pid = selectedPid;
+        boolean textMode = diagramTextMode;
+        String routeId = selectedRoute.routeId;
+
+        // Show loading state immediately
+        diagramRouteId = routeId;
+        diagramLines = List.of("(Loading diagram...)");
+        diagramImageData = null;
+        diagramFullImageData = null;
+        showDiagram = true;
+        diagramScroll = 0;
+        diagramScrollX = 0;
+
+        runner.scheduler().execute(() -> {
+            try {
+                loadDiagramInBackground(pid, textMode, routeId);
+            } finally {
+                diagramLoading.set(false);
+            }
+        });
+    }
+
+    private void loadDiagramInBackground(String pid, boolean textMode, String 
routeId) {
+        Path outputFile = getOutputFile(pid);
         PathUtils.deleteFile(outputFile);
 
         JsonObject root = new JsonObject();
@@ -1242,38 +1276,32 @@ public class CamelMonitor extends CamelCommand {
         root.put("brief", false);
         root.put("metric", true);
 
-        Path actionFile = getActionFile(selectedPid);
+        Path actionFile = getActionFile(pid);
         
org.apache.camel.dsl.jbang.core.common.PathUtils.writeTextSafely(root.toJson(), 
actionFile);
 
         JsonObject jo = pollJsonResponse(outputFile, 5000);
         PathUtils.deleteFile(outputFile);
 
         if (jo == null) {
-            diagramLines = List.of("(No response from integration)");
-            diagramRouteId = selectedRoute.routeId;
-            showDiagram = true;
-            diagramScroll = 0;
+            applyDiagramResult(routeId, List.of("(No response from 
integration)"), null, null, null);
             return;
         }
 
         JsonArray arr = (JsonArray) jo.get("routes");
         if (arr == null) {
-            diagramLines = List.of("(No routes in response)");
-            diagramRouteId = selectedRoute.routeId;
-            showDiagram = true;
-            diagramScroll = 0;
+            applyDiagramResult(routeId, List.of("(No routes in response)"), 
null, null, null);
             return;
         }
 
         List<RouteDiagramLayoutEngine.RouteInfo> diagramRoutes = new 
ArrayList<>();
         for (int i = 0; i < arr.size(); i++) {
             JsonObject o = (JsonObject) arr.get(i);
-            String routeId = objToString(o.get("routeId"));
-            if (selectedRoute.routeId != null && 
!selectedRoute.routeId.equals(routeId)) {
+            String rid = objToString(o.get("routeId"));
+            if (routeId != null && !routeId.equals(rid)) {
                 continue;
             }
             RouteDiagramLayoutEngine.RouteInfo route = new 
RouteDiagramLayoutEngine.RouteInfo();
-            route.routeId = routeId;
+            route.routeId = rid;
             List<JsonObject> lines = o.getCollection("code");
             if (lines != null) {
                 for (JsonObject line : lines) {
@@ -1288,28 +1316,15 @@ public class CamelMonitor extends CamelCommand {
             diagramRoutes.add(route);
         }
 
-        diagramRouteId = selectedRoute.routeId;
-        diagramScroll = 0;
-        diagramScrollX = 0;
-        diagramCropX = -1;
-        diagramCropY = -1;
-        diagramCropW = -1;
-        diagramCropH = -1;
-
-        if (diagramTextMode) {
-            diagramImageData = null;
-            diagramFullImageData = null;
-            diagramProtocol = null;
-
+        if (textMode) {
             String ascii = renderAscii(diagramRoutes, 
RouteDiagramLayoutEngine.DEFAULT_BOX_WIDTH, "CODE", true);
-
             List<String> result = new ArrayList<>();
             for (String line : ascii.split("\n", -1)) {
                 if (!line.isEmpty()) {
                     result.add(line);
                 }
             }
-            diagramLines = result;
+            applyDiagramResult(routeId, result, null, null, null);
         } else {
             TerminalImageCapabilities caps = 
TerminalImageCapabilities.detect();
             if (caps.supportsNativeImages()) {
@@ -1325,21 +1340,36 @@ public class CamelMonitor extends CamelCommand {
                 RouteDiagramRenderer.DiagramColors colors = 
RouteDiagramRenderer.DiagramColors.parse("transparent");
                 java.awt.image.BufferedImage image = 
renderer.renderDiagram(layoutRoutes, totalHeight, colors);
                 ImageData fullImage = ImageData.fromBufferedImage(image);
-                diagramFullImageData = fullImage.resize(fullImage.width() / 2, 
fullImage.height() / 2);
-                diagramImageData = diagramFullImageData;
-                diagramProtocol = caps.bestProtocol();
-                diagramLines = Collections.emptyList();
+                ImageData resized = fullImage.resize(fullImage.width() / 2, 
fullImage.height() / 2);
+                ImageProtocol protocol = caps.bestProtocol();
+                applyDiagramResult(routeId, Collections.emptyList(), resized, 
resized, protocol);
             } else {
-                diagramImageData = null;
-                diagramFullImageData = null;
-                diagramProtocol = null;
-                diagramLines = List.of(
+                applyDiagramResult(routeId, List.of(
                         "(Terminal does not support image rendering)",
-                        "(Press Shift+D for text diagram)");
+                        "(Press Shift+D for text diagram)"), null, null, null);
             }
         }
+    }
 
-        showDiagram = true;
+    private void applyDiagramResult(
+            String routeId, List<String> lines, ImageData imageData, ImageData 
fullImageData, ImageProtocol protocol) {
+        if (runner == null) {
+            return;
+        }
+        runner.runOnRenderThread(() -> {
+            diagramRouteId = routeId;
+            diagramLines = lines;
+            diagramImageData = imageData;
+            diagramFullImageData = fullImageData;
+            diagramProtocol = protocol;
+            diagramScroll = 0;
+            diagramScrollX = 0;
+            diagramCropX = -1;
+            diagramCropY = -1;
+            diagramCropW = -1;
+            diagramCropH = -1;
+            showDiagram = true;
+        });
     }
 
     private static String renderAscii(
@@ -1401,13 +1431,13 @@ public class CamelMonitor extends CamelCommand {
             Style stateStyle;
             String icon;
             if ("UP".equals(hc.state)) {
-                stateStyle = Style.create().fg(Color.GREEN);
+                stateStyle = Style.EMPTY.fg(Color.GREEN);
                 icon = "\u2714 ";
             } else if ("DOWN".equals(hc.state)) {
-                stateStyle = Style.create().fg(Color.RED);
+                stateStyle = Style.EMPTY.fg(Color.RED);
                 icon = "\u2716 ";
             } else {
-                stateStyle = Style.create().fg(Color.YELLOW);
+                stateStyle = Style.EMPTY.fg(Color.YELLOW);
                 icon = "\u26A0 ";
             }
 
@@ -1420,8 +1450,8 @@ public class CamelMonitor extends CamelCommand {
             }
 
             rows.add(Row.from(
-                    Cell.from(Span.styled(hc.group != null ? hc.group : "", 
Style.create().dim())),
-                    Cell.from(Span.styled(hc.name != null ? hc.name : "", 
Style.create().fg(Color.CYAN))),
+                    Cell.from(Span.styled(hc.group != null ? hc.group : "", 
Style.EMPTY.dim())),
+                    Cell.from(Span.styled(hc.name != null ? hc.name : "", 
Style.EMPTY.fg(Color.CYAN))),
                     Cell.from(Span.styled(icon + hc.state, stateStyle)),
                     Cell.from(kind),
                     Cell.from(hc.message != null ? hc.message : "")));
@@ -1431,7 +1461,7 @@ public class CamelMonitor extends CamelCommand {
             rows.add(Row.from(
                     Cell.from(""),
                     Cell.from(Span.styled(showOnlyDown ? "No DOWN checks" : 
"No health checks registered",
-                            Style.create().dim())),
+                            Style.EMPTY.dim())),
                     Cell.from(""),
                     Cell.from(""),
                     Cell.from("")));
@@ -1444,18 +1474,18 @@ public class CamelMonitor extends CamelCommand {
         Table table = Table.builder()
                 .rows(rows)
                 .header(Row.from(
-                        Cell.from(Span.styled("GROUP", Style.create().bold())),
-                        Cell.from(Span.styled("NAME", Style.create().bold())),
-                        Cell.from(Span.styled("STATUS", 
Style.create().bold())),
-                        Cell.from(Span.styled("KIND", Style.create().bold())),
-                        Cell.from(Span.styled("MESSAGE", 
Style.create().bold()))))
+                        Cell.from(Span.styled("GROUP", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("NAME", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("STATUS", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("KIND", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("MESSAGE", Style.EMPTY.bold()))))
                 .widths(
                         Constraint.length(12),
                         Constraint.length(25),
                         Constraint.length(12),
                         Constraint.length(6),
                         Constraint.fill())
-                .highlightStyle(Style.create().fg(Color.WHITE).bold().onBlue())
+                .highlightStyle(Style.EMPTY.fg(Color.WHITE).bold().onBlue())
                 .highlightSpacing(Table.HighlightSpacing.ALWAYS)
                 
.block(Block.builder().borderType(BorderType.ROUNDED).title(title).build())
                 .build();
@@ -1465,8 +1495,8 @@ public class CamelMonitor extends CamelCommand {
         // Memory gauge
         if (info.heapMemMax > 0) {
             int pct = (int) (100.0 * info.heapMemUsed / info.heapMemMax);
-            Style gaugeStyle = pct > 80 ? Style.create().fg(Color.RED)
-                    : pct > 60 ? Style.create().fg(Color.YELLOW) : 
Style.create().fg(Color.GREEN);
+            Style gaugeStyle = pct > 80 ? Style.EMPTY.fg(Color.RED)
+                    : pct > 60 ? Style.EMPTY.fg(Color.YELLOW) : 
Style.EMPTY.fg(Color.GREEN);
             Gauge gauge = Gauge.builder()
                     .percent(pct)
                     .label(String.format("Heap: %s / %s (%d%%)", 
formatBytes(info.heapMemUsed),
@@ -1499,9 +1529,9 @@ public class CamelMonitor extends CamelCommand {
         for (EndpointInfo ep : info.endpoints) {
             String dir = ep.direction != null ? ep.direction : "";
             Style dirStyle = switch (dir) {
-                case "in" -> Style.create().fg(Color.GREEN);
-                case "out" -> Style.create().fg(Color.BLUE);
-                default -> Style.create().fg(Color.YELLOW);
+                case "in" -> Style.EMPTY.fg(Color.GREEN);
+                case "out" -> Style.EMPTY.fg(Color.BLUE);
+                default -> Style.EMPTY.fg(Color.YELLOW);
             };
             String arrow = switch (dir) {
                 case "in" -> "\u2192 ";
@@ -1510,7 +1540,7 @@ public class CamelMonitor extends CamelCommand {
             };
 
             rows.add(Row.from(
-                    Cell.from(Span.styled(ep.component != null ? ep.component 
: "", Style.create().fg(Color.CYAN))),
+                    Cell.from(Span.styled(ep.component != null ? ep.component 
: "", Style.EMPTY.fg(Color.CYAN))),
                     Cell.from(Span.styled(arrow + dir, dirStyle)),
                     Cell.from(ep.uri != null ? ep.uri : ""),
                     Cell.from(ep.routeId != null ? ep.routeId : "")));
@@ -1519,7 +1549,7 @@ public class CamelMonitor extends CamelCommand {
         if (rows.isEmpty()) {
             rows.add(Row.from(
                     Cell.from(""),
-                    Cell.from(Span.styled("No endpoints", 
Style.create().dim())),
+                    Cell.from(Span.styled("No endpoints", Style.EMPTY.dim())),
                     Cell.from(""),
                     Cell.from("")));
         }
@@ -1527,16 +1557,16 @@ public class CamelMonitor extends CamelCommand {
         Table table = Table.builder()
                 .rows(rows)
                 .header(Row.from(
-                        Cell.from(Span.styled("COMPONENT", 
Style.create().bold())),
-                        Cell.from(Span.styled("DIR", Style.create().bold())),
-                        Cell.from(Span.styled("URI", Style.create().bold())),
-                        Cell.from(Span.styled("ROUTE", 
Style.create().bold()))))
+                        Cell.from(Span.styled("COMPONENT", 
Style.EMPTY.bold())),
+                        Cell.from(Span.styled("DIR", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("URI", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("ROUTE", Style.EMPTY.bold()))))
                 .widths(
                         Constraint.length(15),
                         Constraint.length(8),
                         Constraint.fill(),
                         Constraint.length(20))
-                .highlightStyle(Style.create().fg(Color.WHITE).bold().onBlue())
+                .highlightStyle(Style.EMPTY.fg(Color.WHITE).bold().onBlue())
                 .highlightSpacing(Table.HighlightSpacing.ALWAYS)
                 .block(Block.builder().borderType(BorderType.ROUNDED)
                         .title(" Endpoints [" + info.name + "] ").build())
@@ -1570,16 +1600,16 @@ public class CamelMonitor extends CamelCommand {
         List<Row> rows = new ArrayList<>();
         for (LogEntry entry : filteredLogEntries) {
             Style levelStyle = switch (entry.level) {
-                case "ERROR", "FATAL" -> Style.create().fg(Color.RED);
-                case "WARN" -> Style.create().fg(Color.YELLOW);
-                case "DEBUG", "TRACE" -> Style.create().dim();
-                default -> Style.create();
+                case "ERROR", "FATAL" -> Style.EMPTY.fg(Color.RED);
+                case "WARN" -> Style.EMPTY.fg(Color.YELLOW);
+                case "DEBUG", "TRACE" -> Style.EMPTY.dim();
+                default -> Style.EMPTY;
             };
 
             rows.add(Row.from(
-                    Cell.from(Span.styled(entry.time, Style.create().dim())),
+                    Cell.from(Span.styled(entry.time, Style.EMPTY.dim())),
                     Cell.from(Span.styled(entry.level, levelStyle)),
-                    Cell.from(Span.styled(entry.logger != null ? entry.logger 
: "", Style.create().fg(Color.CYAN))),
+                    Cell.from(Span.styled(entry.logger != null ? entry.logger 
: "", Style.EMPTY.fg(Color.CYAN))),
                     Cell.from(Span.styled(entry.message, levelStyle))));
         }
 
@@ -1587,16 +1617,16 @@ public class CamelMonitor extends CamelCommand {
         Table logTable = Table.builder()
                 .rows(rows)
                 .header(Row.from(
-                        Cell.from(Span.styled("TIME", Style.create().bold())),
-                        Cell.from(Span.styled("LEVEL", Style.create().bold())),
-                        Cell.from(Span.styled("LOGGER", 
Style.create().bold())),
-                        Cell.from(Span.styled("MESSAGE", 
Style.create().bold()))))
+                        Cell.from(Span.styled("TIME", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("LEVEL", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("LOGGER", Style.EMPTY.bold())),
+                        Cell.from(Span.styled("MESSAGE", Style.EMPTY.bold()))))
                 .widths(
                         Constraint.length(12),
                         Constraint.length(6),
                         Constraint.length(20),
                         Constraint.fill())
-                .highlightStyle(Style.create().fg(Color.WHITE).bold().onBlue())
+                .highlightStyle(Style.EMPTY.fg(Color.WHITE).bold().onBlue())
                 .highlightSpacing(Table.HighlightSpacing.ALWAYS)
                 .block(Block.builder().borderType(BorderType.ROUNDED)
                         .title(" Log [" + info.name + "] " + 
levelTitle).build())
@@ -1614,7 +1644,7 @@ public class CamelMonitor extends CamelCommand {
             frame.renderWidget(
                     Paragraph.builder()
                             .text(Text.from(Line.from(
-                                    Span.styled(" Select a log entry", 
Style.create().dim()))))
+                                    Span.styled(" Select a log entry", 
Style.EMPTY.dim()))))
                             
.block(Block.builder().borderType(BorderType.ROUNDED)
                                     .title(" Detail ").build())
                             .build(),
@@ -1635,10 +1665,10 @@ public class CamelMonitor extends CamelCommand {
 
     private Style colorStyleForLevel(String level) {
         return switch (level) {
-            case "ERROR", "FATAL" -> Style.create().fg(Color.RED);
-            case "WARN" -> Style.create().fg(Color.YELLOW);
-            case "DEBUG", "TRACE" -> Style.create().dim();
-            default -> Style.create();
+            case "ERROR", "FATAL" -> Style.EMPTY.fg(Color.RED);
+            case "WARN" -> Style.EMPTY.fg(Color.YELLOW);
+            case "DEBUG", "TRACE" -> Style.EMPTY.dim();
+            default -> Style.EMPTY;
         };
     }
 
@@ -1655,8 +1685,8 @@ public class CamelMonitor extends CamelCommand {
         return sb.toString();
     }
 
-    private void readLogFile(String pid) {
-        logLines.clear();
+    private void readLogFile(String pid, List<String> target) {
+        target.clear();
         Path logFile = CommandLineHelper.getCamelDir().resolve(pid + ".log");
         if (!Files.exists(logFile)) {
             return;
@@ -1673,12 +1703,12 @@ public class CamelMonitor extends CamelCommand {
             byte[] remaining = new byte[(int) (length - raf.getFilePointer())];
             raf.readFully(remaining);
             String content = new String(remaining, StandardCharsets.UTF_8);
-            String[] lines = content.split("\n", -1);
-            int start = Math.max(0, lines.length - MAX_LOG_LINES);
-            for (int i = start; i < lines.length; i++) {
-                String line = lines[i].replaceAll("\u001B\\[[;\\d]*m", "");
+            String[] rawLines = content.split("\n", -1);
+            int start = Math.max(0, rawLines.length - MAX_LOG_LINES);
+            for (int i = start; i < rawLines.length; i++) {
+                String line = rawLines[i].replaceAll("\u001B\\[[;\\d]*m", "");
                 if (!line.isEmpty()) {
-                    logLines.add(line);
+                    target.add(line);
                 }
             }
         } catch (IOException e) {
@@ -1686,15 +1716,16 @@ public class CamelMonitor extends CamelCommand {
         }
     }
 
-    private void applyLogFilters() {
-        filteredLogEntries.clear();
-        for (String line : logLines) {
+    private List<LogEntry> applyLogFilters(List<String> lines) {
+        List<LogEntry> result = new ArrayList<>();
+        for (String line : lines) {
             LogEntry entry = parseLogLine(line);
             if (!matchesLogLevelFilter(entry.level)) {
                 continue;
             }
-            filteredLogEntries.add(entry);
+            result.add(entry);
         }
+        return result;
     }
 
     // Regex for Spring Boot / Camel log format:
@@ -1775,10 +1806,10 @@ public class CamelMonitor extends CamelCommand {
         for (TraceEntry entry : current) {
             String status = entry.status != null ? entry.status : "";
             Style statusStyle = switch (status) {
-                case "Done" -> Style.create().fg(Color.GREEN);
-                case "Failed" -> Style.create().fg(Color.RED);
-                case "Processing" -> Style.create().fg(Color.YELLOW);
-                default -> Style.create().fg(Color.WHITE);
+                case "Done" -> Style.EMPTY.fg(Color.GREEN);
+                case "Failed" -> Style.EMPTY.fg(Color.RED);
+                case "Processing" -> Style.EMPTY.fg(Color.YELLOW);
+                default -> Style.EMPTY.fg(Color.WHITE);
             };
 
             String bodyPreview = entry.bodyPreview != null ? 
truncate(entry.bodyPreview, 40) : "";
@@ -1788,7 +1819,7 @@ public class CamelMonitor extends CamelCommand {
                     Cell.from(entry.pid != null ? entry.pid : ""),
                     Cell.from(Span.styled(
                             entry.routeId != null ? truncate(entry.routeId, 
15) : "",
-                            Style.create().fg(Color.CYAN))),
+                            Style.EMPTY.fg(Color.CYAN))),
                     Cell.from(entry.nodeId != null ? truncate(entry.nodeId, 
15) : ""),
                     Cell.from(Span.styled(status, statusStyle)),
                     Cell.from(entry.elapsed + "ms"),
@@ -1796,13 +1827,13 @@ public class CamelMonitor extends CamelCommand {
         }
 
         Row header = Row.from(
-                Cell.from(Span.styled("TIME", Style.create().bold())),
-                Cell.from(Span.styled("PID", Style.create().bold())),
-                Cell.from(Span.styled("ROUTE", Style.create().bold())),
-                Cell.from(Span.styled("NODE", Style.create().bold())),
-                Cell.from(Span.styled("STATUS", Style.create().bold())),
-                Cell.from(Span.styled("ELAPSED", Style.create().bold())),
-                Cell.from(Span.styled("BODY", Style.create().bold())));
+                Cell.from(Span.styled("TIME", Style.EMPTY.bold())),
+                Cell.from(Span.styled("PID", Style.EMPTY.bold())),
+                Cell.from(Span.styled("ROUTE", Style.EMPTY.bold())),
+                Cell.from(Span.styled("NODE", Style.EMPTY.bold())),
+                Cell.from(Span.styled("STATUS", Style.EMPTY.bold())),
+                Cell.from(Span.styled("ELAPSED", Style.EMPTY.bold())),
+                Cell.from(Span.styled("BODY", Style.EMPTY.bold())));
 
         String traceTitle = String.format(" Traces [%d] %s ",
                 current.size(),
@@ -1819,7 +1850,7 @@ public class CamelMonitor extends CamelCommand {
                         Constraint.length(12),
                         Constraint.length(10),
                         Constraint.fill())
-                .highlightStyle(Style.create().fg(Color.WHITE).bold().onBlue())
+                .highlightStyle(Style.EMPTY.fg(Color.WHITE).bold().onBlue())
                 .highlightSpacing(Table.HighlightSpacing.ALWAYS)
                 
.block(Block.builder().borderType(BorderType.ROUNDED).title(traceTitle).build())
                 .build();
@@ -1838,7 +1869,7 @@ public class CamelMonitor extends CamelCommand {
                     Paragraph.builder()
                             .text(Text.from(Line.from(
                                     Span.styled(" Select a trace entry to view 
details",
-                                            Style.create().dim()))))
+                                            Style.EMPTY.dim()))))
                             
.block(Block.builder().borderType(BorderType.ROUNDED)
                                     .title(" Detail ").build())
                             .build(),
@@ -1851,22 +1882,22 @@ public class CamelMonitor extends CamelCommand {
 
         // Exchange info
         lines.add(Line.from(
-                Span.styled(" Exchange: ", 
Style.create().fg(Color.YELLOW).bold()),
+                Span.styled(" Exchange: ", 
Style.EMPTY.fg(Color.YELLOW).bold()),
                 Span.raw(entry.exchangeId != null ? entry.exchangeId : "")));
         lines.add(Line.from(
-                Span.styled(" UID:      ", 
Style.create().fg(Color.YELLOW).bold()),
+                Span.styled(" UID:      ", 
Style.EMPTY.fg(Color.YELLOW).bold()),
                 Span.raw(entry.uid != null ? entry.uid : "")));
         lines.add(Line.from(
-                Span.styled(" Location: ", 
Style.create().fg(Color.YELLOW).bold()),
+                Span.styled(" Location: ", 
Style.EMPTY.fg(Color.YELLOW).bold()),
                 Span.raw(entry.location != null ? entry.location : "")));
         lines.add(Line.from(
-                Span.styled(" Route:    ", 
Style.create().fg(Color.YELLOW).bold()),
+                Span.styled(" Route:    ", 
Style.EMPTY.fg(Color.YELLOW).bold()),
                 Span.raw(entry.routeId != null ? entry.routeId : ""),
                 Span.raw("  Node: "),
                 Span.raw(entry.nodeId != null ? entry.nodeId : ""),
                 Span.raw(entry.nodeLabel != null ? " (" + entry.nodeLabel + 
")" : "")));
         lines.add(Line.from(
-                Span.styled(" Status:   ", 
Style.create().fg(Color.YELLOW).bold()),
+                Span.styled(" Status:   ", 
Style.EMPTY.fg(Color.YELLOW).bold()),
                 Span.raw(entry.status != null ? entry.status : ""),
                 Span.raw("  Elapsed: "),
                 Span.raw(entry.elapsed + "ms")));
@@ -1874,10 +1905,10 @@ public class CamelMonitor extends CamelCommand {
 
         // Headers
         if (showTraceHeaders && entry.headers != null && 
!entry.headers.isEmpty()) {
-            lines.add(Line.from(Span.styled(" Headers:", 
Style.create().fg(Color.GREEN).bold())));
+            lines.add(Line.from(Span.styled(" Headers:", 
Style.EMPTY.fg(Color.GREEN).bold())));
             for (Map.Entry<String, Object> h : entry.headers.entrySet()) {
                 lines.add(Line.from(
-                        Span.styled("   " + h.getKey(), 
Style.create().fg(Color.CYAN)),
+                        Span.styled("   " + h.getKey(), 
Style.EMPTY.fg(Color.CYAN)),
                         Span.raw(" = "),
                         Span.raw(h.getValue() != null ? 
h.getValue().toString() : "null")));
             }
@@ -1886,7 +1917,7 @@ public class CamelMonitor extends CamelCommand {
 
         // Body
         if (showTraceBody && entry.body != null) {
-            lines.add(Line.from(Span.styled(" Body:", 
Style.create().fg(Color.GREEN).bold())));
+            lines.add(Line.from(Span.styled(" Body:", 
Style.EMPTY.fg(Color.GREEN).bold())));
             String[] bodyLines = entry.body.split("\n");
             for (String bl : bodyLines) {
                 lines.add(Line.from(Span.raw("   " + bl)));
@@ -1896,10 +1927,10 @@ public class CamelMonitor extends CamelCommand {
 
         // Exchange properties
         if (entry.exchangeProperties != null && 
!entry.exchangeProperties.isEmpty()) {
-            lines.add(Line.from(Span.styled(" Exchange Properties:", 
Style.create().fg(Color.GREEN).bold())));
+            lines.add(Line.from(Span.styled(" Exchange Properties:", 
Style.EMPTY.fg(Color.GREEN).bold())));
             for (Map.Entry<String, Object> p : 
entry.exchangeProperties.entrySet()) {
                 lines.add(Line.from(
-                        Span.styled("   " + p.getKey(), 
Style.create().fg(Color.CYAN)),
+                        Span.styled("   " + p.getKey(), 
Style.EMPTY.fg(Color.CYAN)),
                         Span.raw(" = "),
                         Span.raw(p.getValue() != null ? 
p.getValue().toString() : "null")));
             }
@@ -1908,10 +1939,10 @@ public class CamelMonitor extends CamelCommand {
 
         // Exchange variables
         if (entry.exchangeVariables != null && 
!entry.exchangeVariables.isEmpty()) {
-            lines.add(Line.from(Span.styled(" Exchange Variables:", 
Style.create().fg(Color.GREEN).bold())));
+            lines.add(Line.from(Span.styled(" Exchange Variables:", 
Style.EMPTY.fg(Color.GREEN).bold())));
             for (Map.Entry<String, Object> v : 
entry.exchangeVariables.entrySet()) {
                 lines.add(Line.from(
-                        Span.styled("   " + v.getKey(), 
Style.create().fg(Color.CYAN)),
+                        Span.styled("   " + v.getKey(), 
Style.EMPTY.fg(Color.CYAN)),
                         Span.raw(" = "),
                         Span.raw(v.getValue() != null ? 
v.getValue().toString() : "null")));
             }
@@ -1935,7 +1966,7 @@ public class CamelMonitor extends CamelCommand {
                 Paragraph.builder()
                         .text(Text.from(Line.from(
                                 Span.styled(" Select an integration from the 
Overview tab (press 1)",
-                                        Style.create().dim()))))
+                                        Style.EMPTY.dim()))))
                         .block(Block.builder().borderType(BorderType.ROUNDED)
                                 .title(" No integration selected ").build())
                         .build(),
@@ -1943,108 +1974,102 @@ public class CamelMonitor extends CamelCommand {
     }
 
     private void renderFooter(Frame frame, Rect area) {
-        String refreshLabel = refreshInterval >= 1000
-                ? (refreshInterval / 1000) + "s"
-                : refreshInterval + "ms";
-        Line footer;
+        List<Span> spans = new ArrayList<>();
         int tab = tabsState.selected();
+
         if (tab == TAB_OVERVIEW) {
-            footer = Line.from(
-                    Span.styled(" q", Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" quit  "),
-                    Span.styled("r", Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" refresh  "),
-                    Span.styled("\u2191\u2193", 
Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" navigate  "),
-                    Span.styled("Enter", 
Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" details  "),
-                    Span.styled("1-6", Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" tabs  "),
-                    Span.styled("Refresh: " + refreshLabel, 
Style.create().dim()));
+            hint(spans, "q", "quit");
+            hint(spans, "r", "refresh");
+            hint(spans, "\u2191\u2193", "navigate");
+            hint(spans, "Enter", "details");
+            hint(spans, "1-6", "tabs");
+            hintRefresh(spans);
+        } else if (tab == TAB_ROUTES && showDiagram) {
+            String closeKey = diagramTextMode ? "D" : "d";
+            hint(spans, closeKey + "/Esc", "close");
+            hint(spans, "\u2191\u2193\u2190\u2192", "scroll");
+            hint(spans, "PgUp/PgDn", "page");
+            hintLast(spans, "Home/End", "top/bottom");
         } else if (tab == TAB_ROUTES) {
-            if (showDiagram) {
-                String closeKey = diagramTextMode ? "D" : "d";
-                footer = Line.from(
-                        Span.styled(" " + closeKey, 
Style.create().fg(Color.YELLOW).bold()),
-                        Span.raw("/"),
-                        Span.styled("Esc", 
Style.create().fg(Color.YELLOW).bold()),
-                        Span.raw(" close  "),
-                        Span.styled("\u2191\u2193\u2190\u2192", 
Style.create().fg(Color.YELLOW).bold()),
-                        Span.raw(" scroll  "),
-                        Span.styled("PgUp/PgDn", 
Style.create().fg(Color.YELLOW).bold()),
-                        Span.raw(" page  "),
-                        Span.styled("Home/End", 
Style.create().fg(Color.YELLOW).bold()),
-                        Span.raw(" top/bottom"));
-            } else {
-                footer = Line.from(
-                        Span.styled(" Esc", 
Style.create().fg(Color.YELLOW).bold()),
-                        Span.raw(" back  "),
-                        Span.styled("\u2191\u2193", 
Style.create().fg(Color.YELLOW).bold()),
-                        Span.raw(" navigate  "),
-                        Span.styled("s", 
Style.create().fg(Color.YELLOW).bold()),
-                        Span.raw(" sort  "),
-                        Span.styled("d", 
Style.create().fg(Color.YELLOW).bold()),
-                        Span.raw(" diagram  "),
-                        Span.styled("D", 
Style.create().fg(Color.YELLOW).bold()),
-                        Span.raw(" text diagram  "),
-                        Span.styled("1-6", 
Style.create().fg(Color.YELLOW).bold()),
-                        Span.raw(" tabs  "),
-                        Span.styled("Refresh: " + refreshLabel, 
Style.create().dim()));
-            }
+            hint(spans, "Esc", "back");
+            hint(spans, "\u2191\u2193", "navigate");
+            hint(spans, "s", "sort");
+            hint(spans, "d", "diagram");
+            hint(spans, "D", "text diagram");
+            hint(spans, "1-6", "tabs");
+            hintRefresh(spans);
         } else if (tab == TAB_HEALTH) {
-            footer = Line.from(
-                    Span.styled(" Esc", 
Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" back  "),
-                    Span.styled("\u2191\u2193", 
Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" navigate  "),
-                    Span.styled("d", Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" toggle DOWN  "),
-                    Span.styled("1-6", Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" tabs  "),
-                    Span.styled("Refresh: " + refreshLabel, 
Style.create().dim()));
+            hint(spans, "Esc", "back");
+            hint(spans, "\u2191\u2193", "navigate");
+            hint(spans, "d", "toggle DOWN");
+            hint(spans, "1-6", "tabs");
+            hintRefresh(spans);
         } else if (tab == TAB_LOG) {
-            footer = Line.from(
-                    Span.styled(" Esc", 
Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" back  "),
-                    Span.styled("\u2191\u2193", 
Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" scroll  "),
-                    Span.styled("PgUp/PgDn", 
Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" page  "),
-                    Span.styled("t/d/i/w/e", 
Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" levels  "),
-                    Span.styled("f", Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" follow  "),
-                    Span.styled("g/G", Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" top/end"));
+            hint(spans, "Esc", "back");
+            hint(spans, "\u2191\u2193", "scroll");
+            hint(spans, "PgUp/PgDn", "page");
+            hint(spans, "Home/End", "top/end");
+            hint(spans, "t/d/i/w/e", "levels");
+            hintLast(spans, "f", "follow");
         } else if (tab == TAB_TRACE) {
-            footer = Line.from(
-                    Span.styled(" Esc", 
Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" back  "),
-                    Span.styled("\u2191\u2193", 
Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" navigate  "),
-                    Span.styled("h", Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" headers" + (showTraceHeaders ? " [on]" : " 
[off]") + "  "),
-                    Span.styled("b", Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" body" + (showTraceBody ? " [on]" : " [off]") + 
"  "),
-                    Span.styled("f", Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" follow" + (traceFollowMode ? " [on]" : " 
[off]")));
+            hint(spans, "Esc", "back");
+            hint(spans, "\u2191\u2193", "navigate");
+            hint(spans, "h", "headers" + (showTraceHeaders ? " [on]" : " 
[off]"));
+            hint(spans, "b", "body" + (showTraceBody ? " [on]" : " [off]"));
+            hintLast(spans, "f", "follow" + (traceFollowMode ? " [on]" : " 
[off]"));
         } else {
-            footer = Line.from(
-                    Span.styled(" Esc", 
Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" back  "),
-                    Span.styled("\u2191\u2193", 
Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" navigate  "),
-                    Span.styled("1-6", Style.create().fg(Color.YELLOW).bold()),
-                    Span.raw(" tabs  "),
-                    Span.styled("Refresh: " + refreshLabel, 
Style.create().dim()));
+            hint(spans, "Esc", "back");
+            hint(spans, "\u2191\u2193", "navigate");
+            hint(spans, "1-6", "tabs");
+            hintRefresh(spans);
         }
 
-        frame.renderWidget(Paragraph.from(footer), area);
+        frame.renderWidget(Paragraph.from(Line.from(spans)), area);
+    }
+
+    private static final Style HINT_KEY_STYLE = 
Style.EMPTY.fg(Color.YELLOW).bold();
+
+    private static void hint(List<Span> spans, String key, String label) {
+        spans.add(Span.styled(" " + key, HINT_KEY_STYLE));
+        spans.add(Span.raw(" " + label + "  "));
+    }
+
+    private static void hintLast(List<Span> spans, String key, String label) {
+        spans.add(Span.styled(" " + key, HINT_KEY_STYLE));
+        spans.add(Span.raw(" " + label));
+    }
+
+    private void hintRefresh(List<Span> spans) {
+        String refreshLabel = refreshInterval >= 1000
+                ? (refreshInterval / 1000) + "s"
+                : refreshInterval + "ms";
+        spans.add(Span.styled("Refresh: " + refreshLabel, Style.EMPTY.dim()));
     }
 
     // ---- Data Loading ----
 
     private void refreshData() {
+        if (runner == null) {
+            refreshDataSync();
+            return;
+        }
+        if (!refreshInProgress.compareAndSet(false, true)) {
+            return;
+        }
+        lastRefresh = System.currentTimeMillis();
+        String currentSelectedPid = selectedPid;
+        runner.scheduler().execute(() -> {
+            try {
+                refreshDataSync();
+            } finally {
+                refreshInProgress.set(false);
+            }
+            runner.runOnRenderThread(() -> {
+            });
+        });
+    }
+
+    private void refreshDataSync() {
         lastRefresh = System.currentTimeMillis();
         try {
             List<IntegrationInfo> infos = new ArrayList<>();
@@ -2057,7 +2082,6 @@ public class CamelMonitor extends CamelCommand {
                             IntegrationInfo info = parseIntegration(ph, root);
                             if (info != null) {
                                 infos.add(info);
-                                // Track throughput for sparkline
                                 updateThroughputHistory(info);
                             }
                         }
@@ -2095,8 +2119,11 @@ public class CamelMonitor extends CamelCommand {
             // Refresh log data for the selected integration
             IntegrationInfo selected = findSelectedIntegration();
             if (selected != null) {
-                readLogFile(selected.pid);
-                applyLogFilters();
+                List<String> newLogLines = new ArrayList<>();
+                readLogFile(selected.pid, newLogLines);
+                List<LogEntry> newFilteredEntries = 
applyLogFilters(newLogLines);
+                logLines = newLogLines;
+                filteredLogEntries = newFilteredEntries;
             }
 
             // Refresh trace data
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiHelper.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiHelper.java
index 87b7cc74d9e3..0183a53b139e 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiHelper.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiHelper.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Function;
 
+import dev.tamboui.text.CharWidth;
 import org.apache.camel.dsl.jbang.core.common.ProcessHelper;
 import org.apache.camel.support.PatternHelper;
 import org.apache.camel.util.FileUtil;
@@ -109,7 +110,9 @@ final class TuiHelper {
         if (s == null) {
             return "";
         }
-        return s.length() > max ? s.substring(0, max - 1) + "\u2026" : s;
+        return CharWidth.of(s) > max
+                ? CharWidth.truncateWithEllipsis(s, max, 
CharWidth.TruncatePosition.END)
+                : s;
     }
 
     /**


Reply via email to