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);
}