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

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


The following commit(s) were added to refs/heads/main by this push:
     new c916a75ec8b8 CAMEL-23831: Refactor Classpath tab to use / filter with 
substring matching in camel-tui
c916a75ec8b8 is described below

commit c916a75ec8b807e7628e72d23fec9644a55b40e0
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Jul 4 14:26:41 2026 +0200

    CAMEL-23831: Refactor Classpath tab to use / filter with substring matching 
in camel-tui
    
    CAMEL-23831: Make Consumers and DataSource tabs read-only in camel-tui
    
    CAMEL-23831: Polish read-only tabs, memory trend, process user, and startup 
in camel-tui
    
    - Add left padding on first column for Consumers, DataSource, Health, 
Inflight tabs
    - Add border to DataSource tab
    - Make Health and Inflight tabs read-only (no selection)
    - Memory trend threshold relative to committed size to avoid false alarms
    - Show process user in Process tab
    - Remove unnecessary F5 reload from Startup tab
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  |   6 +-
 .../dsl/jbang/core/commands/tui/ClasspathTab.java  | 150 ++++++++++-----------
 .../dsl/jbang/core/commands/tui/ConsumersTab.java  |  30 ++++-
 .../dsl/jbang/core/commands/tui/DataSourceTab.java |  33 ++++-
 .../dsl/jbang/core/commands/tui/HealthTab.java     |  29 +++-
 .../dsl/jbang/core/commands/tui/InflightTab.java   |  30 ++++-
 .../dsl/jbang/core/commands/tui/MemoryTab.java     |  11 +-
 .../dsl/jbang/core/commands/tui/ProcessTab.java    |  16 +++
 .../dsl/jbang/core/commands/tui/StartupTab.java    |   7 +-
 .../dsl/jbang/core/commands/tui/TabRegistry.java   |   4 +
 10 files changed, 220 insertions(+), 96 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
index cd21ef80a14d..e109d54a0683 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
@@ -569,10 +569,14 @@ public class CamelMonitor extends CamelCommand {
         boolean beanFilterActive = tabRegistry.selectedTabIndex() == TAB_MORE
                 && tabRegistry.getActiveMoreTab() == tabRegistry.beansTab()
                 && tabRegistry.beansTab().isFilterInputActive();
+        boolean classpathFilterActive = tabRegistry.selectedTabIndex() == 
TAB_MORE
+                && tabRegistry.getActiveMoreTab() == tabRegistry.classpathTab()
+                && tabRegistry.classpathTab().isFilterInputActive();
         boolean sqlInputActive = tabRegistry.selectedTabIndex() == TAB_MORE
                 && tabRegistry.getActiveMoreTab() == tabRegistry.sqlQueryTab()
                 && tabRegistry.sqlQueryTab().isInputActive();
-        boolean textEditing = probeEditing || logSearchActive || 
spanFilterActive || beanFilterActive || sqlInputActive;
+        boolean textEditing = probeEditing || logSearchActive || 
spanFilterActive || beanFilterActive
+                || classpathFilterActive || sqlInputActive;
         if (!textEditing && (ke.isCharIgnoreCase('q') || ke.isCtrlC())) {
             runner.quit();
             return true;
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 f418f2aca1b1..abc3d512f251 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
@@ -36,6 +36,7 @@ import dev.tamboui.tui.event.MouseEventKind;
 import dev.tamboui.widgets.block.Block;
 import dev.tamboui.widgets.block.BorderType;
 import dev.tamboui.widgets.block.Borders;
+import dev.tamboui.widgets.input.TextInputState;
 import dev.tamboui.widgets.list.ListItem;
 import dev.tamboui.widgets.list.ListState;
 import dev.tamboui.widgets.list.ListWidget;
@@ -51,16 +52,16 @@ import static 
org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class ClasspathTab extends AbstractTab {
 
-    private static final Style MATCH_STYLE = 
Style.EMPTY.fg(Color.YELLOW).bold();
-
     private final ListState listState = new ListState();
     private final ScrollbarState listScrollState = new ScrollbarState();
-    private final FuzzyFilter fuzzyFilter = new FuzzyFilter();
     private final AtomicBoolean loading = new AtomicBoolean(false);
     private Rect lastArea;
 
+    private boolean filterInputActive;
+    private TextInputState filterInputState = new TextInputState("");
+    private String filterTerm;
     private List<JarEntry> allEntries = Collections.emptyList();
-    private List<FilteredEntry> filteredEntries = Collections.emptyList();
+    private List<JarEntry> filteredEntries = Collections.emptyList();
     private String lastPid;
     private String errorMessage;
     private boolean dataLoaded;
@@ -86,7 +87,8 @@ class ClasspathTab extends AbstractTab {
     public void onIntegrationChanged() {
         allEntries = Collections.emptyList();
         filteredEntries = Collections.emptyList();
-        fuzzyFilter.clearFilter();
+        filterTerm = null;
+        filterInputActive = false;
         lastPid = null;
         errorMessage = null;
         dataLoaded = false;
@@ -94,12 +96,13 @@ class ClasspathTab extends AbstractTab {
 
     @Override
     public boolean handleKeyEvent(KeyEvent ke) {
-        if (ke.isDeleteBackward()) {
-            if (fuzzyFilter.hasFilter()) {
-                fuzzyFilter.deleteChar();
-                refilter();
-                return true;
-            }
+        if (filterInputActive) {
+            return handleFilterInput(ke);
+        }
+        if (ke.isChar('/')) {
+            filterInputActive = true;
+            filterInputState = new TextInputState(filterTerm != null ? 
filterTerm : "");
+            return true;
         }
         if (ke.isPageUp() || ke.isKey(KeyCode.PAGE_UP)) {
             for (int i = 0; i < 20 && listState.selected() != null && 
listState.selected() > 0; i++) {
@@ -113,12 +116,27 @@ class ClasspathTab extends AbstractTab {
             }
             return true;
         }
-        if (ke.code() == KeyCode.CHAR) {
-            fuzzyFilter.appendChar(ke.string().charAt(0));
+        return false;
+    }
+
+    private boolean handleFilterInput(KeyEvent ke) {
+        if (ke.isKey(KeyCode.ESCAPE)) {
+            filterInputActive = false;
+            return true;
+        }
+        if (ke.isConfirm()) {
+            String text = filterInputState.text().trim();
+            filterTerm = text.isEmpty() ? null : text;
+            filterInputActive = false;
             refilter();
             return true;
         }
-        return false;
+        FormHelper.handleTextInput(ke, filterInputState);
+        return true;
+    }
+
+    boolean isFilterInputActive() {
+        return filterInputActive;
     }
 
     @Override
@@ -143,8 +161,8 @@ class ClasspathTab extends AbstractTab {
 
     @Override
     public boolean handleEscape() {
-        if (fuzzyFilter.hasFilter()) {
-            fuzzyFilter.clearFilter();
+        if (filterTerm != null) {
+            filterTerm = null;
             refilter();
             return true;
         }
@@ -194,28 +212,19 @@ class ClasspathTab extends AbstractTab {
 
         int contentW = Math.max(10, area.width() - 4);
         List<ListItem> items = new ArrayList<>();
-        for (FilteredEntry fe : filteredEntries) {
-            String displayText = formatEntry(fe.entry(), contentW);
-            Style normalStyle = fe.entry().isCamel() ? Style.EMPTY : 
Style.EMPTY.dim();
-            if (fe.matchPositions() != null && fe.matchPositions().length > 0) 
{
-                int[] adjusted = adjustPositions(fe.matchPositions(), 
fe.entry(), displayText);
-                Line line = FuzzyFilter.highlightLine(displayText, adjusted, 
normalStyle, MATCH_STYLE);
-                items.add(ListItem.from(Text.from(line)));
-            } else {
-                items.add(ListItem.from(displayText).style(normalStyle));
-            }
+        for (JarEntry entry : filteredEntries) {
+            String displayText = formatEntry(entry, contentW);
+            Style normalStyle = entry.isCamel() ? Style.EMPTY : 
Style.EMPTY.dim();
+            items.add(ListItem.from(displayText).style(normalStyle));
         }
 
         if (items.isEmpty() && dataLoaded) {
             items.add(ListItem.from("  No classpath entries 
found").style(Style.EMPTY.dim()));
         }
 
-        String title = " Classpath (" + filteredEntries.size();
-        if (fuzzyFilter.hasFilter()) {
-            title += "/" + allEntries.size() + ") [" + fuzzyFilter.filter() + 
"] ";
-        } else {
-            title += ") ";
-        }
+        String title = filterTerm != null
+                ? String.format(" Classpath [%d/%d] filter:\"%s\" ", 
filteredEntries.size(), allEntries.size(), filterTerm)
+                : String.format(" Classpath [%d] ", filteredEntries.size());
 
         ListWidget list = ListWidget.builder()
                 .items(items.toArray(ListItem[]::new))
@@ -240,9 +249,21 @@ class ClasspathTab extends AbstractTab {
 
     @Override
     public void renderFooter(List<Span> spans) {
-        hint(spans, "Esc", fuzzyFilter.hasFilter() ? "clear" : "back");
-        hint(spans, "↑↓", "navigate");
-        hintLast(spans, "type", "filter");
+        if (filterInputActive) {
+            spans.add(Span.styled(" /", Style.EMPTY.fg(Color.YELLOW).bold()));
+            spans.add(Span.raw(filterInputState.text() + "█  "));
+            hint(spans, "Enter", "filter");
+            hintLast(spans, "Esc", "cancel");
+            return;
+        }
+        hint(spans, "Esc", filterTerm != null ? "clear" : "back");
+        if (filterTerm != null) {
+            spans.add(Span.styled("  /", Style.EMPTY.fg(Color.YELLOW).bold()));
+            spans.add(Span.raw("\"" + filterTerm + "\"  "));
+        } else {
+            hint(spans, "/", "filter");
+        }
+        hintLast(spans, "↑↓", "navigate");
     }
 
     private void loadClasspath() {
@@ -318,34 +339,17 @@ class ClasspathTab extends AbstractTab {
     }
 
     private void refilter() {
-        List<FilteredEntry> result = new ArrayList<>();
+        List<JarEntry> result = new ArrayList<>();
+        String ft = filterTerm != null ? filterTerm.toLowerCase() : null;
         for (JarEntry entry : allEntries) {
-            if (!fuzzyFilter.hasFilter()) {
-                result.add(new FilteredEntry(entry, null));
-            } else {
-                int[] positions = fuzzyFilter.match(entry.display());
-                if (positions != null) {
-                    result.add(new FilteredEntry(entry, positions));
-                }
+            if (ft == null || entry.display().toLowerCase().contains(ft)) {
+                result.add(entry);
             }
         }
         filteredEntries = result;
         listState.select(filteredEntries.isEmpty() ? null : 0);
     }
 
-    private int[] adjustPositions(int[] matchPositions, JarEntry entry, String 
displayText) {
-        String searchText = entry.display();
-        int offset = displayText.indexOf(searchText.substring(0, 
Math.min(searchText.length(), 5)));
-        if (offset < 0) {
-            offset = 2;
-        }
-        int[] adjusted = new int[matchPositions.length];
-        for (int i = 0; i < matchPositions.length; i++) {
-            adjusted[i] = matchPositions[i] + offset;
-        }
-        return adjusted;
-    }
-
     private String formatEntry(JarEntry entry, int width) {
         if (entry.groupId() != null) {
             String gav = entry.groupId() + ":" + entry.artifactId();
@@ -384,12 +388,7 @@ class ClasspathTab extends AbstractTab {
 
     @Override
     public boolean setFilter(String filter) {
-        fuzzyFilter.clearFilter();
-        if (filter != null && !filter.isEmpty()) {
-            for (char c : filter.toCharArray()) {
-                fuzzyFilter.appendChar(c);
-            }
-        }
+        filterTerm = filter != null && !filter.isEmpty() ? filter : null;
         refilter();
         return true;
     }
@@ -420,9 +419,6 @@ class ClasspathTab extends AbstractTab {
         }
     }
 
-    record FilteredEntry(JarEntry entry, int[] matchPositions) {
-    }
-
     @Override
     public String description() {
         return "JVM classpath entries with filtering";
@@ -458,16 +454,16 @@ class ClasspathTab extends AbstractTab {
                  org.slf4j:slf4j-api                         2.0.16
                 ```
 
-                ## Fuzzy Filter
+                ## Filter
 
-                Start typing to filter the classpath. The filter uses fuzzy 
matching
-                so you can type partial strings like `kafka` to find all 
Kafka-related
-                JARs, or `jackson` to find Jackson dependencies. Matching 
characters
-                are highlighted in yellow.
+                Press `/` to open the filter input. Type a search term and 
press
+                `Enter` to filter the classpath by substring match. For 
example,
+                type `kafka` to find all Kafka-related JARs, or `jackson` to 
find
+                Jackson dependencies.
 
-                - Type any characters to filter
-                - `Backspace` to delete characters from filter
-                - `Esc` to clear filter
+                - `/` — open filter input
+                - `Enter` — apply filter
+                - `Esc` — clear filter
 
                 ## When To Use
 
@@ -480,23 +476,21 @@ class ClasspathTab extends AbstractTab {
 
                 - `Up/Down` — navigate entries
                 - `PgUp/PgDn` — scroll by page
-                - `type` — fuzzy filter
-                - `Backspace` — delete filter character
+                - `/` — open filter
                 - `Esc` — clear filter or back
                 """;
     }
 
     @Override
     public JsonObject getTableDataAsJson() {
-        List<FilteredEntry> entries = filteredEntries;
+        List<JarEntry> entries = filteredEntries;
         if (entries.isEmpty()) {
             return null;
         }
         JsonObject result = new JsonObject();
         result.put("tab", "Classpath");
         JsonArray rows = new JsonArray();
-        for (FilteredEntry fe : entries) {
-            JarEntry j = fe.entry();
+        for (JarEntry j : entries) {
             JsonObject row = new JsonObject();
             if (j.groupId() != null) {
                 row.put("groupId", j.groupId());
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 6feb26e385cc..2bea6caa2865 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
@@ -27,6 +27,9 @@ import dev.tamboui.style.Color;
 import dev.tamboui.style.Style;
 import dev.tamboui.terminal.Frame;
 import dev.tamboui.text.Span;
+import dev.tamboui.tui.event.KeyCode;
+import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.tui.event.MouseEvent;
 import dev.tamboui.widgets.block.Block;
 import dev.tamboui.widgets.block.BorderType;
 import dev.tamboui.widgets.block.Borders;
@@ -44,6 +47,29 @@ class ConsumersTab extends AbstractTableTab {
         super(ctx, "id", "status", "type", "inflight", "polls", "uri");
     }
 
+    @Override
+    public void navigateUp() {
+    }
+
+    @Override
+    public void navigateDown() {
+    }
+
+    @Override
+    public boolean handleKeyEvent(KeyEvent ke) {
+        if (ke.isPageUp() || ke.isKey(KeyCode.PAGE_UP)
+                || ke.isPageDown() || ke.isKey(KeyCode.PAGE_DOWN)
+                || ke.isHome() || ke.isEnd()) {
+            return false;
+        }
+        return super.handleKeyEvent(ke);
+    }
+
+    @Override
+    public boolean handleMouseEvent(MouseEvent me, Rect area) {
+        return false;
+    }
+
     @Override
     protected int getRowCount() {
         IntegrationInfo info = ctx.findSelectedIntegration();
@@ -74,7 +100,7 @@ class ConsumersTab extends AbstractTableTab {
                     : (ci.uri != null ? ci.uri : "");
 
             rows.add(Row.from(
-                    Cell.from(Span.styled(ci.id != null ? ci.id : "", 
Style.EMPTY.fg(Color.CYAN))),
+                    Cell.from(Span.styled(" " + (ci.id != null ? ci.id : ""), 
Style.EMPTY.fg(Color.CYAN))),
                     Cell.from(Span.styled(statusText, statusStyle)),
                     Cell.from(type),
                     rightCell(String.valueOf(ci.inflight), 8),
@@ -91,7 +117,7 @@ class ConsumersTab extends AbstractTableTab {
         Table table = Table.builder()
                 .rows(rows)
                 .header(Row.from(
-                        Cell.from(Span.styled(sortLabel("ROUTE", "id"), 
sortStyle("id"))),
+                        Cell.from(Span.styled(" " + sortLabel("ROUTE", "id"), 
sortStyle("id"))),
                         Cell.from(Span.styled(sortLabel("STATUS", "status"), 
sortStyle("status"))),
                         Cell.from(Span.styled(sortLabel("TYPE", "type"), 
sortStyle("type"))),
                         rightCell(sortLabel("INFLIGHT", "inflight"), 8, 
sortStyle("inflight")),
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 de6011fe2255..6d434e75c943 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
@@ -25,8 +25,12 @@ import dev.tamboui.style.Color;
 import dev.tamboui.style.Style;
 import dev.tamboui.terminal.Frame;
 import dev.tamboui.text.Span;
+import dev.tamboui.tui.event.KeyCode;
+import dev.tamboui.tui.event.KeyEvent;
+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.table.Cell;
 import dev.tamboui.widgets.table.Row;
 import dev.tamboui.widgets.table.Table;
@@ -41,6 +45,29 @@ class DataSourceTab extends AbstractTableTab {
         super(ctx, "name", "pool", "active", "idle", "total", "max", 
"waiting");
     }
 
+    @Override
+    public void navigateUp() {
+    }
+
+    @Override
+    public void navigateDown() {
+    }
+
+    @Override
+    public boolean handleKeyEvent(KeyEvent ke) {
+        if (ke.isPageUp() || ke.isKey(KeyCode.PAGE_UP)
+                || ke.isPageDown() || ke.isKey(KeyCode.PAGE_DOWN)
+                || ke.isHome() || ke.isEnd()) {
+            return false;
+        }
+        return super.handleKeyEvent(ke);
+    }
+
+    @Override
+    public boolean handleMouseEvent(MouseEvent me, Rect area) {
+        return false;
+    }
+
     @Override
     protected int getRowCount() {
         IntegrationInfo info = ctx.findSelectedIntegration();
@@ -67,7 +94,7 @@ class DataSourceTab extends AbstractTableTab {
             String poolLabel = di.poolName != null ? di.poolName : 
(di.poolType != null ? di.poolType : "");
 
             rows.add(Row.from(
-                    Cell.from(Span.styled(di.name != null ? di.name : "", 
Style.EMPTY.fg(Color.CYAN))),
+                    Cell.from(Span.styled(" " + (di.name != null ? di.name : 
""), Style.EMPTY.fg(Color.CYAN))),
                     Cell.from(poolLabel),
                     rightCell(String.valueOf(di.active), 8, activeStyle),
                     rightCell(String.valueOf(di.idle), 8),
@@ -84,7 +111,7 @@ class DataSourceTab extends AbstractTableTab {
         Table table = Table.builder()
                 .rows(rows)
                 .header(Row.from(
-                        Cell.from(Span.styled(sortLabel("NAME", "name"), 
sortStyle("name"))),
+                        Cell.from(Span.styled(" " + sortLabel("NAME", "name"), 
sortStyle("name"))),
                         Cell.from(Span.styled(sortLabel("POOL", "pool"), 
sortStyle("pool"))),
                         rightCell(sortLabel("ACTIVE", "active"), 8, 
sortStyle("active")),
                         rightCell(sortLabel("IDLE", "idle"), 8, 
sortStyle("idle")),
@@ -101,7 +128,7 @@ class DataSourceTab extends AbstractTableTab {
                         Constraint.length(8),
                         Constraint.length(8),
                         Constraint.fill())
-                .block(Block.builder().borderType(BorderType.ROUNDED)
+                
.block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL)
                         .title(" DataSource sort:" + sort + " ").build())
                 .build();
 
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 c2a4a6d04e11..705d20a2ef5b 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
@@ -25,7 +25,9 @@ import dev.tamboui.style.Color;
 import dev.tamboui.style.Style;
 import dev.tamboui.terminal.Frame;
 import dev.tamboui.text.Span;
+import dev.tamboui.tui.event.KeyCode;
 import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.tui.event.MouseEvent;
 import dev.tamboui.widgets.block.Block;
 import dev.tamboui.widgets.block.BorderType;
 import dev.tamboui.widgets.block.Borders;
@@ -47,6 +49,29 @@ class HealthTab extends AbstractTableTab {
         sort = "name";
     }
 
+    @Override
+    public void navigateUp() {
+    }
+
+    @Override
+    public void navigateDown() {
+    }
+
+    @Override
+    public boolean handleKeyEvent(KeyEvent ke) {
+        if (ke.isPageUp() || ke.isKey(KeyCode.PAGE_UP)
+                || ke.isPageDown() || ke.isKey(KeyCode.PAGE_DOWN)
+                || ke.isHome() || ke.isEnd()) {
+            return false;
+        }
+        return super.handleKeyEvent(ke);
+    }
+
+    @Override
+    public boolean handleMouseEvent(MouseEvent me, Rect area) {
+        return false;
+    }
+
     @Override
     protected int getRowCount() {
         IntegrationInfo info = ctx.findSelectedIntegration();
@@ -91,7 +116,7 @@ class HealthTab extends AbstractTableTab {
             }
 
             rows.add(Row.from(
-                    Cell.from(Span.styled(hc.group != null ? hc.group : "", 
Style.EMPTY.dim())),
+                    Cell.from(Span.styled(" " + (hc.group != null ? hc.group : 
""), Style.EMPTY.dim())),
                     Cell.from(Span.styled(hc.name != null ? hc.name : "", 
Style.EMPTY.fg(Color.CYAN))),
                     Cell.from(Span.styled(icon + hc.state, stateStyle)),
                     Cell.from(kind),
@@ -115,7 +140,7 @@ class HealthTab extends AbstractTableTab {
         Table table = Table.builder()
                 .rows(rows)
                 .header(Row.from(
-                        Cell.from(Span.styled(sortLabel("GROUP", "group"), 
sortStyle("group"))),
+                        Cell.from(Span.styled(" " + sortLabel("GROUP", 
"group"), sortStyle("group"))),
                         Cell.from(Span.styled(sortLabel("NAME", "name"), 
sortStyle("name"))),
                         Cell.from(Span.styled(sortLabel("STATUS", "status"), 
sortStyle("status"))),
                         Cell.from(Span.styled("KIND", Style.EMPTY.bold())),
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 27f5656de1d7..9fc158057591 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
@@ -27,6 +27,9 @@ 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.KeyCode;
+import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.tui.event.MouseEvent;
 import dev.tamboui.widgets.block.Block;
 import dev.tamboui.widgets.block.BorderType;
 import dev.tamboui.widgets.block.Borders;
@@ -55,6 +58,29 @@ class InflightTab extends AbstractTableTab {
         sort = "duration";
     }
 
+    @Override
+    public void navigateUp() {
+    }
+
+    @Override
+    public void navigateDown() {
+    }
+
+    @Override
+    public boolean handleKeyEvent(KeyEvent ke) {
+        if (ke.isPageUp() || ke.isKey(KeyCode.PAGE_UP)
+                || ke.isPageDown() || ke.isKey(KeyCode.PAGE_DOWN)
+                || ke.isHome() || ke.isEnd()) {
+            return false;
+        }
+        return super.handleKeyEvent(ke);
+    }
+
+    @Override
+    public boolean handleMouseEvent(MouseEvent me, Rect area) {
+        return false;
+    }
+
     @Override
     protected int getRowCount() {
         IntegrationInfo info = ctx.findSelectedIntegration();
@@ -90,7 +116,7 @@ class InflightTab extends AbstractTableTab {
             Span barSpan = buildDurationBar(ii.duration, maxDuration, 20);
 
             rows.add(Row.from(
-                    Cell.from(Span.styled(status, statusStyle)),
+                    Cell.from(Span.styled(" " + status, statusStyle)),
                     Cell.from(Span.styled(ii.exchangeId != null ? 
ii.exchangeId : "", Style.EMPTY.fg(Color.CYAN))),
                     Cell.from(routeNode),
                     rightCell(duration, 14, durationStyle),
@@ -106,7 +132,7 @@ class InflightTab extends AbstractTableTab {
         Table table = Table.builder()
                 .rows(rows)
                 .header(Row.from(
-                        Cell.from(Span.styled(sortLabel("STATUS", "status"), 
sortStyle("status"))),
+                        Cell.from(Span.styled(" " + sortLabel("STATUS", 
"status"), sortStyle("status"))),
                         Cell.from(Span.styled(sortLabel("EXCHANGE ID", 
"exchange"), sortStyle("exchange"))),
                         Cell.from(Span.styled(sortLabel("ROUTE/NODE", 
"route"), sortStyle("route"))),
                         rightCell(sortLabel("DURATION", "duration"), 14, 
sortStyle("duration")),
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 3081c54bff79..1cad072dc3c8 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
@@ -131,7 +131,7 @@ class MemoryTab extends AbstractTab {
 
             // Compute heap trend from history
             LinkedList<Long> hist = heapMemHistory.get(info.pid);
-            Span trendSpan = computeTrendSpan(hist);
+            Span trendSpan = computeTrendSpan(hist, info.heapMemCommitted);
 
             lines.add(Line.from(
                     Span.styled("  used:      ", Style.EMPTY.dim()),
@@ -380,7 +380,7 @@ class MemoryTab extends AbstractTab {
         }
     }
 
-    private static Span computeTrendSpan(LinkedList<Long> hist) {
+    private static Span computeTrendSpan(LinkedList<Long> hist, long 
heapCeiling) {
         // need at least 30 samples (~2.5 min at 5s intervals) for a 
meaningful trend
         if (hist == null || hist.size() < 30) {
             return null;
@@ -409,6 +409,13 @@ class MemoryTab extends AbstractTab {
         // each sample is taken every 5 seconds (HEAP_SAMPLE_INTERVAL_MS)
         long seconds = size * 5L;
         String period = seconds >= 60 ? (seconds / 60) + "m" : seconds + "s";
+
+        // ignore small fluctuations relative to heap capacity (at least 5M or 
1% of ceiling)
+        long threshold = Math.max(5 * 1024 * 1024, (long) (heapCeiling * 
0.01));
+        if (Math.abs(diff) < threshold) {
+            return Span.styled("  → stable over last " + period, 
Style.EMPTY.fg(Color.GREEN));
+        }
+
         if (change > 0.05) {
             return Span.styled(
                     String.format("  ↑ growing by %d%% (%s) over last %s", 
pct, formatBytes(diff), period),
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 12215adc5db9..836c2e06ea36 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
@@ -111,6 +111,7 @@ class ProcessTab extends AbstractTab {
         List<Line> lines = new ArrayList<>();
 
         addField(lines, "PID", info.pid);
+        addField(lines, "User", getProcessUser(info.pid));
         addField(lines, "Name", info.name);
         addField(lines, "Camel", info.camelVersion);
 
@@ -213,6 +214,10 @@ class ProcessTab extends AbstractTab {
         result.put("tab", "Process");
         JsonObject data = new JsonObject();
         data.put("pid", info.pid);
+        String user = getProcessUser(info.pid);
+        if (user != null) {
+            data.put("user", user);
+        }
         data.put("name", info.name);
         data.put("camelVersion", info.camelVersion);
         data.put("platform", info.platform);
@@ -241,6 +246,17 @@ class ProcessTab extends AbstractTab {
                 Span.styled(value, Style.EMPTY.fg(Color.WHITE).bold())));
     }
 
+    private static String getProcessUser(String pid) {
+        try {
+            long p = Long.parseLong(pid);
+            return ProcessHandle.of(p)
+                    .flatMap(ph -> ph.info().user())
+                    .orElse(null);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
     private static String getCommandLine(String pid) {
         try {
             long p = Long.parseLong(pid);
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 3f097462f4f1..a24c300fb311 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
@@ -103,10 +103,6 @@ class StartupTab extends AbstractTab {
             scrollOffset = Integer.MAX_VALUE;
             return true;
         }
-        if (ke.isKey(KeyCode.F5)) {
-            loadStartupData();
-            return true;
-        }
         return false;
     }
 
@@ -260,8 +256,7 @@ class StartupTab extends AbstractTab {
     public void renderFooter(List<Span> spans) {
         hint(spans, "Esc", "back");
         hint(spans, "↑↓", "scroll");
-        hint(spans, "PgUp/Dn", "page");
-        hintLast(spans, "F5", "reload");
+        hintLast(spans, "PgUp/Dn", "page");
     }
 
     private void loadStartupData() {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TabRegistry.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TabRegistry.java
index db4d61526229..51a667b10340 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TabRegistry.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TabRegistry.java
@@ -321,6 +321,10 @@ class TabRegistry {
         return sqlQueryTab;
     }
 
+    ClasspathTab classpathTab() {
+        return classpathTab;
+    }
+
     // ---- Tab entries for Go-to and MCP ----
 
     record TabEntry(String name, String description, String shortcut, int 
tabIndex, int moreIndex) {

Reply via email to