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 075870657c69 CAMEL-23831: Add Go-to fuzzy tab search in F2 Actions 
popup in camel-tui
075870657c69 is described below

commit 075870657c69c3a15d2b6d73cda59953c99535a4
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Jul 2 20:36:33 2026 +0200

    CAMEL-23831: Add Go-to fuzzy tab search in F2 Actions popup in camel-tui
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../dsl/jbang/core/commands/tui/ActionsPopup.java  | 260 ++++++++++++++++++++-
 .../dsl/jbang/core/commands/tui/BeansTab.java      |   5 +
 .../dsl/jbang/core/commands/tui/BrowseTab.java     |   5 +
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  |  11 +
 .../jbang/core/commands/tui/CircuitBreakerTab.java |   5 +
 .../dsl/jbang/core/commands/tui/ClasspathTab.java  |   5 +
 .../jbang/core/commands/tui/ConfigurationTab.java  |   5 +
 .../dsl/jbang/core/commands/tui/ConsumersTab.java  |   5 +
 .../dsl/jbang/core/commands/tui/DataSourceTab.java |   5 +
 .../dsl/jbang/core/commands/tui/DiagramTab.java    |   5 +
 .../dsl/jbang/core/commands/tui/EndpointsTab.java  |   5 +
 .../dsl/jbang/core/commands/tui/ErrorsTab.java     |   5 +
 .../dsl/jbang/core/commands/tui/HealthTab.java     |   5 +
 .../jbang/core/commands/tui/HeapHistogramTab.java  |   5 +
 .../dsl/jbang/core/commands/tui/HistoryTab.java    |   5 +
 .../camel/dsl/jbang/core/commands/tui/HttpTab.java |   5 +
 .../dsl/jbang/core/commands/tui/InflightTab.java   |   5 +
 .../camel/dsl/jbang/core/commands/tui/LogTab.java  |   5 +
 .../dsl/jbang/core/commands/tui/McpFacade.java     |  41 +---
 .../dsl/jbang/core/commands/tui/MemoryLeakTab.java |   5 +
 .../dsl/jbang/core/commands/tui/MemoryTab.java     |   5 +
 .../dsl/jbang/core/commands/tui/MetricsTab.java    |   5 +
 .../dsl/jbang/core/commands/tui/MonitorTab.java    |   2 +
 .../dsl/jbang/core/commands/tui/OverviewTab.java   |   5 +
 .../dsl/jbang/core/commands/tui/ProcessTab.java    |   5 +
 .../dsl/jbang/core/commands/tui/RoutesTab.java     |   5 +
 .../dsl/jbang/core/commands/tui/SpansTab.java      |   5 +
 .../dsl/jbang/core/commands/tui/SqlQueryTab.java   |   5 +
 .../dsl/jbang/core/commands/tui/SqlTraceTab.java   |   5 +
 .../dsl/jbang/core/commands/tui/StartupTab.java    |   5 +
 .../dsl/jbang/core/commands/tui/TabRegistry.java   |  40 ++++
 .../dsl/jbang/core/commands/tui/ThreadsTab.java    |   5 +
 .../dsl/jbang/core/commands/tui/TuiMcpServer.java  |   9 +-
 33 files changed, 454 insertions(+), 44 deletions(-)

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 1db22ce2598f..a1231aa24502 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
@@ -73,6 +73,7 @@ import static 
org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.hintLast;
 class ActionsPopup {
 
     enum Action {
+        GOTO_TAB,
         SEND_MESSAGE,
         RUN_EXAMPLE,
         RUN_FOLDER,
@@ -94,7 +95,7 @@ class ActionsPopup {
         SHELL
     }
 
-    private static final int[] GROUP_SIZES = { 5, 4, 5 };
+    private static final int[] GROUP_SIZES = { 1, 5, 4, 5 };
     private static final int MCP_GROUP_SIZE = 4;
     private static final int SHELL_GROUP_SIZE = 1;
 
@@ -123,6 +124,14 @@ class ActionsPopup {
     private Rect actionsMenuRect;
     private Rect docPickerRect;
 
+    private boolean showGotoPopup;
+    private final FuzzyFilter gotoFilter = new FuzzyFilter();
+    private final ListState gotoListState = new ListState();
+    private List<TabRegistry.TabEntry> allTabEntries;
+    private List<TabRegistry.TabEntry> filteredTabEntries;
+    private Rect gotoPopupRect;
+    private Runnable gotoTabCallback;
+
     private boolean showExampleBrowser;
     private final ListState exampleBrowserState = new ListState();
     private List<JsonObject> exampleCatalog;
@@ -217,6 +226,11 @@ class ActionsPopup {
         this.browseFilesAction = browseFilesAction;
     }
 
+    void setGotoTabSupport(List<TabRegistry.TabEntry> entries, Runnable 
callback) {
+        this.allTabEntries = entries;
+        this.gotoTabCallback = callback;
+    }
+
     void setMcpEnabled(
             boolean enabled, int port, Supplier<String> connectedClient,
             Supplier<List<TuiMcpServer.LogEntry>> activityLog, 
Supplier<Integer> toolCallCount) {
@@ -277,6 +291,8 @@ class ActionsPopup {
 
     private List<Action> buildVisualActionList() {
         List<Action> flat = new ArrayList<>();
+        flat.add(Action.GOTO_TAB);
+        flat.add(null);
         flat.addAll(List.of(
                 Action.SEND_MESSAGE, Action.RUN_EXAMPLE, Action.RUN_FOLDER, 
Action.RUN_INFRA, Action.BROWSE_FILES));
         flat.add(null);
@@ -309,7 +325,7 @@ class ActionsPopup {
     }
 
     boolean isVisible() {
-        return showActionsMenu || showExampleBrowser || showFolderInput || 
runOptionsForm.isVisible()
+        return showActionsMenu || showGotoPopup || showExampleBrowser || 
showFolderInput || runOptionsForm.isVisible()
                 || showDocPicker || showDocViewer
                 || showInfraBrowser || showInfraPortDialog
                 || mcpLogPopup.isVisible() || aiLogPopup.isVisible() || 
doctorPopup.isVisible()
@@ -355,6 +371,9 @@ class ActionsPopup {
 
     List<String> getActionLabels() {
         List<String> labels = new ArrayList<>();
+        // Group 0: Go to
+        labels.add("Go to...");
+        labels.add("───");
         // Group 1: User Actions
         labels.add("Send Message");
         labels.add("Run an example...");
@@ -394,6 +413,8 @@ class ActionsPopup {
 
     void close() {
         showActionsMenu = false;
+        showGotoPopup = false;
+        gotoFilter.clearFilter();
         showExampleBrowser = false;
         showFolderInput = false;
         runOptionsForm.close();
@@ -572,6 +593,32 @@ class ActionsPopup {
         if (doctorPopup.handleKeyEvent(ke)) {
             return true;
         }
+        if (showGotoPopup) {
+            if (ke.isCancel()) {
+                showGotoPopup = false;
+                gotoFilter.clearFilter();
+                showActionsMenu = true;
+            } else if (ke.isUp()) {
+                gotoListState.selectPrevious();
+            } else if (ke.isDown()) {
+                gotoListState.selectNext(filteredTabEntries != null ? 
filteredTabEntries.size() : 0);
+            } else if (ke.isConfirm()) {
+                Integer sel = gotoListState.selected();
+                if (sel != null && filteredTabEntries != null && sel < 
filteredTabEntries.size()) {
+                    TabRegistry.TabEntry entry = filteredTabEntries.get(sel);
+                    showGotoPopup = false;
+                    gotoFilter.clearFilter();
+                    navigateToTabEntry(entry);
+                }
+            } else if (ke.isKey(KeyCode.BACKSPACE)) {
+                gotoFilter.deleteChar();
+                rebuildGotoList();
+            } else if (ke.code() == KeyCode.CHAR && !ke.hasCtrl() && 
!ke.hasAlt()) {
+                gotoFilter.appendChar(ke.string().charAt(0));
+                rebuildGotoList();
+            }
+            return true;
+        }
         if (showActionsMenu) {
             if (ke.isCancel()) {
                 showActionsMenu = false;
@@ -585,6 +632,9 @@ class ActionsPopup {
                     Action action = resolveAction(sel);
                     if (action == null) {
                         // divider selected, ignore
+                    } else if (action == Action.GOTO_TAB) {
+                        showActionsMenu = false;
+                        openGotoPopup();
                     } else if (action == Action.SHELL) {
                         showActionsMenu = false;
                         if (openShellAction != null) {
@@ -671,6 +721,9 @@ class ActionsPopup {
         if (!isVisible()) {
             return false;
         }
+        if (showGotoPopup) {
+            return handleGotoPopupMouse(me);
+        }
         if (showActionsMenu) {
             return handleListPopupMouse(me, actionsMenuRect, actionsMenuState, 
visualActionCount(), this::isDividerIndex);
         }
@@ -732,6 +785,9 @@ class ActionsPopup {
     }
 
     void render(Frame frame, Rect area) {
+        if (showGotoPopup) {
+            renderGotoPopup(frame, area);
+        }
         if (showActionsMenu) {
             renderActionsMenu(frame, area);
         }
@@ -843,6 +899,13 @@ class ActionsPopup {
             hintLast(spans, "Esc", "back");
             return;
         }
+        if (showGotoPopup) {
+            hint(spans, "type", "filter");
+            hint(spans, "↑↓", "navigate");
+            hint(spans, "Enter", "go to");
+            hintLast(spans, "Esc", "back");
+            return;
+        }
         if (showActionsMenu) {
             hint(spans, "↑↓", "navigate");
             hint(spans, "Enter", "select");
@@ -884,6 +947,9 @@ class ActionsPopup {
                 : "  🔴 Start Tape Recording (Ctrl+R)";
 
         List<ListItem> items = new ArrayList<>();
+        // Group 0: Go to
+        items.add(ListItem.from("  🔍 Go to..."));
+        items.add(ListItem.from(divider).style(Style.EMPTY.dim()));
         // Group 1: User Actions
         items.add(ListItem.from("  📩 Send Message"));
         items.add(ListItem.from("  🐪 Run an example..."));
@@ -2288,6 +2354,196 @@ class ActionsPopup {
         return true;
     }
 
+    // ---- Go-to tab popup ----
+
+    private void openGotoPopup() {
+        showGotoPopup = true;
+        gotoFilter.clearFilter();
+        rebuildGotoList();
+    }
+
+    private void rebuildGotoList() {
+        if (allTabEntries == null) {
+            filteredTabEntries = List.of();
+            return;
+        }
+        if (!gotoFilter.hasFilter()) {
+            filteredTabEntries = new ArrayList<>(allTabEntries);
+        } else {
+            filteredTabEntries = new ArrayList<>();
+            String filter = gotoFilter.filter();
+            for (TabRegistry.TabEntry entry : allTabEntries) {
+                // 1 char: starts-with on name only; 2+ chars: fuzzy name + 
substring description
+                boolean nameMatch;
+                if (filter.length() == 1) {
+                    nameMatch = entry.name().toLowerCase().startsWith(filter);
+                } else {
+                    nameMatch = gotoFilter.match(entry.name()) != null;
+                }
+                boolean descMatch = filter.length() >= 2 && 
entry.description() != null
+                        && entry.description().toLowerCase().contains(filter);
+                if (nameMatch || descMatch) {
+                    filteredTabEntries.add(entry);
+                }
+            }
+        }
+        gotoListState.select(filteredTabEntries.isEmpty() ? null : 0);
+    }
+
+    private void navigateToTabEntry(TabRegistry.TabEntry entry) {
+        if (entry.moreIndex() >= 0) {
+            // More sub-tab — use selectMoreTab callback
+            if (gotoTabCallback != null) {
+                // Store the entry info for the callback to use
+                pendingGotoEntry = entry;
+                gotoTabCallback.run();
+            }
+        } else {
+            // Primary tab — use handleTabKey callback
+            if (gotoTabCallback != null) {
+                pendingGotoEntry = entry;
+                gotoTabCallback.run();
+            }
+        }
+    }
+
+    private TabRegistry.TabEntry pendingGotoEntry;
+
+    TabRegistry.TabEntry consumePendingGotoEntry() {
+        TabRegistry.TabEntry e = pendingGotoEntry;
+        pendingGotoEntry = null;
+        return e;
+    }
+
+    private void renderGotoPopup(Frame frame, Rect area) {
+        if (filteredTabEntries == null) {
+            return;
+        }
+        int nameColWidth = 18;
+        int popupW = Math.min(100, area.width() - 4);
+        int descColWidth = popupW - nameColWidth - 8; // 2 border + 3 key col 
+ 3 padding
+        int listH = Math.min(filteredTabEntries.size(), Math.min(28, 
area.height() - 8));
+        int popupH = listH + 4; // borders + filter row + separator
+        int x = area.left() + Math.max(0, (area.width() - popupW) / 2);
+        int y = area.top() + 2;
+        Rect popup = new Rect(x, y, Math.min(popupW, area.width()), 
Math.min(popupH, area.height() - 2));
+        this.gotoPopupRect = popup;
+
+        frame.renderWidget(Clear.INSTANCE, popup);
+
+        // Build filter display line
+        String filterText = gotoFilter.hasFilter() ? gotoFilter.filter() : "";
+        String prompt = "> " + filterText + "█";
+
+        List<ListItem> items = new ArrayList<>();
+        // Filter input row
+        items.add(ListItem.from(Line.from(Span.styled(prompt, Theme.info()))));
+        // Separator
+        String sep = "─".repeat(Math.max(1, popupW - 2));
+        items.add(ListItem.from(Line.from(Span.styled(sep, 
Style.EMPTY.dim()))));
+
+        // Tab entries
+        Style normalStyle = Style.EMPTY;
+        Style matchStyle = Style.EMPTY.fg(Color.YELLOW).bold();
+        Style dimStyle = Style.EMPTY.dim();
+        for (TabRegistry.TabEntry entry : filteredTabEntries) {
+            List<Span> spans = new ArrayList<>();
+            // Shortcut key column
+            String key = String.format(" %-2s ", entry.shortcut());
+            spans.add(Span.styled(key, dimStyle));
+            // Name column with fuzzy highlight
+            String name = entry.name();
+            if (name.length() > nameColWidth) {
+                name = name.substring(0, nameColWidth);
+            } else {
+                name = String.format("%-" + nameColWidth + "s", name);
+            }
+            if (gotoFilter.hasFilter()) {
+                int[] nameMatch = FuzzyFilter.fuzzyMatch(name, 
gotoFilter.filter());
+                if (nameMatch != null) {
+                    Line hl = FuzzyFilter.highlightLine(name, nameMatch, 
normalStyle, matchStyle);
+                    spans.addAll(hl.spans());
+                } else {
+                    spans.add(Span.styled(name, normalStyle));
+                }
+            } else {
+                spans.add(Span.styled(name, normalStyle));
+            }
+            // Description column (dimmed, with substring highlight)
+            String desc = entry.description();
+            if (desc != null) {
+                if (desc.length() > descColWidth) {
+                    desc = desc.substring(0, Math.max(0, descColWidth - 1)) + 
"…";
+                }
+                spans.add(Span.styled(" ", dimStyle));
+                if (gotoFilter.hasFilter() && gotoFilter.filter().length() >= 
2) {
+                    String filter = gotoFilter.filter();
+                    int idx = desc.toLowerCase().indexOf(filter);
+                    if (idx >= 0) {
+                        if (idx > 0) {
+                            spans.add(Span.styled(desc.substring(0, idx), 
dimStyle));
+                        }
+                        spans.add(Span.styled(desc.substring(idx, idx + 
filter.length()), matchStyle));
+                        if (idx + filter.length() < desc.length()) {
+                            spans.add(Span.styled(desc.substring(idx + 
filter.length()), dimStyle));
+                        }
+                    } else {
+                        spans.add(Span.styled(desc, dimStyle));
+                    }
+                } else {
+                    spans.add(Span.styled(desc, dimStyle));
+                }
+            }
+            items.add(ListItem.from(Line.from(spans)));
+        }
+
+        // The list has 2 header items (filter + separator) + entries
+        // We need to offset the selection by 2 to account for the header
+        ListState renderState = new ListState();
+        Integer sel = gotoListState.selected();
+        if (sel != null) {
+            renderState.select(sel + 2); // offset for filter row + separator
+        }
+
+        ListWidget list = ListWidget.builder()
+                .items(items.toArray(ListItem[]::new))
+                .highlightStyle(Theme.selectionBg())
+                .highlightSymbol("")
+                .scrollMode(ScrollMode.AUTO_SCROLL)
+                .block(Block.builder()
+                        .borderType(BorderType.ROUNDED).borders(Borders.ALL)
+                        .title(" Go to Tab ")
+                        .build())
+                .build();
+        frame.renderStatefulWidget(list, popup, renderState);
+    }
+
+    private boolean handleGotoPopupMouse(MouseEvent me) {
+        if (me.kind() == MouseEventKind.SCROLL_UP) {
+            handleKeyEvent(KeyEvent.ofKey(KeyCode.UP));
+            return true;
+        }
+        if (me.kind() == MouseEventKind.SCROLL_DOWN) {
+            handleKeyEvent(KeyEvent.ofKey(KeyCode.DOWN));
+            return true;
+        }
+        if (me.isClick()) {
+            if (gotoPopupRect != null && gotoPopupRect.contains(me.x(), 
me.y())) {
+                int idx = listItemAt(gotoPopupRect, 0,
+                        (filteredTabEntries != null ? 
filteredTabEntries.size() : 0) + 2,
+                        me.x(), me.y());
+                if (idx >= 2 && filteredTabEntries != null && idx - 2 < 
filteredTabEntries.size()) {
+                    gotoListState.select(idx - 2);
+                    handleKeyEvent(KeyEvent.ofKey(KeyCode.ENTER));
+                }
+                return true;
+            }
+            handleKeyEvent(KeyEvent.ofKey(KeyCode.ESCAPE));
+            return true;
+        }
+        return true;
+    }
+
     private record PendingLaunch(String name, Process process, Path 
outputFile, long startTime) {
     }
 
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 37c2833c8c57..cad5f1964ee3 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
@@ -427,6 +427,11 @@ class BeansTab extends AbstractTableTab {
         }
     }
 
+    @Override
+    public String description() {
+        return "Registered beans in the Camel registry";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 b0aedb6f2d15..91f26da31b2b 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
@@ -696,6 +696,11 @@ class BrowseTab extends AbstractTab {
         long timestamp;
     }
 
+    @Override
+    public String description() {
+        return "Browse messages queued in browsable endpoints (e.g. SEDA)";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 23c511ac7e91..0b45b55c4727 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
@@ -287,6 +287,17 @@ public class CamelMonitor extends CamelCommand {
             }
         });
 
+        actionsPopup.setGotoTabSupport(tabRegistry.allTabEntries(), () -> {
+            TabRegistry.TabEntry entry = 
actionsPopup.consumePendingGotoEntry();
+            if (entry != null) {
+                if (entry.moreIndex() >= 0) {
+                    tabRegistry.selectMoreTab(entry.moreIndex());
+                } else {
+                    tabRegistry.handleTabKey(entry.tabIndex(), ctx, 
dataService);
+                }
+            }
+        });
+
         popupManager = new PopupManager(
                 ctx, this::getNonVanishingIntegrations, filesBrowser,
                 new PopupManager.PopupCallbacks() {
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 07d83f20b18b..3973feeb1287 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
@@ -377,6 +377,11 @@ class CircuitBreakerTab extends AbstractTableTab {
         return new SelectionContext("table", items, sel != null ? sel : -1, 
items.size(), "Circuit Breakers");
     }
 
+    @Override
+    public String description() {
+        return "Circuit breaker state and statistics (Resilience4j)";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 b19682610caf..df85defa5013 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
@@ -424,6 +424,11 @@ class ClasspathTab extends AbstractTab {
     record FilteredEntry(JarEntry entry, int[] matchPositions) {
     }
 
+    @Override
+    public String description() {
+        return "JVM classpath entries with filtering";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 883aa87c74ed..d164e936cf72 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
@@ -258,6 +258,11 @@ class ConfigurationTab extends AbstractTab {
         String location;
     }
 
+    @Override
+    public String description() {
+        return "Application configuration properties";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 e454fb50c8b2..6feb26e385cc 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
@@ -279,6 +279,11 @@ class ConsumersTab extends AbstractTableTab {
         return new SelectionContext("table", items, sel != null ? sel : -1, 
items.size(), "Consumers");
     }
 
+    @Override
+    public String description() {
+        return "Consumer statistics (polling and event-driven consumers)";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 8bee8b5f0417..de6011fe2255 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
@@ -152,6 +152,11 @@ class DataSourceTab extends AbstractTableTab {
         return new SelectionContext("table", items, sel != null ? sel : -1, 
items.size(), "DataSource");
     }
 
+    @Override
+    public String description() {
+        return "JDBC DataSource pool statistics (active, idle, max 
connections)";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 97d7cfb0e380..6a669d6b9f7b 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
@@ -728,6 +728,11 @@ class DiagramTab extends AbstractTab {
         });
     }
 
+    @Override
+    public String description() {
+        return "Route topology diagram showing how routes connect to each 
other and external systems";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 d70facbf5c1b..23da8ba7b73a 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
@@ -664,6 +664,11 @@ class EndpointsTab extends AbstractTableTab {
         return new SelectionContext("table", items, sel != null ? sel : -1, 
items.size(), "Endpoints");
     }
 
+    @Override
+    public String description() {
+        return "Registered endpoints with usage statistics (hits, direction)";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 31b1279c7ac5..ce0904344cb1 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
@@ -735,6 +735,11 @@ class ErrorsTab extends AbstractTableTab {
         });
     }
 
+    @Override
+    public String description() {
+        return "Routing errors with exception details, stack traces, and 
exchange context";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 eff82d38c861..c2a4a6d04e11 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
@@ -176,6 +176,11 @@ class HealthTab extends AbstractTableTab {
         return new SelectionContext("table", items, sel != null ? sel : -1, 
items.size(), "Health");
     }
 
+    @Override
+    public String description() {
+        return "Health check status for readiness and liveness probes";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 77bf232f2e88..72644ef64b4f 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
@@ -315,6 +315,11 @@ class HeapHistogramTab extends AbstractTableTab {
         return result;
     }
 
+    @Override
+    public String description() {
+        return "Class-level heap memory analysis showing instance counts, byte 
usage, package summary, and JAR origin per class";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 9bba7575a7f8..16ad6de044d5 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
@@ -2251,6 +2251,11 @@ class HistoryTab extends AbstractTab {
         return new SelectionContext("table", items, sel != null ? sel : -1, 
items.size(), "History");
     }
 
+    @Override
+    public String description() {
+        return "Message history trace showing route path, headers, body, and 
timing";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 7bd712ea120f..0039896dea6d 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
@@ -1584,6 +1584,11 @@ class HttpTab extends AbstractTableTab {
             String statusText, boolean error) {
     }
 
+    @Override
+    public String description() {
+        return "HTTP endpoint probe — send requests and inspect responses";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 2fdacf4c1db8..c4a36a794f8f 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
@@ -199,6 +199,11 @@ class InflightTab extends AbstractTableTab {
         return sortReversed ? -result : result;
     }
 
+    @Override
+    public String description() {
+        return "Currently in-flight exchanges being processed";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 a6a697dcb466..08c3e5902624 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
@@ -645,6 +645,11 @@ class LogTab extends AbstractTab {
         return entry;
     }
 
+    @Override
+    public String description() {
+        return "Live application log with ANSI color support and filtering";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 06e4a7d0dc65..55b58af1e523 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
@@ -23,7 +23,6 @@ import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Queue;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -94,42 +93,6 @@ class McpFacade {
             "SQL Query", "SQL Trace", "Spans", "Process", "Startup", "Threads"
     };
 
-    static final Map<String, String> TAB_DESCRIPTIONS = Map.ofEntries(
-            Map.entry("Overview", "Running integrations with PID, uptime, and 
exchange statistics"),
-            Map.entry("Log", "Live application log with ANSI color support and 
filtering"),
-            Map.entry("Diagram", "Route topology diagram showing how routes 
connect to each other and external systems"),
-            Map.entry("Routes", "Route list with state, message counts, 
throughput, and failure statistics"),
-            Map.entry("Endpoints", "Registered endpoints with usage statistics 
(hits, direction)"),
-            Map.entry("HTTP", "HTTP endpoint probe — send requests and inspect 
responses"),
-            Map.entry("Health", "Health check status for readiness and 
liveness probes"),
-            Map.entry("Inspect", "Message history trace showing route path, 
headers, body, and timing"),
-            Map.entry("Errors", "Routing errors with exception details, stack 
traces, and exchange context"),
-            Map.entry("Beans", "Registered beans in the Camel registry"),
-            Map.entry("Browse", "Browse messages queued in browsable endpoints 
(e.g. SEDA)"),
-            Map.entry("Circuit Breaker", "Circuit breaker state and statistics 
(Resilience4j)"),
-            Map.entry("Classpath", "JVM classpath entries with filtering"),
-            Map.entry("Configuration", "Application configuration properties"),
-            Map.entry("Consumers", "Consumer statistics (polling and 
event-driven consumers)"),
-            Map.entry("DataSource", "JDBC DataSource pool statistics (active, 
idle, max connections)"),
-            Map.entry("Heap Histogram",
-                    "Class-level heap memory analysis showing instance counts, 
byte usage, package summary, and JAR origin per class"),
-            Map.entry("Inflight", "Currently in-flight exchanges being 
processed"),
-            Map.entry("Memory", "JVM memory usage (heap/non-heap), GC stats, 
and thread counts"),
-            Map.entry("Memory Leak",
-                    "Memory leak diagnosis using JFR recording — shows objects 
surviving multiple GC cycles with reference chains and allocation stack 
traces"),
-            Map.entry("Metrics", "Micrometer metrics (counters, gauges, 
timers, distribution summaries)"),
-            Map.entry("SQL Query",
-                    "Execute SQL queries against DataSources in the running 
application and browse results"),
-            Map.entry("SQL Trace",
-                    "Trace SQL query executions through camel-sql and 
camel-jdbc components. "
-                                   + "Shows per-query timing, row counts, and 
failure status. "
-                                   + "Use to identify slow queries, fastest 
queries, most frequent queries, "
-                                   + "and failed SQL executions. Sortable by 
time, type, duration, and rows."),
-            Map.entry("Spans", "OpenTelemetry spans with trace/span IDs, 
timing, and attributes"),
-            Map.entry("Process", "OS process information (PID, CPU, memory, 
file descriptors)"),
-            Map.entry("Startup", "Startup step recorder showing initialization 
timing"),
-            Map.entry("Threads", "JVM thread dump with thread names, states, 
and stack traces"));
-
     private final MonitorContext ctx;
     private final AtomicReference<List<IntegrationInfo>> data;
     private final TabsState tabsState;
@@ -301,6 +264,10 @@ class McpFacade {
         return names;
     }
 
+    List<TabRegistry.TabEntry> getTabEntries() {
+        return tabRegistry.allTabEntries();
+    }
+
     List<String> getActionLabels() {
         return actionsPopup.getActionLabels();
     }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MemoryLeakTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MemoryLeakTab.java
index 028ced64c25d..c8a246a5e485 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MemoryLeakTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MemoryLeakTab.java
@@ -848,6 +848,11 @@ class MemoryLeakTab extends AbstractTab {
         return result;
     }
 
+    @Override
+    public String description() {
+        return "Memory leak diagnosis using JFR recording";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 c3ee7e572bde..a3a9acaabfc3 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
@@ -403,6 +403,11 @@ class MemoryTab extends AbstractTab {
         PathUtils.writeTextSafely(root.toJson(), actionFile);
     }
 
+    @Override
+    public String description() {
+        return "JVM memory usage (heap/non-heap), GC stats, and thread counts";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 231c60e87eb3..ed1e7abc3ac7 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
@@ -901,6 +901,11 @@ class MetricsTab extends AbstractTableTab {
         return new SelectionContext("table", items, sel != null ? sel : -1, 
items.size(), "Metrics");
     }
 
+    @Override
+    public String description() {
+        return "Micrometer metrics (counters, gauges, timers, distribution 
summaries)";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 8520d2b5c9d0..b7ef0143d3bc 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
@@ -68,6 +68,8 @@ interface MonitorTab {
         return null;
     }
 
+    String description();
+
     default String getHelpText() {
         return null;
     }
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 587f74e95a48..8b859518a76b 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
@@ -862,6 +862,11 @@ class OverviewTab extends AbstractTab {
         return sortStyle(column, sort);
     }
 
+    @Override
+    public String description() {
+        return "Running integrations with PID, uptime, and exchange 
statistics";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 a3e0827c6a70..12215adc5db9 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
@@ -54,6 +54,11 @@ class ProcessTab extends AbstractTab {
         super(ctx);
     }
 
+    @Override
+    public String description() {
+        return "OS process information (PID, CPU, memory, file descriptors)";
+    }
+
     @Override
     public boolean handleKeyEvent(KeyEvent ke) {
         if (ke.isChar('w')) {
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 698fedbaf022..bb031f6eec95 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
@@ -1561,6 +1561,11 @@ class RoutesTab extends AbstractTab {
         return new SelectionContext("table", items, sel != null ? sel : -1, 
items.size(), "Routes");
     }
 
+    @Override
+    public String description() {
+        return "Route list with state, message counts, throughput, and failure 
statistics";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 85d5e5de9667..3e2cb3021f7e 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
@@ -985,6 +985,11 @@ class SpansTab extends AbstractTab {
         return id.length() > 8 ? id.substring(0, 8) : id;
     }
 
+    @Override
+    public String description() {
+        return "OpenTelemetry spans with trace/span IDs, timing, and 
attributes";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 6b6af98490e8..40775ad7ea69 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
@@ -840,6 +840,11 @@ class SqlQueryTab extends AbstractTab {
         }
     }
 
+    @Override
+    public String description() {
+        return "Execute SQL queries against DataSources in the running 
application and browse results";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 4701b41d23dc..ddf7f3e97115 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
@@ -438,6 +438,11 @@ class SqlTraceTab extends AbstractTableTab {
         return new SelectionContext("table", items, sel != null ? sel : -1, 
items.size(), "SQL Trace");
     }
 
+    @Override
+    public String description() {
+        return "Trace SQL query executions through camel-sql and camel-jdbc 
components";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 48337147cc30..386b080e6431 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
@@ -359,6 +359,11 @@ class StartupTab extends AbstractTab {
         long duration;
     }
 
+    @Override
+    public String description() {
+        return "Startup step recorder showing initialization timing";
+    }
+
     @Override
     public String getHelpText() {
         return """
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 dfb7e67b604e..b5efb3570005 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
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.dsl.jbang.core.commands.tui;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import dev.tamboui.widgets.tabs.TabsState;
@@ -319,4 +320,43 @@ class TabRegistry {
     SqlQueryTab sqlQueryTab() {
         return sqlQueryTab;
     }
+
+    // ---- Tab entries for Go-to and MCP ----
+
+    record TabEntry(String name, String description, String shortcut, int 
tabIndex, int moreIndex) {
+    }
+
+    private static final String[] MORE_SHORTCUTS = {
+            "B", "W", "C", "A", "G", "N", "D", "H", "I", "M", "K", "E", "Q", 
"R", "O", "P", "S", "T"
+    };
+
+    List<TabEntry> allTabEntries() {
+        List<TabEntry> entries = new ArrayList<>();
+        entries.add(new TabEntry("Overview", overviewTab.description(), "1", 
TAB_OVERVIEW, -1));
+        entries.add(new TabEntry("Log", logTab.description(), "2", TAB_LOG, 
-1));
+        entries.add(new TabEntry("Diagram", diagramTab.description(), "3", 
TAB_DIAGRAM, -1));
+        entries.add(new TabEntry("Routes", routesTab.description(), "4", 
TAB_ROUTES, -1));
+        entries.add(new TabEntry("Endpoints", endpointsTab.description(), "5", 
TAB_ENDPOINTS, -1));
+        entries.add(new TabEntry("HTTP", httpTab.description(), "6", TAB_HTTP, 
-1));
+        entries.add(new TabEntry("Health", healthTab.description(), "7", 
TAB_HEALTH, -1));
+        entries.add(new TabEntry("Inspect", historyTab.description(), "8", 
TAB_HISTORY, -1));
+        entries.add(new TabEntry("Errors", errorsTab.description(), "9", 
TAB_ERRORS, -1));
+        // More sub-tabs
+        MonitorTab[] moreTabs = {
+                beansTab, browseTab, circuitBreakerTab, classpathTab, 
configurationTab,
+                consumersTab, dataSourceTab, heapHistogramTab, inflightTab, 
memoryTab,
+                memoryLeakTab, metricsTab, sqlQueryTab, sqlTraceTab, spansTab,
+                processTab, startupTab, threadsTab
+        };
+        String[] moreNames = {
+                "Beans", "Browse", "Circuit Breaker", "Classpath", 
"Configuration",
+                "Consumers", "DataSource", "Heap Histogram", "Inflight", 
"Memory",
+                "Memory Leak", "Metrics", "SQL Query", "SQL Trace", "Spans",
+                "Process", "Startup", "Threads"
+        };
+        for (int i = 0; i < moreTabs.length; i++) {
+            entries.add(new TabEntry(moreNames[i], moreTabs[i].description(), 
MORE_SHORTCUTS[i], TAB_MORE, i));
+        }
+        return entries;
+    }
 }
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 f5fb6889c85a..ed9712c99392 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
@@ -467,6 +467,11 @@ class ThreadsTab extends AbstractTableTab {
         List<String> stackTrace;
     }
 
+    @Override
+    public String description() {
+        return "JVM thread dump with thread names, states, and stack traces";
+    }
+
     @Override
     public String getHelpText() {
         return """
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiMcpServer.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiMcpServer.java
index aca263d72773..c3a7436c38c8 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiMcpServer.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiMcpServer.java
@@ -930,12 +930,11 @@ class TuiMcpServer {
     private String callGetOptions() {
         JsonObject result = new JsonObject();
         JsonArray tabsArray = new JsonArray();
-        for (String name : facade.getTabNames()) {
+        for (TabRegistry.TabEntry entry : facade.getTabEntries()) {
             JsonObject tab = new JsonObject();
-            tab.put("name", name);
-            String desc = McpFacade.TAB_DESCRIPTIONS.get(name);
-            if (desc != null) {
-                tab.put("description", desc);
+            tab.put("name", entry.name());
+            if (entry.description() != null) {
+                tab.put("description", entry.description());
             }
             tabsArray.add(tab);
         }

Reply via email to