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

gnodet pushed a commit to branch 
improve-mouse-support-in-tui-scrolling-with-wheel
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 9208873ac94b4e36ba00f8a5fd6f918f0679d17a
Author: Guillaume Nodet <[email protected]>
AuthorDate: Wed Jul 1 23:34:02 2026 +0200

    chore: apply SOLID principles to TUI class hierarchy
    
    - Move static utilities (formatting, hint/hintLast, contains, compareStr) 
from MonitorContext and AbstractTab to TuiHelper (SRP)
    - Add default implementations to MonitorTab interface to reduce mandatory 
overrides (ISP)
    - MonitorContext is now pure shared mutable state with no static members
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../dsl/jbang/core/commands/tui/AbstractTab.java   | 107 +++++++---
 .../jbang/core/commands/tui/AbstractTableTab.java  |  12 +-
 .../dsl/jbang/core/commands/tui/ActionsPopup.java  |   6 +-
 .../dsl/jbang/core/commands/tui/AiLogPopup.java    |   4 +-
 .../camel/dsl/jbang/core/commands/tui/AiPanel.java |  16 +-
 .../dsl/jbang/core/commands/tui/BeansTab.java      |   2 +-
 .../dsl/jbang/core/commands/tui/BrowseTab.java     |   6 +-
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  |   7 +-
 .../jbang/core/commands/tui/CaptionOverlay.java    |   4 +-
 .../jbang/core/commands/tui/CircuitBreakerTab.java |   8 +-
 .../dsl/jbang/core/commands/tui/ClasspathTab.java  |   2 +-
 .../jbang/core/commands/tui/ConfigurationTab.java  |   2 +-
 .../dsl/jbang/core/commands/tui/ConsumersTab.java  |   2 +-
 .../core/commands/tui/DataRefreshService.java      |   2 +-
 .../dsl/jbang/core/commands/tui/DataSourceTab.java |   2 +-
 .../jbang/core/commands/tui/DiagramSupport.java    |   3 +-
 .../dsl/jbang/core/commands/tui/DiagramTab.java    |   2 +-
 .../dsl/jbang/core/commands/tui/DoctorPopup.java   |   2 +-
 .../dsl/jbang/core/commands/tui/EndpointsTab.java  |   2 +-
 .../dsl/jbang/core/commands/tui/ErrorsTab.java     |   2 +-
 .../dsl/jbang/core/commands/tui/FilesBrowser.java  |   6 +-
 .../dsl/jbang/core/commands/tui/HealthTab.java     |   4 +-
 .../jbang/core/commands/tui/HeapHistogramTab.java  |   2 +-
 .../dsl/jbang/core/commands/tui/HelpOverlay.java   |   4 +-
 .../dsl/jbang/core/commands/tui/HistoryTab.java    |  19 +-
 .../camel/dsl/jbang/core/commands/tui/HttpTab.java |   2 +-
 .../dsl/jbang/core/commands/tui/InflightTab.java   |   2 +-
 .../camel/dsl/jbang/core/commands/tui/LogTab.java  |   2 +-
 .../dsl/jbang/core/commands/tui/McpFacade.java     |   6 +-
 .../dsl/jbang/core/commands/tui/McpLogPopup.java   |   4 +-
 .../dsl/jbang/core/commands/tui/MemoryTab.java     |   2 +-
 .../dsl/jbang/core/commands/tui/MetricsTab.java    |   2 +-
 .../jbang/core/commands/tui/MonitorContext.java    | 227 +--------------------
 .../dsl/jbang/core/commands/tui/MonitorTab.java    |  13 +-
 .../dsl/jbang/core/commands/tui/OverviewTab.java   |   8 +-
 .../dsl/jbang/core/commands/tui/PopupManager.java  |   4 +-
 .../dsl/jbang/core/commands/tui/ProcessTab.java    |   2 +-
 .../dsl/jbang/core/commands/tui/RoutesTab.java     |  10 +-
 .../jbang/core/commands/tui/RunOptionsForm.java    |   4 +-
 .../jbang/core/commands/tui/SearchHighlighter.java |   4 +-
 .../jbang/core/commands/tui/SendMessagePopup.java  |   6 +-
 .../dsl/jbang/core/commands/tui/ShellPanel.java    |   8 +-
 .../dsl/jbang/core/commands/tui/SourceViewer.java  |  20 +-
 .../dsl/jbang/core/commands/tui/SpansTab.java      |  38 ++--
 .../dsl/jbang/core/commands/tui/SqlQueryTab.java   |   2 +-
 .../dsl/jbang/core/commands/tui/SqlTraceTab.java   |   2 +-
 .../dsl/jbang/core/commands/tui/StartupTab.java    |   2 +-
 .../dsl/jbang/core/commands/tui/StopAllPopup.java  |   4 +-
 .../dsl/jbang/core/commands/tui/ThreadsTab.java    |   2 +-
 .../dsl/jbang/core/commands/tui/TuiHelper.java     | 152 ++++++++++++++
 .../jbang/core/commands/tui/CamelMonitorTest.java  |   2 +-
 .../commands/tui/MonitorContextRenderTest.java     |  30 +--
 .../core/commands/tui/MonitorContextTest.java      |  72 +++----
 53 files changed, 426 insertions(+), 434 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AbstractTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AbstractTab.java
index e75fbcd0e5f8..81167cc8586c 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AbstractTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AbstractTab.java
@@ -16,14 +16,26 @@
  */
 package org.apache.camel.dsl.jbang.core.commands.tui;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import dev.tamboui.layout.Rect;
+import dev.tamboui.style.Color;
+import dev.tamboui.style.Style;
 import dev.tamboui.terminal.Frame;
+import dev.tamboui.text.Line;
 import dev.tamboui.text.Span;
+import dev.tamboui.text.Text;
 import dev.tamboui.tui.event.MouseEvent;
+import dev.tamboui.widgets.block.Block;
+import dev.tamboui.widgets.block.BorderType;
+import dev.tamboui.widgets.block.Borders;
+import dev.tamboui.widgets.block.Title;
+import dev.tamboui.widgets.paragraph.Paragraph;
 import dev.tamboui.widgets.scrollbar.Scrollbar;
 import dev.tamboui.widgets.scrollbar.ScrollbarState;
+import dev.tamboui.widgets.table.Cell;
+import dev.tamboui.widgets.table.Row;
 import dev.tamboui.widgets.table.TableState;
 
 abstract class AbstractTab implements MonitorTab {
@@ -34,23 +46,79 @@ abstract class AbstractTab implements MonitorTab {
         this.ctx = ctx;
     }
 
-    @Override
-    public boolean handleEscape() {
-        return false;
+    // ---- Rendering helpers ----
+
+    protected static void renderNoSelection(Frame frame, Rect area) {
+        List<Line> lines = new ArrayList<>();
+        lines.add(Line.from(Span.raw("")));
+        for (String row : TuiHelper.SMALL_CAMEL) {
+            lines.add(Line.from(Span.styled("   " + row, 
Style.EMPTY.fg(Theme.accent()))));
+        }
+        lines.add(Line.from(Span.raw("")));
+        List<Span> hintSpans = new ArrayList<>();
+        hintSpans.add(Span.raw("   No integration selected.  "));
+        TuiHelper.hint(hintSpans, "1", "Overview");
+        TuiHelper.hint(hintSpans, "?", "Help");
+        lines.add(Line.from(hintSpans));
+
+        frame.renderWidget(
+                Paragraph.builder()
+                        .text(Text.from(lines))
+                        
.block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL)
+                                .title(Title.from(Line.from(
+                                        Span.styled(" No integration selected 
", Theme.title()))))
+                                .build())
+                        .build(),
+                area);
+    }
+
+    // ---- Cell construction helpers ----
+
+    protected static Cell rightCell(String text, int width) {
+        return Cell.from(String.format("%" + width + "s", text));
+    }
+
+    protected static Cell rightCell(String text, int width, Style style) {
+        return Cell.from(Span.styled(String.format("%" + width + "s", text), 
style));
     }
 
-    @Override
-    public void navigateUp() {
+    protected static Cell centerCell(String text, int width) {
+        int len = text.length();
+        int padding = Math.max(0, width - len);
+        int leftPad = padding / 2;
+        return Cell.from(" ".repeat(leftPad) + text);
     }
 
-    @Override
-    public void navigateDown() {
+    protected static Cell centerCell(String text, int width, Style style) {
+        int len = text.length();
+        int padding = Math.max(0, width - len);
+        int leftPad = padding / 2;
+        return Cell.from(Span.styled(" ".repeat(leftPad) + text, style));
     }
 
-    @Override
-    public void renderFooter(List<Span> spans) {
+    protected static Row emptyRow(String message, int columnCount) {
+        Cell[] cells = new Cell[columnCount];
+        cells[0] = Cell.from(Span.styled(message, Style.EMPTY.dim()));
+        for (int i = 1; i < columnCount; i++) {
+            cells[i] = Cell.from("");
+        }
+        return Row.from(cells);
     }
 
+    // ---- Sort helpers ----
+
+    protected static String sortLabel(String label, String column, String 
currentSort, boolean reversed) {
+        return currentSort.equals(column) ? label + (reversed ? "▲" : "▼") : 
label;
+    }
+
+    protected static Style sortStyle(String column, String currentSort) {
+        return currentSort.equals(column)
+                ? Style.EMPTY.fg(Color.YELLOW).bold()
+                : Style.EMPTY.bold();
+    }
+
+    // ---- Mouse / scrollbar helpers ----
+
     protected static void renderTableScrollbar(
             Frame frame, Rect tableArea, TableState tableState, ScrollbarState 
scrollState, int rowCount) {
         if (tableArea == null || tableState == null || scrollState == null) {
@@ -71,25 +139,6 @@ abstract class AbstractTab implements MonitorTab {
         frame.renderStatefulWidget(Scrollbar.builder().build(), scrollRect, 
scrollState);
     }
 
-    protected static int compareStr(String a, String b) {
-        if (a == null && b == null) {
-            return 0;
-        }
-        if (a == null) {
-            return -1;
-        }
-        if (b == null) {
-            return 1;
-        }
-        return a.compareToIgnoreCase(b);
-    }
-
-    protected static boolean contains(Rect rect, int x, int y) {
-        return rect != null
-                && x >= rect.x() && x < rect.x() + rect.width()
-                && y >= rect.y() && y < rect.y() + rect.height();
-    }
-
     protected static boolean handleTableClick(MouseEvent me, Rect tableArea, 
TableState tableState, int rowCount) {
         if (tableArea == null || tableState == null || rowCount <= 0) {
             return false;
@@ -97,7 +146,7 @@ abstract class AbstractTab implements MonitorTab {
         if (!me.isClick()) {
             return false;
         }
-        if (!contains(tableArea, me.x(), me.y())) {
+        if (!TuiHelper.contains(tableArea, me.x(), me.y())) {
             return false;
         }
         int rowIndex = tableState.offset() + (me.y() - tableArea.y() - 2);
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AbstractTableTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AbstractTableTab.java
index 67fbb68cc7e1..b5ca8016e6a8 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AbstractTableTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AbstractTableTab.java
@@ -28,6 +28,8 @@ import dev.tamboui.tui.event.MouseEvent;
 import dev.tamboui.widgets.scrollbar.ScrollbarState;
 import dev.tamboui.widgets.table.TableState;
 
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
+
 abstract class AbstractTableTab extends AbstractTab {
 
     protected final TableState tableState = new TableState();
@@ -114,7 +116,7 @@ abstract class AbstractTableTab extends AbstractTab {
     public void render(Frame frame, Rect area) {
         IntegrationInfo info = ctx.findSelectedIntegration();
         if (info == null) {
-            MonitorContext.renderNoSelection(frame, area);
+            renderNoSelection(frame, area);
             return;
         }
         renderContent(frame, area, info);
@@ -122,18 +124,18 @@ abstract class AbstractTableTab extends AbstractTab {
 
     @Override
     public void renderFooter(List<Span> spans) {
-        MonitorContext.hint(spans, "Esc", "back");
+        hint(spans, "Esc", "back");
         if (sortColumns != null) {
-            MonitorContext.hint(spans, "s", "sort");
+            hint(spans, "s", "sort");
         }
     }
 
     protected String sortLabel(String label, String column) {
-        return MonitorContext.sortLabel(label, column, sort, sortReversed);
+        return sortLabel(label, column, sort, sortReversed);
     }
 
     protected Style sortStyle(String column) {
-        return MonitorContext.sortStyle(column, sort);
+        return sortStyle(column, sort);
     }
 
     protected void renderScrollbar(Frame frame, int rowCount) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
index 0d4ba025f97f..bf20c5adb32a 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
@@ -64,8 +64,8 @@ import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 import org.apache.camel.util.json.Jsoner;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hint;
-import static 
org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hintLast;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hintLast;
 
 class ActionsPopup {
 
@@ -1038,7 +1038,7 @@ class ActionsPopup {
             JsonObject action = new JsonObject();
             action.put("action", "readme");
             PathUtils.writeTextSafely(action.toJson(), 
ctx.getActionFile(info.pid));
-            JsonObject response = MonitorContext.pollJsonResponse(outputFile, 
5000);
+            JsonObject response = TuiHelper.pollJsonResponse(outputFile, 5000);
             if (response != null && response.getString("content") != null) {
                 String raw = response.getString("content");
                 String file = response.getStringOrDefault("file", "README");
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiLogPopup.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiLogPopup.java
index fad5ae372bfd..97e8d468d2e1 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiLogPopup.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiLogPopup.java
@@ -41,8 +41,8 @@ import dev.tamboui.widgets.list.ScrollMode;
 import dev.tamboui.widgets.paragraph.Paragraph;
 import org.apache.camel.util.json.Jsoner;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hint;
-import static 
org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hintLast;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hintLast;
 
 class AiLogPopup {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java
index 7c9c1256241f..c40c8fad3eab 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java
@@ -224,7 +224,7 @@ class AiPanel {
         if (!visible || lastArea == null) {
             return false;
         }
-        if (!AbstractTab.contains(lastArea, me.x(), me.y())) {
+        if (!TuiHelper.contains(lastArea, me.x(), me.y())) {
             return false;
         }
         if (me.kind() == MouseEventKind.SCROLL_UP) {
@@ -642,19 +642,19 @@ class AiPanel {
     }
 
     void renderFooter(List<Span> spans) {
-        MonitorContext.hint(spans, "F8", "close");
+        TuiHelper.hint(spans, "F8", "close");
         if (statsView) {
-            MonitorContext.hint(spans, "Ctrl+U", "chat");
+            TuiHelper.hint(spans, "Ctrl+U", "chat");
         } else {
-            MonitorContext.hint(spans, "Ctrl+U", "usage");
+            TuiHelper.hint(spans, "Ctrl+U", "usage");
         }
-        MonitorContext.hint(spans, "Shift+F8", "resize (" + 
anim.cyclePercent() + "%)");
-        MonitorContext.hint(spans, "PgUp/Dn", "scroll");
+        TuiHelper.hint(spans, "Shift+F8", "resize (" + anim.cyclePercent() + 
"%)");
+        TuiHelper.hint(spans, "PgUp/Dn", "scroll");
         if (!statsView) {
             if (!thinking.get()) {
-                MonitorContext.hint(spans, "Enter", "send");
+                TuiHelper.hint(spans, "Enter", "send");
             } else {
-                MonitorContext.hint(spans, "Ctrl+C", "cancel");
+                TuiHelper.hint(spans, "Ctrl+C", "cancel");
             }
         }
     }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/BeansTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/BeansTab.java
index 0b91b84f1a80..37c2833c8c57 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/BeansTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/BeansTab.java
@@ -45,7 +45,7 @@ import org.apache.camel.dsl.jbang.core.common.PathUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class BeansTab extends AbstractTableTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/BrowseTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/BrowseTab.java
index bde9b7a024da..b0aedb6f2d15 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/BrowseTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/BrowseTab.java
@@ -54,7 +54,7 @@ import org.apache.camel.dsl.jbang.core.common.PathUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class BrowseTab extends AbstractTab {
 
@@ -515,11 +515,11 @@ class BrowseTab extends AbstractTab {
     }
 
     private String sortLabel(String label, String column) {
-        return MonitorContext.sortLabel(label, column, sort, sortReversed);
+        return sortLabel(label, column, sort, sortReversed);
     }
 
     private Style sortStyle(String column) {
-        return MonitorContext.sortStyle(column, sort);
+        return sortStyle(column, sort);
     }
 
     private static String formatTimestamp(long ts) {
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 0bfbf251c13d..4241b9652446 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
@@ -64,8 +64,9 @@ import picocli.CommandLine;
 import picocli.CommandLine.Command;
 import sun.misc.Signal;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
 import static org.apache.camel.dsl.jbang.core.commands.tui.TabRegistry.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
 
 @Command(name = "monitor",
          description = "Live dashboard for monitoring Camel integrations",
@@ -773,7 +774,7 @@ public class CamelMonitor extends CamelCommand {
         // Tab bar clicks: detect which tab was clicked and switch to it
         if (me.isClick() && lastTabsArea != null && lastTabLabels != null) {
             int tabsY = lastTabsArea.height() >= 2 ? lastTabsArea.y() + 1 : 
lastTabsArea.y();
-            if (me.y() == tabsY && AbstractTab.contains(lastTabsArea, me.x(), 
me.y())) {
+            if (me.y() == tabsY && TuiHelper.contains(lastTabsArea, me.x(), 
me.y())) {
                 int clickedTab = findClickedTab(me.x() - lastTabsArea.x());
                 if (clickedTab >= 0) {
                     if (isInfraSelected()) {
@@ -789,7 +790,7 @@ public class CamelMonitor extends CamelCommand {
         }
 
         // Mouse events in the content area: delegate to the active tab
-        if (AbstractTab.contains(lastContentArea, me.x(), me.y())) {
+        if (TuiHelper.contains(lastContentArea, me.x(), me.y())) {
             if (popupManager.isMorePopupVisible() || 
popupManager.isSwitchPopupVisible()) {
                 return popupManager.handleMouseEvent(me, 
tabRegistry.selectedTabIndex(), TAB_LOG);
             }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CaptionOverlay.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CaptionOverlay.java
index 585658274a3a..e0db9b680868 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CaptionOverlay.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CaptionOverlay.java
@@ -31,8 +31,8 @@ import dev.tamboui.tui.event.KeyEvent;
 import dev.tamboui.widgets.Clear;
 import dev.tamboui.widgets.paragraph.Paragraph;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hint;
-import static 
org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hintLast;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hintLast;
 
 class CaptionOverlay {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CircuitBreakerTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CircuitBreakerTab.java
index 258013c47036..07d83f20b18b 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CircuitBreakerTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CircuitBreakerTab.java
@@ -42,7 +42,7 @@ import dev.tamboui.widgets.table.Table;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class CircuitBreakerTab extends AbstractTableTab {
 
@@ -164,9 +164,9 @@ class CircuitBreakerTab extends AbstractTableTab {
 
     @Override
     public void renderFooter(List<Span> spans) {
-        MonitorContext.hint(spans, "Esc", "back");
-        MonitorContext.hint(spans, "↑↓", "navigate");
-        MonitorContext.hint(spans, "s", "sort");
+        hint(spans, "Esc", "back");
+        hint(spans, "↑↓", "navigate");
+        hint(spans, "s", "sort");
     }
 
     private int sortCb(CircuitBreakerInfo a, CircuitBreakerInfo b) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ClasspathTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ClasspathTab.java
index 706def8d3a56..b19682610caf 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ClasspathTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ClasspathTab.java
@@ -47,7 +47,7 @@ import org.apache.camel.dsl.jbang.core.common.PathUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class ClasspathTab extends AbstractTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ConfigurationTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ConfigurationTab.java
index 6f4b910b0e02..883aa87c74ed 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ConfigurationTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ConfigurationTab.java
@@ -42,7 +42,7 @@ import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class ConfigurationTab extends AbstractTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ConsumersTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ConsumersTab.java
index bb48dd5c3638..e454fb50c8b2 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ConsumersTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ConsumersTab.java
@@ -36,7 +36,7 @@ import dev.tamboui.widgets.table.Table;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class ConsumersTab extends AbstractTableTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataRefreshService.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataRefreshService.java
index 6005b5aee136..4d449c991268 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataRefreshService.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataRefreshService.java
@@ -575,7 +575,7 @@ class DataRefreshService {
             PathUtils.writeTextSafely(action.toJson(), actionFile);
 
             // Poll for response
-            JsonObject response = MonitorContext.pollJsonResponse(outputFile, 
3000);
+            JsonObject response = TuiHelper.pollJsonResponse(outputFile, 3000);
             if (response != null) {
                 Boolean enabled = response.getBoolean("enabled");
                 if (enabled != null && enabled) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataSourceTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataSourceTab.java
index 955190fa1b3d..8bee8b5f0417 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataSourceTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataSourceTab.java
@@ -33,7 +33,7 @@ import dev.tamboui.widgets.table.Table;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class DataSourceTab extends AbstractTableTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
index fa48723a4758..1a710f3c6392 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
@@ -63,7 +63,8 @@ import org.apache.camel.dsl.jbang.core.common.PathUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
 
 class DiagramSupport {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
index 81210eba0ffe..97d7cfb0e380 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
@@ -40,7 +40,7 @@ import org.apache.camel.util.TimeUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class DiagramTab extends AbstractTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DoctorPopup.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DoctorPopup.java
index 9382ce867ee4..6678a4298e93 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DoctorPopup.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DoctorPopup.java
@@ -41,7 +41,7 @@ import org.apache.camel.dsl.jbang.core.common.VersionHelper;
 import org.apache.camel.tooling.maven.MavenDownloaderImpl;
 import org.apache.camel.tooling.maven.MavenResolutionException;
 
-import static 
org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hintLast;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hintLast;
 
 class DoctorPopup {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java
index 1b39eafcb398..d70facbf5c1b 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java
@@ -46,7 +46,7 @@ import dev.tamboui.widgets.table.Table;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class EndpointsTab extends AbstractTableTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
index 169be3b50754..31b1279c7ac5 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
@@ -45,7 +45,7 @@ import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 import org.apache.camel.util.json.Jsoner;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class ErrorsTab extends AbstractTableTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FilesBrowser.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FilesBrowser.java
index c15922a973aa..8df721a40fc8 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FilesBrowser.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FilesBrowser.java
@@ -263,9 +263,9 @@ class FilesBrowser {
         if (sourceViewer.isVisible()) {
             sourceViewer.renderFooter(spans);
         } else {
-            MonitorContext.hint(spans, "↑↓", "navigate");
-            MonitorContext.hint(spans, "Enter", "open");
-            MonitorContext.hint(spans, "Esc", "close");
+            TuiHelper.hint(spans, "↑↓", "navigate");
+            TuiHelper.hint(spans, "Enter", "open");
+            TuiHelper.hint(spans, "Esc", "close");
         }
     }
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HealthTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HealthTab.java
index d413bed5d477..eff82d38c861 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HealthTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HealthTab.java
@@ -35,7 +35,7 @@ import dev.tamboui.widgets.table.Table;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class HealthTab extends AbstractTableTab {
 
@@ -137,7 +137,7 @@ class HealthTab extends AbstractTableTab {
     @Override
     public void renderFooter(List<Span> spans) {
         super.renderFooter(spans);
-        MonitorContext.hint(spans, "d", "toggle DOWN");
+        hint(spans, "d", "toggle DOWN");
     }
 
     boolean isShowOnlyDown() {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HeapHistogramTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HeapHistogramTab.java
index 43728ed7a5da..39d25764c0e2 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HeapHistogramTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HeapHistogramTab.java
@@ -44,7 +44,7 @@ import org.apache.camel.dsl.jbang.core.common.PathUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class HeapHistogramTab extends AbstractTableTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HelpOverlay.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HelpOverlay.java
index c375384e20a7..d1ff39391854 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HelpOverlay.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HelpOverlay.java
@@ -31,8 +31,8 @@ import dev.tamboui.widgets.block.BorderType;
 import dev.tamboui.widgets.block.Borders;
 import dev.tamboui.widgets.block.Title;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hint;
-import static 
org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hintLast;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hintLast;
 
 class HelpOverlay {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HistoryTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HistoryTab.java
index 8c1595fba4ff..9bba7575a7f8 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HistoryTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HistoryTab.java
@@ -61,7 +61,7 @@ import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 import org.apache.camel.util.json.Jsoner;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class HistoryTab extends AbstractTab {
 
@@ -1174,9 +1174,9 @@ class HistoryTab extends AbstractTab {
                 default -> Style.EMPTY;
             };
             rows.add(Row.from(
-                    Cell.from(s.timestamp != null ? truncate(s.timestamp, 12) 
: ""),
+                    Cell.from(s.timestamp != null ? 
TuiHelper.truncate(s.timestamp, 12) : ""),
                     Cell.from(Span.styled(
-                            s.routeId != null ? truncate(s.routeId, 25) : "",
+                            s.routeId != null ? TuiHelper.truncate(s.routeId, 
25) : "",
                             Style.EMPTY.fg(Color.CYAN))),
                     Cell.from(Span.styled(s.status, statusStyle)),
                     rightCell(s.elapsed + "ms", 10),
@@ -1235,7 +1235,8 @@ class HistoryTab extends AbstractTab {
                     entry.timestamp, entry.routeId, entry.nodeId, 
entry.processor, desc, entry.elapsed, changes));
         }
 
-        String stepTitle = String.format(" Trace [%s] — %d steps ", 
truncate(traceSelectedExchangeId, 30), steps.size());
+        String stepTitle
+                = String.format(" Trace [%s] — %d steps ", 
TuiHelper.truncate(traceSelectedExchangeId, 30), steps.size());
         lastTraceStepArea = chunks.get(0);
         detailSplit.setBorderPos(chunks.get(1).y());
         frame.renderStatefulWidget(
@@ -1857,11 +1858,11 @@ class HistoryTab extends AbstractTab {
     }
 
     private String traceSortLabel(String label, String column) {
-        return MonitorContext.sortLabel(label, column, traceSort, 
traceSortReversed);
+        return sortLabel(label, column, traceSort, traceSortReversed);
     }
 
     private Style traceSortStyle(String column) {
-        return MonitorContext.sortStyle(column, traceSort);
+        return sortStyle(column, traceSort);
     }
 
     private static Row buildStepRow(
@@ -1882,9 +1883,9 @@ class HistoryTab extends AbstractTab {
         return Row.from(
                 rightCell(String.valueOf(stepNumber), 3),
                 Cell.from(Span.styled(direction, dirStyle)),
-                Cell.from(timestamp != null ? truncate(timestamp, 12) : ""),
-                Cell.from(Span.styled(routeId != null ? truncate(routeId, 25) 
: "", Style.EMPTY.fg(Color.CYAN))),
-                Cell.from(indent + (nodeId != null ? truncate(nodeId, 25) : 
"")),
+                Cell.from(timestamp != null ? TuiHelper.truncate(timestamp, 
12) : ""),
+                Cell.from(Span.styled(routeId != null ? 
TuiHelper.truncate(routeId, 25) : "", Style.EMPTY.fg(Color.CYAN))),
+                Cell.from(indent + (nodeId != null ? 
TuiHelper.truncate(nodeId, 25) : "")),
                 Cell.from(indent + display),
                 Cell.from(Line.from(changeSpans)),
                 rightCell(elapsedStr, 10));
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HttpTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HttpTab.java
index 0036599d6651..7bd712ea120f 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HttpTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HttpTab.java
@@ -61,7 +61,7 @@ import org.apache.camel.dsl.jbang.core.common.PathUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class HttpTab extends AbstractTableTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/InflightTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/InflightTab.java
index d83056e29062..2fdacf4c1db8 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/InflightTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/InflightTab.java
@@ -38,7 +38,7 @@ import org.apache.camel.util.TimeUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class InflightTab extends AbstractTableTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LogTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LogTab.java
index 266c7cd321c8..a6a697dcb466 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LogTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LogTab.java
@@ -57,7 +57,7 @@ import 
org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class LogTab extends AbstractTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/McpFacade.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/McpFacade.java
index 674c4a3f0f3e..fa9ba23ec8a3 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/McpFacade.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/McpFacade.java
@@ -40,7 +40,7 @@ import org.apache.camel.dsl.jbang.core.common.RuntimeHelper;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hint;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
 
 /**
  * Facade that exposes monitor state and actions to the MCP server.
@@ -451,7 +451,7 @@ class McpFacade {
             Path actionFile = ctx.getActionFile(pid);
             PathUtils.writeTextSafely(action.toJson(), actionFile);
 
-            JsonObject response = MonitorContext.pollJsonResponse(outputFile, 
3000);
+            JsonObject response = TuiHelper.pollJsonResponse(outputFile, 3000);
             if (response != null) {
                 PathUtils.deleteFile(outputFile);
                 Boolean enabled = response.getBoolean("enabled");
@@ -676,7 +676,7 @@ class McpFacade {
             JsonObject action = new JsonObject();
             action.put("action", "readme");
             PathUtils.writeTextSafely(action.toJson(), 
ctx.getActionFile(target.pid));
-            return MonitorContext.pollJsonResponse(outputFile, 5000);
+            return TuiHelper.pollJsonResponse(outputFile, 5000);
         } catch (Exception e) {
             return null;
         }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/McpLogPopup.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/McpLogPopup.java
index 91cae818a67e..a2e26e4b1f6c 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/McpLogPopup.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/McpLogPopup.java
@@ -41,8 +41,8 @@ import dev.tamboui.widgets.list.ScrollMode;
 import dev.tamboui.widgets.paragraph.Paragraph;
 import org.apache.camel.util.json.Jsoner;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hint;
-import static 
org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hintLast;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hintLast;
 
 class McpLogPopup {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MemoryTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MemoryTab.java
index ad84abbf9042..e68c23de8117 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MemoryTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MemoryTab.java
@@ -42,7 +42,7 @@ import org.apache.camel.dsl.jbang.core.common.PathUtils;
 import org.apache.camel.util.TimeUtils;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class MemoryTab extends AbstractTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MetricsTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MetricsTab.java
index c971926943d0..231c60e87eb3 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MetricsTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MetricsTab.java
@@ -52,7 +52,7 @@ import dev.tamboui.widgets.table.Table;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class MetricsTab extends AbstractTableTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContext.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContext.java
index 2dfac4cc824e..8446ad605148 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContext.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContext.java
@@ -16,46 +16,18 @@
  */
 package org.apache.camel.dsl.jbang.core.commands.tui;
 
-import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
-import dev.tamboui.layout.Rect;
-import dev.tamboui.style.Color;
-import dev.tamboui.style.Style;
-import dev.tamboui.terminal.Frame;
-import dev.tamboui.text.Line;
-import dev.tamboui.text.Span;
-import dev.tamboui.text.Text;
 import dev.tamboui.tui.TuiRunner;
-import dev.tamboui.widgets.block.Block;
-import dev.tamboui.widgets.block.BorderType;
-import dev.tamboui.widgets.block.Borders;
-import dev.tamboui.widgets.block.Title;
-import dev.tamboui.widgets.paragraph.Paragraph;
-import dev.tamboui.widgets.table.Cell;
-import dev.tamboui.widgets.table.Row;
 import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
-import org.apache.camel.util.json.JsonObject;
-import org.apache.camel.util.json.Jsoner;
 
 /**
- * Shared state and utilities accessible to all {@link MonitorTab} 
implementations.
+ * Shared state accessible to all {@link MonitorTab} implementations.
  */
 class MonitorContext {
 
-    /** Small flat-orange camel for empty / no-selection states. */
-    static final String[] SMALL_CAMEL = {
-            " ,,__",
-            "/o.  \\___/\\",
-            "\\__/       \\",
-            "   |   |   |",
-            "   |   |   |~",
-            "  (_) (_) (_)",
-    };
-
     final AtomicReference<List<IntegrationInfo>> data;
     final AtomicReference<List<InfraInfo>> infraData;
     TuiRunner runner;
@@ -119,201 +91,4 @@ class MonitorContext {
         return CommandLineHelper.getCamelDir().resolve(pid + "-trace.json");
     }
 
-    static JsonObject pollJsonResponse(Path outputFile, long timeout) {
-        long start = System.currentTimeMillis();
-        while (System.currentTimeMillis() - start < timeout) {
-            try {
-                Thread.sleep(100);
-                if (Files.exists(outputFile) && outputFile.toFile().length() > 
0) {
-                    String text = Files.readString(outputFile);
-                    return (JsonObject) Jsoner.deserialize(text);
-                }
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-                return null;
-            } catch (Exception e) {
-                // ignore
-            }
-        }
-        return null;
-    }
-
-    static void hint(List<Span> spans, String key, String label) {
-        spans.add(Span.styled(" " + key + " ", Theme.hintKey()));
-        spans.add(Span.raw(" " + label + "  "));
-    }
-
-    static void hintLast(List<Span> spans, String key, String label) {
-        spans.add(Span.styled(" " + key + " ", Theme.hintKey()));
-        spans.add(Span.raw(" " + label));
-    }
-
-    static void renderNoSelection(Frame frame, Rect area) {
-        List<Line> lines = new ArrayList<>();
-        lines.add(Line.from(Span.raw("")));
-        for (String row : SMALL_CAMEL) {
-            lines.add(Line.from(Span.styled("   " + row, 
Style.EMPTY.fg(Theme.accent()))));
-        }
-        lines.add(Line.from(Span.raw("")));
-        List<Span> hintSpans = new ArrayList<>();
-        hintSpans.add(Span.raw("   No integration selected.  "));
-        hint(hintSpans, "1", "Overview");
-        hint(hintSpans, "?", "Help");
-        lines.add(Line.from(hintSpans));
-
-        frame.renderWidget(
-                Paragraph.builder()
-                        .text(Text.from(lines))
-                        
.block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL)
-                                .title(Title.from(Line.from(
-                                        Span.styled(" No integration selected 
", Theme.title()))))
-                                .build())
-                        .build(),
-                area);
-    }
-
-    static String truncate(String s, int max) {
-        return TuiHelper.truncate(s, max);
-    }
-
-    static Cell rightCell(String text, int width) {
-        return Cell.from(String.format("%" + width + "s", text));
-    }
-
-    static Cell rightCell(String text, int width, Style style) {
-        return Cell.from(Span.styled(String.format("%" + width + "s", text), 
style));
-    }
-
-    static Cell centerCell(String text, int width) {
-        int len = text.length();
-        int padding = Math.max(0, width - len);
-        int leftPad = padding / 2;
-        return Cell.from(" ".repeat(leftPad) + text);
-    }
-
-    static Cell centerCell(String text, int width, Style style) {
-        int len = text.length();
-        int padding = Math.max(0, width - len);
-        int leftPad = padding / 2;
-        return Cell.from(Span.styled(" ".repeat(leftPad) + text, style));
-    }
-
-    static Row emptyRow(String message, int columnCount) {
-        Cell[] cells = new Cell[columnCount];
-        cells[0] = Cell.from(Span.styled(message, Style.EMPTY.dim()));
-        for (int i = 1; i < columnCount; i++) {
-            cells[i] = Cell.from("");
-        }
-        return Row.from(cells);
-    }
-
-    static String sortLabel(String label, String column, String currentSort, 
boolean reversed) {
-        return currentSort.equals(column) ? label + (reversed ? "▲" : "▼") : 
label;
-    }
-
-    static Style sortStyle(String column, String currentSort) {
-        return currentSort.equals(column)
-                ? Style.EMPTY.fg(Color.YELLOW).bold()
-                : Style.EMPTY.bold();
-    }
-
-    static String formatSinceLast(IntegrationInfo info) {
-        return formatSinceLast(info.sinceLastStarted, info.sinceLastCompleted, 
info.sinceLastFailed);
-    }
-
-    static String formatSinceLast(String started, String completed, String 
failed) {
-        StringBuilder sb = new StringBuilder();
-        if (started != null) {
-            sb.append(started);
-        }
-        if (completed != null) {
-            if (!sb.isEmpty()) {
-                sb.append('/');
-            }
-            sb.append(completed);
-        }
-        if (failed != null) {
-            if (!sb.isEmpty()) {
-                sb.append('/');
-            }
-            sb.append(failed);
-        }
-        return sb.toString();
-    }
-
-    static String formatSinceLastRoute(RouteInfo route) {
-        return formatSinceLast(route.sinceLastStarted, 
route.sinceLastCompleted, route.sinceLastFailed);
-    }
-
-    static String formatLoad(String l1, String l5, String l15) {
-        String s1 = l1 != null && !"0.00".equals(l1) ? l1 : "0";
-        String s5 = l5 != null && !"0.00".equals(l5) ? l5 : "0";
-        String s15 = l15 != null && !"0.00".equals(l15) ? l15 : "0";
-        return s1 + "/" + s5 + "/" + s15;
-    }
-
-    static String formatMemory(long used, long max) {
-        if (used <= 0) {
-            return "";
-        }
-        String u = formatBytes(used);
-        if (max > 0) {
-            return u + "/" + formatBytes(max);
-        }
-        return u;
-    }
-
-    static String formatBytes(long bytes) {
-        if (bytes < 1024) {
-            return bytes + "B";
-        }
-        if (bytes < 1024 * 1024) {
-            return (bytes / 1024) + "K";
-        }
-        return (bytes / (1024 * 1024)) + "M";
-    }
-
-    static String formatThreads(int count, int peak) {
-        if (count <= 0) {
-            return "";
-        }
-        return count + "/" + peak;
-    }
-
-    static Style topTimeStyle(long ms) {
-        if (ms >= 1000) {
-            return Style.EMPTY.fg(Color.LIGHT_RED).bold();
-        } else if (ms >= 100) {
-            return Style.EMPTY.fg(Color.YELLOW);
-        }
-        return Style.EMPTY;
-    }
-
-    static Style topDeltaStyle(long delta) {
-        if (delta > 0) {
-            return Style.EMPTY.fg(Color.LIGHT_RED);
-        } else if (delta < 0) {
-            return Style.EMPTY.fg(Color.GREEN);
-        }
-        return Style.EMPTY;
-    }
-
-    static String buildBar(long value, long maxValue, int maxWidth) {
-        if (value <= 0 || maxValue <= 0) {
-            return "";
-        }
-        int len = (int) Math.round((double) value / maxValue * maxWidth);
-        len = Math.max(len > 0 ? 1 : 0, Math.min(len, maxWidth));
-        return "█".repeat(len);
-    }
-
-    static int compareStr(String a, String b) {
-        if (a == null && b == null)
-            return 0;
-        if (a == null)
-            return 1;
-        if (b == null)
-            return -1;
-        return a.compareToIgnoreCase(b);
-    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorTab.java
index 226a862e0200..8520d2b5c9d0 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorTab.java
@@ -43,15 +43,20 @@ interface MonitorTab {
         return false;
     }
 
-    boolean handleEscape();
+    default boolean handleEscape() {
+        return false;
+    }
 
-    void navigateUp();
+    default void navigateUp() {
+    }
 
-    void navigateDown();
+    default void navigateDown() {
+    }
 
     void render(Frame frame, Rect area);
 
-    void renderFooter(List<Span> spans);
+    default void renderFooter(List<Span> spans) {
+    }
 
     default void onTabSelected() {
     }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OverviewTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OverviewTab.java
index 4338b9309ce4..af1ea4c72b7f 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OverviewTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OverviewTab.java
@@ -51,7 +51,7 @@ import dev.tamboui.widgets.table.TableState;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 import static 
org.apache.camel.dsl.jbang.core.common.CamelCommandHelper.extractState;
 
 class OverviewTab extends AbstractTab {
@@ -838,11 +838,11 @@ class OverviewTab extends AbstractTab {
     }
 
     private String sortLabel(String label, String column) {
-        return MonitorContext.sortLabel(label, column, sort, sortReversed);
+        return sortLabel(label, column, sort, sortReversed);
     }
 
     private Style sortStyle(String column) {
-        return MonitorContext.sortStyle(column, sort);
+        return sortStyle(column, sort);
     }
 
     @Override
@@ -967,7 +967,7 @@ class OverviewTab extends AbstractTab {
     private void renderEmptyState(Frame frame, Rect area) {
         List<Line> lines = new ArrayList<>();
         lines.add(Line.from(Span.raw("")));
-        for (String row : MonitorContext.SMALL_CAMEL) {
+        for (String row : TuiHelper.SMALL_CAMEL) {
             lines.add(Line.from(Span.styled("     " + row, 
Style.EMPTY.fg(Theme.accent()).bold())));
         }
         lines.add(Line.from(Span.styled("     No Active Camel Integrations 
Found", Theme.title())));
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/PopupManager.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/PopupManager.java
index 345a603954db..1ecfd2809d5d 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/PopupManager.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/PopupManager.java
@@ -258,7 +258,7 @@ class PopupManager {
         if (lastMorePopupRect == null) {
             return false;
         }
-        boolean inside = AbstractTab.contains(lastMorePopupRect, me.x(), 
me.y());
+        boolean inside = TuiHelper.contains(lastMorePopupRect, me.x(), me.y());
 
         // Click outside the popup closes it
         if (me.isClick() && !inside) {
@@ -299,7 +299,7 @@ class PopupManager {
             return false;
         }
         List<IntegrationInfo> switchList = 
nonVanishingIntegrationsSupplier.get();
-        boolean inside = AbstractTab.contains(lastSwitchPopupRect, me.x(), 
me.y());
+        boolean inside = TuiHelper.contains(lastSwitchPopupRect, me.x(), 
me.y());
 
         if (me.isClick() && !inside) {
             showSwitchPopup = false;
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ProcessTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ProcessTab.java
index 22a438c260bf..a3e0827c6a70 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ProcessTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ProcessTab.java
@@ -40,7 +40,7 @@ import dev.tamboui.widgets.scrollbar.Scrollbar;
 import dev.tamboui.widgets.scrollbar.ScrollbarState;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class ProcessTab extends AbstractTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RoutesTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RoutesTab.java
index 6bdf283beec9..698fedbaf022 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RoutesTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RoutesTab.java
@@ -48,7 +48,7 @@ import org.apache.camel.util.TimeUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class RoutesTab extends AbstractTab {
 
@@ -1285,19 +1285,19 @@ class RoutesTab extends AbstractTab {
     }
 
     private String routeSortLabel(String label, String column) {
-        return MonitorContext.sortLabel(label, column, routeSort, 
routeSortReversed);
+        return sortLabel(label, column, routeSort, routeSortReversed);
     }
 
     private Style routeSortStyle(String column) {
-        return MonitorContext.sortStyle(column, routeSort);
+        return sortStyle(column, routeSort);
     }
 
     private String routeTopSortLabel(String label, String column) {
-        return MonitorContext.sortLabel(label, column, routeTopSort, 
routeTopSortReversed);
+        return sortLabel(label, column, routeTopSort, routeTopSortReversed);
     }
 
     private Style routeTopSortStyle(String column) {
-        return MonitorContext.sortStyle(column, routeTopSort);
+        return sortStyle(column, routeTopSort);
     }
 
     // ---- Route actions ----
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RunOptionsForm.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RunOptionsForm.java
index ca29642fff48..27bbfdf87646 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RunOptionsForm.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RunOptionsForm.java
@@ -34,8 +34,8 @@ import dev.tamboui.widgets.input.TextInput;
 import dev.tamboui.widgets.input.TextInputState;
 import dev.tamboui.widgets.paragraph.Paragraph;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hint;
-import static 
org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hintLast;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hintLast;
 
 class RunOptionsForm {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SearchHighlighter.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SearchHighlighter.java
index 49a90dadfc2e..a322e4d7b34a 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SearchHighlighter.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SearchHighlighter.java
@@ -30,7 +30,9 @@ import dev.tamboui.tui.event.KeyCode;
 import dev.tamboui.tui.event.KeyEvent;
 import dev.tamboui.widgets.input.TextInputState;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hintLast;
 
 /**
  * Shared find/highlight search logic used by LogTab and SourceViewer.
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SendMessagePopup.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SendMessagePopup.java
index 04661c6cfa39..2137a88cf85b 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SendMessagePopup.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SendMessagePopup.java
@@ -47,7 +47,9 @@ import org.apache.camel.dsl.jbang.core.common.PathUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hintLast;
 
 class SendMessagePopup {
 
@@ -442,7 +444,7 @@ class SendMessagePopup {
                 Path actionFile = ctx.getActionFile(targetPid);
                 PathUtils.writeTextSafely(root.toJson(), actionFile);
 
-                JsonObject response = 
MonitorContext.pollJsonResponse(outputFile, 25000);
+                JsonObject response = TuiHelper.pollJsonResponse(outputFile, 
25000);
                 PathUtils.deleteFile(outputFile);
 
                 if (response == null) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ShellPanel.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ShellPanel.java
index daabad94ad64..2f58b6ff00c0 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ShellPanel.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ShellPanel.java
@@ -197,7 +197,7 @@ class ShellPanel {
         if (!visible || lastArea == null) {
             return false;
         }
-        if (!AbstractTab.contains(lastArea, me.x(), me.y())) {
+        if (!TuiHelper.contains(lastArea, me.x(), me.y())) {
             return false;
         }
         if (me.kind() == MouseEventKind.SCROLL_UP) {
@@ -335,9 +335,9 @@ class ShellPanel {
     }
 
     void renderFooter(List<Span> spans) {
-        MonitorContext.hint(spans, "F6", "close");
-        MonitorContext.hint(spans, "Shift+F6", "resize (" + 
anim.cyclePercent() + "%)");
-        MonitorContext.hint(spans, "PgUp/Dn", "scroll");
+        TuiHelper.hint(spans, "F6", "close");
+        TuiHelper.hint(spans, "Shift+F6", "resize (" + anim.cyclePercent() + 
"%)");
+        TuiHelper.hint(spans, "PgUp/Dn", "scroll");
     }
 
     private List<Line> renderLiveView(long[] screen, int width, int height) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
index 6350d1adb036..8dc3a4d23316 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
@@ -51,7 +51,7 @@ import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 import org.apache.camel.util.json.Jsoner;
 
-import static 
org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.pollJsonResponse;
+import static 
org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.pollJsonResponse;
 
 /**
  * Reusable source code viewer with syntax highlighting, scrolling, and 
line-number display. Can be used by any tab that
@@ -305,22 +305,22 @@ class SourceViewer {
         if (search.hasFindTerm()) {
             search.renderFindStatus(spans);
         } else {
-            MonitorContext.hint(spans, "Esc/c", "close");
+            TuiHelper.hint(spans, "Esc/c", "close");
         }
-        MonitorContext.hint(spans, "↑↓", "navigate");
+        TuiHelper.hint(spans, "↑↓", "navigate");
         if (currentRouteId != null) {
-            MonitorContext.hint(spans, "Y", "yaml");
-            MonitorContext.hint(spans, "J", "java");
-            MonitorContext.hint(spans, "X", "xml");
+            TuiHelper.hint(spans, "Y", "yaml");
+            TuiHelper.hint(spans, "J", "java");
+            TuiHelper.hint(spans, "X", "xml");
         }
         search.renderSearchHints(spans);
-        MonitorContext.hint(spans, "w", "wrap" + (wordWrap ? " [on]" : " 
[off]"));
+        TuiHelper.hint(spans, "w", "wrap" + (wordWrap ? " [on]" : " [off]"));
         if (!wordWrap) {
-            MonitorContext.hint(spans, "←→", "horizontal");
+            TuiHelper.hint(spans, "←→", "horizontal");
         }
-        MonitorContext.hint(spans, "PgUp/PgDn", "page");
+        TuiHelper.hint(spans, "PgUp/PgDn", "page");
         if (onLineSelected != null) {
-            MonitorContext.hint(spans, "Enter", "select node");
+            TuiHelper.hint(spans, "Enter", "select node");
         }
     }
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SpansTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SpansTab.java
index 29fdef1e0137..85d5e5de9667 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SpansTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SpansTab.java
@@ -54,6 +54,8 @@ import dev.tamboui.widgets.table.TableState;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
+
 class SpansTab extends AbstractTab {
 
     private static final int MOUSE_SCROLL_LINES = 3;
@@ -295,7 +297,7 @@ class SpansTab extends AbstractTab {
     public void render(Frame frame, Rect area) {
         IntegrationInfo info = ctx.findSelectedIntegration();
         if (info == null) {
-            MonitorContext.renderNoSelection(frame, area);
+            renderNoSelection(frame, area);
             return;
         }
 
@@ -374,12 +376,12 @@ class SpansTab extends AbstractTab {
                     Cell.from(shortId(ts.traceId)),
                     Cell.from(ts.rootRouteId != null ? ts.rootRouteId : ""),
                     Cell.from(ts.rootName != null ? ts.rootName : "?"),
-                    MonitorContext.rightCell(String.valueOf(ts.spanCount), 5),
-                    MonitorContext.rightCell(String.valueOf(ts.routeCount), 5),
+                    rightCell(String.valueOf(ts.spanCount), 5),
+                    rightCell(String.valueOf(ts.routeCount), 5),
                     Cell.from(ts.remoteComponents.isEmpty() ? "-" : 
ts.remoteComponents),
                     Cell.from(Span.styled(ts.hasError ? "ERROR" : "OK", 
statusStyle)),
                     Cell.from(ts.totalDurationMs + "ms"),
-                    MonitorContext.rightCell(String.valueOf(ts.maxDepth), 5)));
+                    rightCell(String.valueOf(ts.maxDepth), 5)));
         }
 
         String title;
@@ -641,28 +643,28 @@ class SpansTab extends AbstractTab {
     @Override
     public void renderFooter(List<Span> spans) {
         if (waterfallView) {
-            MonitorContext.hint(spans, "Esc", "back");
-            MonitorContext.hint(spans, "F5", "refresh");
-            MonitorContext.hint(spans, "c", camelOnly ? "camel-only [on]" : 
"camel-only [off]");
-            MonitorContext.hint(spans, "p", showProcessors ? "processors [on]" 
: "processors [off]");
-            MonitorContext.hint(spans, "↑↓", "navigate");
-            MonitorContext.hintLast(spans, "PgUp/Dn", "page");
+            hint(spans, "Esc", "back");
+            hint(spans, "F5", "refresh");
+            hint(spans, "c", camelOnly ? "camel-only [on]" : "camel-only 
[off]");
+            hint(spans, "p", showProcessors ? "processors [on]" : "processors 
[off]");
+            hint(spans, "↑↓", "navigate");
+            hintLast(spans, "PgUp/Dn", "page");
         } else if (filterInputActive) {
             spans.add(Span.styled(" /", Style.EMPTY.fg(Color.YELLOW).bold()));
             spans.add(Span.raw(filterInputState.text() + "█  "));
-            MonitorContext.hint(spans, "Enter", "filter");
-            MonitorContext.hintLast(spans, "Esc", "cancel");
+            hint(spans, "Enter", "filter");
+            hintLast(spans, "Esc", "cancel");
         } else {
-            MonitorContext.hint(spans, "Esc", filterTerm != null ? "clear" : 
"back");
-            MonitorContext.hint(spans, "F5", "refresh");
-            MonitorContext.hint(spans, "Enter", "waterfall");
+            hint(spans, "Esc", filterTerm != null ? "clear" : "back");
+            hint(spans, "F5", "refresh");
+            hint(spans, "Enter", "waterfall");
             if (filterTerm != null) {
                 spans.add(Span.styled("  /", 
Style.EMPTY.fg(Color.YELLOW).bold()));
                 spans.add(Span.raw("\"" + filterTerm + "\"  "));
             } else {
-                MonitorContext.hint(spans, "/", "filter");
+                hint(spans, "/", "filter");
             }
-            MonitorContext.hintLast(spans, "↑↓", "navigate");
+            hintLast(spans, "↑↓", "navigate");
         }
     }
 
@@ -949,7 +951,7 @@ class SpansTab extends AbstractTab {
     }
 
     private String sortLabel(String label, String column) {
-        return MonitorContext.sortLabel(label, column, sortColumn, 
sortReversed);
+        return sortLabel(label, column, sortColumn, sortReversed);
     }
 
     private Style sortStyle(String column) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SqlQueryTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SqlQueryTab.java
index 5db2f592147a..6b6af98490e8 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SqlQueryTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SqlQueryTab.java
@@ -52,7 +52,7 @@ import org.apache.camel.dsl.jbang.core.common.PathUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class SqlQueryTab extends AbstractTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SqlTraceTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SqlTraceTab.java
index 30eb57254ea7..4701b41d23dc 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SqlTraceTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SqlTraceTab.java
@@ -46,7 +46,7 @@ import dev.tamboui.widgets.table.Table;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class SqlTraceTab extends AbstractTableTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/StartupTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/StartupTab.java
index 8f038bb41777..48337147cc30 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/StartupTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/StartupTab.java
@@ -45,7 +45,7 @@ import org.apache.camel.dsl.jbang.core.common.PathUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class StartupTab extends AbstractTab {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/StopAllPopup.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/StopAllPopup.java
index 267d71406b3e..4598d2cb77e0 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/StopAllPopup.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/StopAllPopup.java
@@ -36,8 +36,8 @@ import dev.tamboui.widgets.paragraph.Paragraph;
 import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
 import org.apache.camel.dsl.jbang.core.common.PathUtils;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hint;
-import static 
org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hintLast;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hintLast;
 
 class StopAllPopup {
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ThreadsTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ThreadsTab.java
index 91dbc03b3035..f5fb6889c85a 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ThreadsTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ThreadsTab.java
@@ -45,7 +45,7 @@ import org.apache.camel.dsl.jbang.core.common.PathUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class ThreadsTab extends AbstractTableTab {
 
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 586d04ec5a0c..b3889d1477ee 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
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Function;
 
+import dev.tamboui.layout.Rect;
 import dev.tamboui.style.AnsiColor;
 import dev.tamboui.style.Color;
 import dev.tamboui.style.Style;
@@ -427,6 +428,157 @@ final class TuiHelper {
         return DURATION_BAND_STYLES[bandIndex];
     }
 
+    // ---- UI helpers ----
+
+    static void hint(List<Span> spans, String key, String label) {
+        spans.add(Span.styled(" " + key + " ", Theme.hintKey()));
+        spans.add(Span.raw(" " + label + "  "));
+    }
+
+    static void hintLast(List<Span> spans, String key, String label) {
+        spans.add(Span.styled(" " + key + " ", Theme.hintKey()));
+        spans.add(Span.raw(" " + label));
+    }
+
+    static boolean contains(Rect rect, int x, int y) {
+        return rect != null
+                && x >= rect.x() && x < rect.x() + rect.width()
+                && y >= rect.y() && y < rect.y() + rect.height();
+    }
+
+    static int compareStr(String a, String b) {
+        if (a == null && b == null) {
+            return 0;
+        }
+        if (a == null) {
+            return 1;
+        }
+        if (b == null) {
+            return -1;
+        }
+        return a.compareToIgnoreCase(b);
+    }
+
+    // ---- Data formatting helpers ----
+
+    static final String[] SMALL_CAMEL = {
+            " ,,__",
+            "/o.  \\___/\\",
+            "\\__/       \\",
+            "   |   |   |",
+            "   |   |   |~",
+            "  (_) (_) (_)",
+    };
+
+    static JsonObject pollJsonResponse(Path outputFile, long timeout) {
+        long start = System.currentTimeMillis();
+        while (System.currentTimeMillis() - start < timeout) {
+            try {
+                Thread.sleep(100);
+                if (Files.exists(outputFile) && outputFile.toFile().length() > 
0) {
+                    String text = Files.readString(outputFile);
+                    return (JsonObject) Jsoner.deserialize(text);
+                }
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                return null;
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+        return null;
+    }
+
+    static String formatSinceLast(IntegrationInfo info) {
+        return formatSinceLast(info.sinceLastStarted, info.sinceLastCompleted, 
info.sinceLastFailed);
+    }
+
+    static String formatSinceLast(String started, String completed, String 
failed) {
+        StringBuilder sb = new StringBuilder();
+        if (started != null) {
+            sb.append(started);
+        }
+        if (completed != null) {
+            if (!sb.isEmpty()) {
+                sb.append('/');
+            }
+            sb.append(completed);
+        }
+        if (failed != null) {
+            if (!sb.isEmpty()) {
+                sb.append('/');
+            }
+            sb.append(failed);
+        }
+        return sb.toString();
+    }
+
+    static String formatSinceLastRoute(RouteInfo route) {
+        return formatSinceLast(route.sinceLastStarted, 
route.sinceLastCompleted, route.sinceLastFailed);
+    }
+
+    static String formatLoad(String l1, String l5, String l15) {
+        String s1 = l1 != null && !"0.00".equals(l1) ? l1 : "0";
+        String s5 = l5 != null && !"0.00".equals(l5) ? l5 : "0";
+        String s15 = l15 != null && !"0.00".equals(l15) ? l15 : "0";
+        return s1 + "/" + s5 + "/" + s15;
+    }
+
+    static String formatMemory(long used, long max) {
+        if (used <= 0) {
+            return "";
+        }
+        String u = formatBytes(used);
+        if (max > 0) {
+            return u + "/" + formatBytes(max);
+        }
+        return u;
+    }
+
+    static String formatBytes(long bytes) {
+        if (bytes < 1024) {
+            return bytes + "B";
+        }
+        if (bytes < 1024 * 1024) {
+            return (bytes / 1024) + "K";
+        }
+        return (bytes / (1024 * 1024)) + "M";
+    }
+
+    static String formatThreads(int count, int peak) {
+        if (count <= 0) {
+            return "";
+        }
+        return count + "/" + peak;
+    }
+
+    static Style topTimeStyle(long ms) {
+        if (ms >= 1000) {
+            return Style.EMPTY.fg(Color.LIGHT_RED).bold();
+        } else if (ms >= 100) {
+            return Style.EMPTY.fg(Color.YELLOW);
+        }
+        return Style.EMPTY;
+    }
+
+    static Style topDeltaStyle(long delta) {
+        if (delta > 0) {
+            return Style.EMPTY.fg(Color.LIGHT_RED);
+        } else if (delta < 0) {
+            return Style.EMPTY.fg(Color.GREEN);
+        }
+        return Style.EMPTY;
+    }
+
+    static String buildBar(long value, long maxValue, int maxWidth) {
+        if (value <= 0 || maxValue <= 0) {
+            return "";
+        }
+        int len = (int) Math.round((double) value / maxValue * maxWidth);
+        len = Math.max(len > 0 ? 1 : 0, Math.min(len, maxWidth));
+        return "█".repeat(len);
+    }
+
     static String shortTypeName(String type) {
         if (type == null) {
             return "null";
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitorTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitorTest.java
index 09925b08a261..7b154e5c86e1 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitorTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitorTest.java
@@ -24,7 +24,7 @@ import dev.tamboui.tui.event.KeyCode;
 import dev.tamboui.tui.event.KeyEvent;
 import org.junit.jupiter.api.Test;
 
-import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.hint;
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hint;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContextRenderTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContextRenderTest.java
index d299f8d0eafe..1cd58e629761 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContextRenderTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContextRenderTest.java
@@ -41,7 +41,7 @@ class MonitorContextRenderTest {
         Buffer buffer = Buffer.empty(area);
         Frame frame = Frame.forTesting(buffer);
 
-        MonitorContext.renderNoSelection(frame, area);
+        AbstractTab.renderNoSelection(frame, area);
 
         String rendered = HealthTabRenderTest.bufferToString(buffer);
         assertTrue(rendered.contains("No integration selected"),
@@ -54,7 +54,7 @@ class MonitorContextRenderTest {
         Buffer buffer = Buffer.empty(area);
         Frame frame = Frame.forTesting(buffer);
 
-        MonitorContext.renderNoSelection(frame, area);
+        AbstractTab.renderNoSelection(frame, area);
 
         String rendered = HealthTabRenderTest.bufferToString(buffer);
         // The block title and prompt text should appear in the buffer
@@ -68,7 +68,7 @@ class MonitorContextRenderTest {
         Buffer buffer = Buffer.empty(area);
         Frame frame = Frame.forTesting(buffer);
 
-        MonitorContext.renderNoSelection(frame, area);
+        AbstractTab.renderNoSelection(frame, area);
 
         boolean foundBold = false;
         for (int y = 0; y < buffer.height(); y++) {
@@ -90,7 +90,7 @@ class MonitorContextRenderTest {
     @Test
     void hintAddsKeyAndLabel() {
         List<Span> spans = new ArrayList<>();
-        MonitorContext.hint(spans, "Esc", "back");
+        TuiHelper.hint(spans, "Esc", "back");
 
         assertEquals(2, spans.size(), "hint should add exactly 2 spans");
         assertTrue(spans.get(0).content().contains("Esc"), "First span should 
contain the key");
@@ -100,7 +100,7 @@ class MonitorContextRenderTest {
     @Test
     void hintKeyUsesThemeBoldStyle() {
         List<Span> spans = new ArrayList<>();
-        MonitorContext.hint(spans, "s", "sort");
+        TuiHelper.hint(spans, "s", "sort");
 
         Span keySpan = spans.get(0);
         assertTrue(keySpan.style().fg().isPresent(), "Key span should have a 
foreground color");
@@ -112,7 +112,7 @@ class MonitorContextRenderTest {
     @Test
     void hintLabelHasTrailingSpaces() {
         List<Span> spans = new ArrayList<>();
-        MonitorContext.hint(spans, "x", "action");
+        TuiHelper.hint(spans, "x", "action");
 
         Span labelSpan = spans.get(1);
         assertTrue(labelSpan.content().endsWith("  "),
@@ -122,7 +122,7 @@ class MonitorContextRenderTest {
     @Test
     void hintLastDoesNotHaveTrailingSpaces() {
         List<Span> spans = new ArrayList<>();
-        MonitorContext.hintLast(spans, "q", "quit");
+        TuiHelper.hintLast(spans, "q", "quit");
 
         Span labelSpan = spans.get(1);
         assertEquals(" quit", labelSpan.content(),
@@ -131,7 +131,7 @@ class MonitorContextRenderTest {
 
     @Test
     void rightCellRendersRightAligned() {
-        var cell = MonitorContext.rightCell("42", 8);
+        var cell = AbstractTab.rightCell("42", 8);
         // rightCell uses String.format("%8s", "42") → "      42"
         String content = extractCellContent(cell);
         assertTrue(content.endsWith("42"), "Content should end with the 
value");
@@ -140,7 +140,7 @@ class MonitorContextRenderTest {
 
     @Test
     void rightCellWithStyleAppliesStyle() {
-        var cell = MonitorContext.rightCell("5", 6, 
dev.tamboui.style.Style.EMPTY.fg(Color.LIGHT_RED));
+        var cell = AbstractTab.rightCell("5", 6, 
dev.tamboui.style.Style.EMPTY.fg(Color.LIGHT_RED));
         // The cell should have styled content
         String content = extractCellContent(cell);
         assertTrue(content.contains("5"), "Should contain the value");
@@ -148,7 +148,7 @@ class MonitorContextRenderTest {
 
     @Test
     void centerCellCentersText() {
-        var cell = MonitorContext.centerCell("x", 6);
+        var cell = AbstractTab.centerCell("x", 6);
         String content = extractCellContent(cell);
         // "x" centered in width 6: "  x" (leftPad = (6-1)/2 = 2)
         assertTrue(content.startsWith("  "), "Content should have leading 
padding");
@@ -157,22 +157,22 @@ class MonitorContextRenderTest {
 
     @Test
     void sortLabelShowsIndicatorForActiveColumn() {
-        String label = MonitorContext.sortLabel("NAME", "name", "name", false);
+        String label = AbstractTab.sortLabel("NAME", "name", "name", false);
         assertEquals("NAME▼", label, "Active sort column should have 
descending indicator");
 
-        String reversed = MonitorContext.sortLabel("NAME", "name", "name", 
true);
+        String reversed = AbstractTab.sortLabel("NAME", "name", "name", true);
         assertEquals("NAME▲", reversed, "Reversed sort should have ascending 
indicator");
     }
 
     @Test
     void sortLabelNoIndicatorForInactiveColumn() {
-        String label = MonitorContext.sortLabel("NAME", "name", "status", 
false);
+        String label = AbstractTab.sortLabel("NAME", "name", "status", false);
         assertEquals("NAME", label, "Inactive column should have no 
indicator");
     }
 
     @Test
     void sortStyleActiveColumnIsYellowBold() {
-        var style = MonitorContext.sortStyle("name", "name");
+        var style = AbstractTab.sortStyle("name", "name");
         assertEquals(Color.YELLOW, style.fg().orElse(null), "Active sort 
column should be YELLOW");
         
assertTrue(style.effectiveModifiers().contains(dev.tamboui.style.Modifier.BOLD),
                 "Active sort column should be BOLD");
@@ -180,7 +180,7 @@ class MonitorContextRenderTest {
 
     @Test
     void sortStyleInactiveColumnIsBoldOnly() {
-        var style = MonitorContext.sortStyle("name", "status");
+        var style = AbstractTab.sortStyle("name", "status");
         assertTrue(style.fg().isEmpty() || 
!Color.YELLOW.equals(style.fg().get()),
                 "Inactive column should not be YELLOW");
         
assertTrue(style.effectiveModifiers().contains(dev.tamboui.style.Modifier.BOLD),
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContextTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContextTest.java
index 58cbf0b67b4b..daff89970204 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContextTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContextTest.java
@@ -30,37 +30,37 @@ class MonitorContextTest {
 
     @Test
     void formatSinceLastAllThreePresent() {
-        String result = MonitorContext.formatSinceLast("1s", "2s", "3s");
+        String result = TuiHelper.formatSinceLast("1s", "2s", "3s");
         assertEquals("1s/2s/3s", result);
     }
 
     @Test
     void formatSinceLastOnlyStarted() {
-        String result = MonitorContext.formatSinceLast("5s", null, null);
+        String result = TuiHelper.formatSinceLast("5s", null, null);
         assertEquals("5s", result);
     }
 
     @Test
     void formatSinceLastOnlyCompleted() {
-        String result = MonitorContext.formatSinceLast(null, "10s", null);
+        String result = TuiHelper.formatSinceLast(null, "10s", null);
         assertEquals("10s", result);
     }
 
     @Test
     void formatSinceLastOnlyFailed() {
-        String result = MonitorContext.formatSinceLast(null, null, "7s");
+        String result = TuiHelper.formatSinceLast(null, null, "7s");
         assertEquals("7s", result);
     }
 
     @Test
     void formatSinceLastNonePresent() {
-        String result = MonitorContext.formatSinceLast(null, null, null);
+        String result = TuiHelper.formatSinceLast(null, null, null);
         assertEquals("", result);
     }
 
     @Test
     void formatSinceLastStartedAndFailed() {
-        String result = MonitorContext.formatSinceLast("1s", null, "3s");
+        String result = TuiHelper.formatSinceLast("1s", null, "3s");
         assertEquals("1s/3s", result);
     }
 
@@ -68,25 +68,25 @@ class MonitorContextTest {
 
     @Test
     void formatLoadNonZeroValues() {
-        String result = MonitorContext.formatLoad("1.23", "4.56", "7.89");
+        String result = TuiHelper.formatLoad("1.23", "4.56", "7.89");
         assertEquals("1.23/4.56/7.89", result);
     }
 
     @Test
     void formatLoadZeroCollapse() {
-        String result = MonitorContext.formatLoad("0.00", "0.00", "0.00");
+        String result = TuiHelper.formatLoad("0.00", "0.00", "0.00");
         assertEquals("0/0/0", result);
     }
 
     @Test
     void formatLoadNullHandling() {
-        String result = MonitorContext.formatLoad(null, null, null);
+        String result = TuiHelper.formatLoad(null, null, null);
         assertEquals("0/0/0", result);
     }
 
     @Test
     void formatLoadMixedZeroAndNonZero() {
-        String result = MonitorContext.formatLoad("1.50", "0.00", "0.75");
+        String result = TuiHelper.formatLoad("1.50", "0.00", "0.75");
         assertEquals("1.50/0/0.75", result);
     }
 
@@ -95,20 +95,20 @@ class MonitorContextTest {
     @Test
     void formatMemoryBothPositive() {
         // 512MB used, 1GB max
-        String result = MonitorContext.formatMemory(536870912L, 1073741824L);
+        String result = TuiHelper.formatMemory(536870912L, 1073741824L);
         assertEquals("512M/1024M", result);
     }
 
     @Test
     void formatMemoryMaxZeroShowsUsedOnly() {
         // 1048576 bytes = 1M (1024 * 1024)
-        String result = MonitorContext.formatMemory(1048576L, 0L);
+        String result = TuiHelper.formatMemory(1048576L, 0L);
         assertEquals("1M", result);
     }
 
     @Test
     void formatMemoryUsedZeroReturnsEmpty() {
-        String result = MonitorContext.formatMemory(0L, 1048576L);
+        String result = TuiHelper.formatMemory(0L, 1048576L);
         assertEquals("", result);
     }
 
@@ -116,55 +116,55 @@ class MonitorContextTest {
 
     @Test
     void formatBytesRange() {
-        assertEquals("500B", MonitorContext.formatBytes(500));
+        assertEquals("500B", TuiHelper.formatBytes(500));
     }
 
     @Test
     void formatBytesKilobytes() {
-        assertEquals("1K", MonitorContext.formatBytes(1024));
-        assertEquals("10K", MonitorContext.formatBytes(10240));
+        assertEquals("1K", TuiHelper.formatBytes(1024));
+        assertEquals("10K", TuiHelper.formatBytes(10240));
     }
 
     @Test
     void formatBytesMegabytes() {
-        assertEquals("1M", MonitorContext.formatBytes(1048576));
-        assertEquals("100M", MonitorContext.formatBytes(104857600));
+        assertEquals("1M", TuiHelper.formatBytes(1048576));
+        assertEquals("100M", TuiHelper.formatBytes(104857600));
     }
 
     // ---- buildBar tests ----
 
     @Test
     void buildBarFull() {
-        String bar = MonitorContext.buildBar(100, 100, 10);
+        String bar = TuiHelper.buildBar(100, 100, 10);
         assertEquals(10, bar.length());
     }
 
     @Test
     void buildBarPartial() {
-        String bar = MonitorContext.buildBar(50, 100, 10);
+        String bar = TuiHelper.buildBar(50, 100, 10);
         assertEquals(5, bar.length());
     }
 
     @Test
     void buildBarZeroValue() {
-        String bar = MonitorContext.buildBar(0, 100, 10);
+        String bar = TuiHelper.buildBar(0, 100, 10);
         assertEquals("", bar);
     }
 
     @Test
     void buildBarZeroMax() {
-        String bar = MonitorContext.buildBar(50, 0, 10);
+        String bar = TuiHelper.buildBar(50, 0, 10);
         assertEquals("", bar);
     }
 
     @Test
     void buildBarSmallValueRoundsCorrectly() {
         // 1/1000 * 10 rounds to 0, buildBar returns empty for zero-length
-        String bar = MonitorContext.buildBar(1, 1000, 10);
+        String bar = TuiHelper.buildBar(1, 1000, 10);
         assertEquals("", bar);
 
         // A value large enough to produce at least one block (>= 1/maxWidth 
ratio)
-        String bar2 = MonitorContext.buildBar(100, 1000, 10);
+        String bar2 = TuiHelper.buildBar(100, 1000, 10);
         assertTrue(bar2.length() >= 1);
     }
 
@@ -172,20 +172,20 @@ class MonitorContextTest {
 
     @Test
     void topTimeStyleOver1000ms() {
-        Style style = MonitorContext.topTimeStyle(1000);
+        Style style = TuiHelper.topTimeStyle(1000);
         assertTrue(style.effectiveModifiers().contains(Modifier.BOLD));
         assertEquals(Color.LIGHT_RED, style.fg().orElse(null));
     }
 
     @Test
     void topTimeStyleOver100ms() {
-        Style style = MonitorContext.topTimeStyle(500);
+        Style style = TuiHelper.topTimeStyle(500);
         assertEquals(Color.YELLOW, style.fg().orElse(null));
     }
 
     @Test
     void topTimeStyleUnder100ms() {
-        Style style = MonitorContext.topTimeStyle(50);
+        Style style = TuiHelper.topTimeStyle(50);
         assertEquals(Style.EMPTY, style);
     }
 
@@ -193,19 +193,19 @@ class MonitorContextTest {
 
     @Test
     void topDeltaStylePositive() {
-        Style style = MonitorContext.topDeltaStyle(10);
+        Style style = TuiHelper.topDeltaStyle(10);
         assertEquals(Color.LIGHT_RED, style.fg().orElse(null));
     }
 
     @Test
     void topDeltaStyleNegative() {
-        Style style = MonitorContext.topDeltaStyle(-5);
+        Style style = TuiHelper.topDeltaStyle(-5);
         assertEquals(Color.GREEN, style.fg().orElse(null));
     }
 
     @Test
     void topDeltaStyleZero() {
-        Style style = MonitorContext.topDeltaStyle(0);
+        Style style = TuiHelper.topDeltaStyle(0);
         assertEquals(Style.EMPTY, style);
     }
 
@@ -213,23 +213,23 @@ class MonitorContextTest {
 
     @Test
     void compareStrBothNull() {
-        assertEquals(0, MonitorContext.compareStr(null, null));
+        assertEquals(0, TuiHelper.compareStr(null, null));
     }
 
     @Test
     void compareStrFirstNull() {
-        assertEquals(1, MonitorContext.compareStr(null, "b"));
+        assertEquals(1, TuiHelper.compareStr(null, "b"));
     }
 
     @Test
     void compareStrSecondNull() {
-        assertEquals(-1, MonitorContext.compareStr("a", null));
+        assertEquals(-1, TuiHelper.compareStr("a", null));
     }
 
     @Test
     void compareStrCaseInsensitive() {
-        assertEquals(0, MonitorContext.compareStr("ABC", "abc"));
-        assertTrue(MonitorContext.compareStr("abc", "xyz") < 0);
-        assertTrue(MonitorContext.compareStr("xyz", "abc") > 0);
+        assertEquals(0, TuiHelper.compareStr("ABC", "abc"));
+        assertTrue(TuiHelper.compareStr("abc", "xyz") < 0);
+        assertTrue(TuiHelper.compareStr("xyz", "abc") > 0);
     }
 }

Reply via email to