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 dc3f83c2cbb1 CAMEL-23912: Add Maven Dependencies TUI tab
dc3f83c2cbb1 is described below

commit dc3f83c2cbb1e141af2ff464df56ff6328bf540b
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Jul 6 10:18:29 2026 +0200

    CAMEL-23912: Add Maven Dependencies TUI tab
    
    New "More" tab showing declared Maven dependencies for the selected
    integration. Reads from pom.xml (exported Spring Boot/Quarkus apps)
    or .camel-jbang-run.properties (JBang mode). Uses sortable table
    with GROUP:ARTIFACT and VERSION columns, filter support, and
    property resolution for ${...} placeholders.
    
    Also renames DataSource tab to "JDBC DataSource" to resolve mnemonic
    collision (both had 'D' shortcut).
    
    CAMEL-23912: Add scope toggle to Classpath and Maven Dependencies tabs
    
    Press f to cycle scope (all/camel/other) to quickly filter by
    Camel vs third-party dependencies. Matches the existing scope
    pattern used in the Beans tab.
    
    CAMEL-23912: Add on-demand transitive dependency resolution with parent 
tracking
    
    CAMEL-23912: Update TabRegistryTest for Maven Dependencies tab
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  |   5 +-
 .../dsl/jbang/core/commands/tui/ClasspathTab.java  |  58 +-
 .../dsl/jbang/core/commands/tui/DataSourceTab.java |   4 +-
 .../core/commands/tui/MavenDependenciesTab.java    | 885 +++++++++++++++++++++
 .../dsl/jbang/core/commands/tui/TabRegistry.java   |  10 +-
 .../dsl/jbang/core/commands/tui/TuiIcons.java      |   1 +
 .../jbang/core/commands/tui/TabRegistryTest.java   |   6 +-
 7 files changed, 952 insertions(+), 17 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
index 2e37d0bb2374..63028e631a96 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
@@ -574,11 +574,14 @@ public class CamelMonitor extends CamelCommand {
         boolean classpathFilterActive = tabRegistry.selectedTabIndex() == 
TAB_MORE
                 && tabRegistry.getActiveMoreTab() == tabRegistry.classpathTab()
                 && tabRegistry.classpathTab().isFilterInputActive();
+        boolean mavenDepsFilterActive = tabRegistry.selectedTabIndex() == 
TAB_MORE
+                && tabRegistry.getActiveMoreTab() == 
tabRegistry.mavenDependenciesTab()
+                && tabRegistry.mavenDependenciesTab().isFilterInputActive();
         boolean sqlInputActive = tabRegistry.selectedTabIndex() == TAB_MORE
                 && tabRegistry.getActiveMoreTab() == tabRegistry.sqlQueryTab()
                 && tabRegistry.sqlQueryTab().isInputActive();
         boolean textEditing = probeEditing || logSearchActive || 
spanFilterActive || beanFilterActive
-                || classpathFilterActive || sqlInputActive;
+                || classpathFilterActive || mavenDepsFilterActive || 
sqlInputActive;
         if (!textEditing && (ke.isCharIgnoreCase('q') || ke.isCtrlC())) {
             runner.quit();
             return true;
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ClasspathTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ClasspathTab.java
index 90ad5700604d..d83afd0ccea6 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
@@ -52,6 +52,8 @@ import static 
org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
 
 class ClasspathTab extends AbstractTab {
 
+    private static final String[] SCOPES = { "all", "camel", "other" };
+
     private final ListState listState = new ListState();
     private final ScrollbarState listScrollState = new ScrollbarState();
     private final AtomicBoolean loading = new AtomicBoolean(false);
@@ -60,6 +62,7 @@ class ClasspathTab extends AbstractTab {
     private boolean filterInputActive;
     private TextInputState filterInputState = new TextInputState("");
     private String filterTerm;
+    private int scopeIndex;
     private List<JarEntry> allEntries = Collections.emptyList();
     private List<JarEntry> filteredEntries = Collections.emptyList();
     private String lastPid;
@@ -89,6 +92,7 @@ class ClasspathTab extends AbstractTab {
         filteredEntries = Collections.emptyList();
         filterTerm = null;
         filterInputActive = false;
+        scopeIndex = 0;
         lastPid = null;
         errorMessage = null;
         dataLoaded = false;
@@ -104,6 +108,11 @@ class ClasspathTab extends AbstractTab {
             filterInputState = new TextInputState(filterTerm != null ? 
filterTerm : "");
             return true;
         }
+        if (ke.isCharIgnoreCase('f')) {
+            scopeIndex = (scopeIndex + 1) % SCOPES.length;
+            refilter();
+            return true;
+        }
         if (ke.isPageUp() || ke.isKey(KeyCode.PAGE_UP)) {
             for (int i = 0; i < 20 && listState.selected() != null && 
listState.selected() > 0; i++) {
                 listState.selectPrevious();
@@ -222,9 +231,22 @@ class ClasspathTab extends AbstractTab {
             items.add(ListItem.from("  No classpath entries 
found").style(Style.EMPTY.dim()));
         }
 
-        String title = filterTerm != null
-                ? String.format(" Classpath [%d/%d] filter:\"%s\" ", 
filteredEntries.size(), allEntries.size(), filterTerm)
-                : String.format(" Classpath [%d] ", filteredEntries.size());
+        String scope = SCOPES[scopeIndex];
+        StringBuilder sb = new StringBuilder(" Classpath [");
+        if (filterTerm != null || !"all".equals(scope)) {
+            
sb.append(filteredEntries.size()).append('/').append(allEntries.size());
+        } else {
+            sb.append(filteredEntries.size());
+        }
+        sb.append(']');
+        if (!"all".equals(scope)) {
+            sb.append(" scope:").append(scope);
+        }
+        if (filterTerm != null) {
+            sb.append(" filter:\"").append(filterTerm).append('"');
+        }
+        sb.append(' ');
+        String title = sb.toString();
 
         ListWidget list = ListWidget.builder()
                 .items(items.toArray(ListItem[]::new))
@@ -257,6 +279,7 @@ class ClasspathTab extends AbstractTab {
             return;
         }
         hint(spans, "Esc", filterTerm != null ? "clear" : "back");
+        hint(spans, "f", "scope [" + SCOPES[scopeIndex] + "]");
         if (filterTerm != null) {
             spans.add(Span.styled("  /", Style.EMPTY.fg(Color.YELLOW).bold()));
             spans.add(Span.raw("\"" + filterTerm + "\"  "));
@@ -341,10 +364,18 @@ class ClasspathTab extends AbstractTab {
     private void refilter() {
         List<JarEntry> result = new ArrayList<>();
         String ft = filterTerm != null ? filterTerm.toLowerCase() : null;
+        String scope = SCOPES[scopeIndex];
         for (JarEntry entry : allEntries) {
-            if (ft == null || entry.display().toLowerCase().contains(ft)) {
-                result.add(entry);
+            if ("camel".equals(scope) && !entry.isCamel()) {
+                continue;
+            }
+            if ("other".equals(scope) && entry.isCamel()) {
+                continue;
             }
+            if (ft != null && !entry.display().toLowerCase().contains(ft)) {
+                continue;
+            }
+            result.add(entry);
         }
         filteredEntries = result;
         listState.select(filteredEntries.isEmpty() ? null : 0);
@@ -454,16 +485,22 @@ class ClasspathTab extends AbstractTab {
                  org.slf4j:slf4j-api                         2.0.16
                 ```
 
+                ## Scope
+
+                Press `f` to cycle the scope filter:
+
+                - **all** — show all classpath entries (default)
+                - **camel** — show only Apache Camel JARs
+                - **other** — show only non-Camel (third-party) JARs
+
+                The active scope is shown in the footer and title bar.
+
                 ## Filter
 
                 Press `/` to open the filter input. Type a search term and 
press
                 `Enter` to filter the classpath by substring match. For 
example,
                 type `kafka` to find all Kafka-related JARs, or `jackson` to 
find
-                Jackson dependencies.
-
-                - `/` — open filter input
-                - `Enter` — apply filter
-                - `Esc` — clear filter
+                Jackson dependencies. The scope and text filter work together.
 
                 ## When To Use
 
@@ -476,6 +513,7 @@ class ClasspathTab extends AbstractTab {
 
                 - `Up/Down` — navigate entries
                 - `PgUp/PgDn` — scroll by page
+                - `f` — cycle scope (all, camel, other)
                 - `/` — open filter
                 - `Esc` — clear filter or back
                 """;
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 8600f6ef787d..726dd6aca8e5 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
@@ -176,7 +176,7 @@ class DataSourceTab extends AbstractTableTab {
         sorted.sort(this::sortDataSource);
         List<String> items = sorted.stream().map(d -> d.name != null ? d.name 
: "").toList();
         Integer sel = tableState.selected();
-        return new SelectionContext("table", items, sel != null ? sel : -1, 
items.size(), "DataSource");
+        return new SelectionContext("table", items, sel != null ? sel : -1, 
items.size(), "JDBC DataSource");
     }
 
     @Override
@@ -236,7 +236,7 @@ class DataSourceTab extends AbstractTableTab {
             return null;
         }
         JsonObject result = new JsonObject();
-        result.put("tab", "DataSource");
+        result.put("tab", "JDBC DataSource");
         JsonArray rows = new JsonArray();
         for (DataSourceInfo di : info.dataSources) {
             JsonObject row = new JsonObject();
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MavenDependenciesTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MavenDependenciesTab.java
new file mode 100644
index 000000000000..b1fb11836596
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MavenDependenciesTab.java
@@ -0,0 +1,885 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.tui;
+
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import dev.tamboui.layout.Constraint;
+import dev.tamboui.layout.Rect;
+import dev.tamboui.style.Color;
+import dev.tamboui.style.Style;
+import dev.tamboui.terminal.Frame;
+import dev.tamboui.text.Line;
+import dev.tamboui.text.Span;
+import dev.tamboui.text.Text;
+import dev.tamboui.tui.event.KeyCode;
+import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.widgets.block.Block;
+import dev.tamboui.widgets.block.BorderType;
+import dev.tamboui.widgets.block.Borders;
+import dev.tamboui.widgets.input.TextInputState;
+import dev.tamboui.widgets.paragraph.Paragraph;
+import dev.tamboui.widgets.table.Cell;
+import dev.tamboui.widgets.table.Row;
+import dev.tamboui.widgets.table.Table;
+import org.apache.camel.dsl.jbang.core.common.XmlHelper;
+import org.apache.camel.tooling.maven.MavenArtifact;
+import org.apache.camel.tooling.maven.MavenDownloaderImpl;
+import org.apache.camel.tooling.maven.MavenGav;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+
+import static org.apache.camel.dsl.jbang.core.commands.tui.TuiHelper.*;
+
+/**
+ * TUI tab showing declared Maven dependencies for the selected integration. 
Reads from pom.xml (for exported Spring
+ * Boot / Quarkus apps) or from .camel-jbang/camel-jbang-run.properties (for 
JBang mode). Unlike the Classpath tab, this
+ * filters out internal infrastructure JARs and shows only the dependencies 
the user's application actually declares.
+ */
+class MavenDependenciesTab extends AbstractTableTab {
+
+    private static final String[] SCOPES = { "all", "camel", "other" };
+
+    private final AtomicBoolean loading = new AtomicBoolean(false);
+
+    private boolean filterInputActive;
+    private TextInputState filterInputState = new TextInputState("");
+    private String filterTerm;
+    private int scopeIndex;
+    private List<DepEntry> allEntries = Collections.emptyList();
+    private List<DepEntry> filteredEntries = Collections.emptyList();
+    private String lastPid;
+    private String errorMessage;
+    private boolean dataLoaded;
+    private String dataSource;
+    private boolean transitiveMode;
+    private boolean transitiveLoading;
+    private boolean transitiveLoaded;
+    private List<DepEntry> transitiveEntries = Collections.emptyList();
+
+    MavenDependenciesTab(MonitorContext ctx) {
+        super(ctx, "artifact", "version");
+    }
+
+    @Override
+    public void onTabSelected() {
+        String pid = ctx.selectedPid;
+        if (pid != null && !pid.equals(lastPid)) {
+            lastPid = pid;
+            allEntries = Collections.emptyList();
+            dataLoaded = false;
+        }
+        if (!dataLoaded) {
+            loadDependencies();
+        }
+    }
+
+    @Override
+    public void onIntegrationChanged() {
+        allEntries = Collections.emptyList();
+        filteredEntries = Collections.emptyList();
+        filterTerm = null;
+        filterInputActive = false;
+        scopeIndex = 0;
+        lastPid = null;
+        errorMessage = null;
+        dataLoaded = false;
+        dataSource = null;
+        transitiveMode = false;
+        transitiveLoading = false;
+        transitiveLoaded = false;
+        transitiveEntries = Collections.emptyList();
+    }
+
+    @Override
+    public boolean handleKeyEvent(KeyEvent ke) {
+        if (filterInputActive) {
+            return handleFilterInput(ke);
+        }
+        return super.handleKeyEvent(ke);
+    }
+
+    @Override
+    protected boolean handleTabKeyEvent(KeyEvent ke) {
+        if (ke.isChar('/')) {
+            filterInputActive = true;
+            filterInputState = new TextInputState(filterTerm != null ? 
filterTerm : "");
+            return true;
+        }
+        if (ke.isCharIgnoreCase('f')) {
+            scopeIndex = (scopeIndex + 1) % SCOPES.length;
+            refilter();
+            return true;
+        }
+        if (ke.isCharIgnoreCase('t')) {
+            if (!transitiveLoaded && !transitiveLoading) {
+                resolveTransitives();
+            } else {
+                transitiveMode = !transitiveMode;
+                refilter();
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private boolean handleFilterInput(KeyEvent ke) {
+        if (ke.isKey(KeyCode.ESCAPE)) {
+            filterInputActive = false;
+            return true;
+        }
+        if (ke.isConfirm()) {
+            String text = filterInputState.text().trim();
+            filterTerm = text.isEmpty() ? null : text;
+            filterInputActive = false;
+            refilter();
+            return true;
+        }
+        FormHelper.handleTextInput(ke, filterInputState);
+        return true;
+    }
+
+    boolean isFilterInputActive() {
+        return filterInputActive;
+    }
+
+    @Override
+    public boolean handleEscape() {
+        if (filterTerm != null) {
+            filterTerm = null;
+            refilter();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    protected int getRowCount() {
+        return filteredEntries.size();
+    }
+
+    @Override
+    public void render(Frame frame, Rect area) {
+        IntegrationInfo info = ctx.findSelectedIntegration();
+        if (info == null) {
+            renderNoSelection(frame, area);
+            return;
+        }
+
+        if (loading.get() && allEntries.isEmpty()) {
+            frame.renderWidget(
+                    Paragraph.builder()
+                            .text(Text.from(Line.from(Span.styled("  Loading 
dependencies...", Style.EMPTY.dim()))))
+                            
.block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL)
+                                    .title(" Maven Dependencies ").build())
+                            .build(),
+                    area);
+            return;
+        }
+
+        if (errorMessage != null && allEntries.isEmpty()) {
+            frame.renderWidget(
+                    Paragraph.builder()
+                            .text(Text.from(Line.from(
+                                    Span.styled("  " + errorMessage, 
Style.EMPTY.fg(Color.LIGHT_RED)))))
+                            
.block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL)
+                                    .title(" Maven Dependencies ").build())
+                            .build(),
+                    area);
+            return;
+        }
+
+        renderContent(frame, area, info);
+    }
+
+    @Override
+    protected void renderContent(Frame frame, Rect area, IntegrationInfo info) 
{
+        List<DepEntry> sorted = new ArrayList<>(filteredEntries);
+        sorted.sort(this::sortDep);
+
+        List<Row> rows = new ArrayList<>();
+        for (DepEntry entry : sorted) {
+            String artifact = entry.groupId() + ":" + entry.artifactId();
+            String ver = entry.version() != null ? entry.version() : "";
+            Style style = entry.transitive() ? Style.EMPTY.dim() : Style.EMPTY;
+            if (transitiveMode) {
+                String via = entry.parent() != null ? 
shortArtifact(entry.parent()) : "";
+                rows.add(Row.from(
+                        Cell.from(Span.styled(" " + artifact, style)),
+                        Cell.from(Span.styled(ver, style)),
+                        Cell.from(Span.styled(via, Style.EMPTY.dim()))));
+            } else {
+                rows.add(Row.from(
+                        Cell.from(Span.styled(" " + artifact, style)),
+                        Cell.from(Span.styled(ver, style))));
+            }
+        }
+
+        if (rows.isEmpty() && dataLoaded) {
+            rows.add(emptyRow("No Maven dependency entries found", 2));
+        }
+
+        String scope = SCOPES[scopeIndex];
+        int totalCount = transitiveMode ? combinedEntries().size() : 
allEntries.size();
+        boolean filtered = filterTerm != null || !"all".equals(scope);
+        StringBuilder title = new StringBuilder(" Maven Dependencies ");
+        if (transitiveMode) {
+            title.append("(+transitive) ");
+        }
+        title.append('[');
+        if (filtered) {
+            
title.append(filteredEntries.size()).append('/').append(totalCount);
+        } else {
+            title.append(filteredEntries.size());
+        }
+        title.append(']');
+        if (!"all".equals(scope)) {
+            title.append(" scope:").append(scope);
+        }
+        if (filterTerm != null) {
+            title.append(" filter:\"").append(filterTerm).append('"');
+        }
+        if (dataSource != null) {
+            title.append(" (").append(dataSource).append(')');
+        }
+        title.append(' ');
+
+        Table.Builder tableBuilder = Table.builder()
+                .rows(rows)
+                .highlightStyle(Theme.selectionBg())
+                
.block(Block.builder().borderType(BorderType.ROUNDED).borders(Borders.ALL)
+                        .title(title.toString()).build());
+
+        if (transitiveMode) {
+            tableBuilder
+                    .header(Row.from(
+                            Cell.from(Span.styled(" " + 
sortLabel("GROUP:ARTIFACT", "artifact"), sortStyle("artifact"))),
+                            Cell.from(Span.styled(sortLabel("VERSION", 
"version"), sortStyle("version"))),
+                            Cell.from(Span.styled("VIA", Style.EMPTY.bold()))))
+                    .widths(
+                            Constraint.fill(),
+                            Constraint.length(20),
+                            Constraint.length(30));
+        } else {
+            tableBuilder
+                    .header(Row.from(
+                            Cell.from(Span.styled(" " + 
sortLabel("GROUP:ARTIFACT", "artifact"), sortStyle("artifact"))),
+                            Cell.from(Span.styled(sortLabel("VERSION", 
"version"), sortStyle("version")))))
+                    .widths(
+                            Constraint.fill(),
+                            Constraint.length(20));
+        }
+
+        Table table = tableBuilder.build();
+
+        lastTableArea = area;
+        frame.renderStatefulWidget(table, area, tableState);
+        renderScrollbar(frame, sorted.size());
+    }
+
+    @Override
+    public void renderFooter(List<Span> spans) {
+        if (filterInputActive) {
+            spans.add(Span.styled(" /", Style.EMPTY.fg(Color.YELLOW).bold()));
+            spans.add(Span.raw(filterInputState.text() + "█  "));
+            hint(spans, "Enter", "filter");
+            hintLast(spans, "Esc", "cancel");
+            return;
+        }
+        hint(spans, "Esc", filterTerm != null ? "clear" : "back");
+        hint(spans, "s", "sort");
+        hint(spans, "f", "scope [" + SCOPES[scopeIndex] + "]");
+        if (transitiveLoading) {
+            hint(spans, "t", "resolving...");
+        } else {
+            hint(spans, "t", transitiveMode ? "direct" : "transitive");
+        }
+        if (filterTerm != null) {
+            spans.add(Span.styled("  /", Style.EMPTY.fg(Color.YELLOW).bold()));
+            spans.add(Span.raw("\"" + filterTerm + "\"  "));
+        } else {
+            hint(spans, "/", "filter");
+        }
+        hintLast(spans, TuiIcons.HINT_SCROLL, "navigate");
+    }
+
+    private int sortDep(DepEntry a, DepEntry b) {
+        int result = switch (sort) {
+            case "version" -> {
+                String va = a.version() != null ? a.version() : "";
+                String vb = b.version() != null ? b.version() : "";
+                yield va.compareToIgnoreCase(vb);
+            }
+            default -> { // "artifact"
+                yield a.display().compareToIgnoreCase(b.display());
+            }
+        };
+        return sortReversed ? -result : result;
+    }
+
+    private void loadDependencies() {
+        IntegrationInfo info = ctx.findSelectedIntegration();
+        if (info == null || ctx.runner == null) {
+            return;
+        }
+        if (!loading.compareAndSet(false, true)) {
+            return;
+        }
+
+        ctx.runner.scheduler().execute(() -> {
+            try {
+                List<Path> candidates = new ArrayList<>();
+                Path sourceDir = FilesBrowser.resolveSourceDirectory(info);
+                if (sourceDir != null) {
+                    candidates.add(sourceDir);
+                }
+                if (info.directory != null && !info.directory.isEmpty()) {
+                    Path infoDir = Path.of(info.directory);
+                    if (!candidates.contains(infoDir)) {
+                        candidates.add(infoDir);
+                    }
+                }
+                if (candidates.isEmpty()) {
+                    applyResult(Collections.emptyList(), null, "Cannot 
determine integration directory");
+                    return;
+                }
+
+                boolean jbangMode = "JBang".equals(info.platform) || 
"Camel".equals(info.platform);
+
+                if (jbangMode) {
+                    for (Path dir : candidates) {
+                        Path propsFile = 
dir.resolve(".camel-jbang").resolve("camel-jbang-run.properties");
+                        if (Files.exists(propsFile)) {
+                            List<DepEntry> deps = 
loadFromRunProperties(propsFile);
+                            applyResult(deps, "jbang", deps.isEmpty() ? "No 
dependencies in run properties" : null);
+                            return;
+                        }
+                    }
+                }
+
+                for (Path dir : candidates) {
+                    Path pomFile = dir.resolve("pom.xml");
+                    if (Files.exists(pomFile)) {
+                        List<DepEntry> deps = loadFromPomXml(pomFile);
+                        applyResult(deps, "pom.xml", deps.isEmpty() ? "No 
compile dependencies in pom.xml" : null);
+                        return;
+                    }
+                }
+
+                if (!jbangMode) {
+                    for (Path dir : candidates) {
+                        Path propsFile = 
dir.resolve(".camel-jbang").resolve("camel-jbang-run.properties");
+                        if (Files.exists(propsFile)) {
+                            List<DepEntry> deps = 
loadFromRunProperties(propsFile);
+                            applyResult(deps, "jbang", deps.isEmpty() ? "No 
dependencies in run properties" : null);
+                            return;
+                        }
+                    }
+                }
+
+                applyResult(Collections.emptyList(), null, "No dependency 
information found");
+            } catch (Exception e) {
+                applyResult(Collections.emptyList(), null, "Error: " + 
e.getMessage());
+            } finally {
+                loading.set(false);
+            }
+        });
+    }
+
+    private void resolveTransitives() {
+        if (allEntries.isEmpty() || ctx.runner == null) {
+            return;
+        }
+        transitiveLoading = true;
+        ctx.runner.scheduler().execute(() -> {
+            try (MavenDownloaderImpl downloader = new MavenDownloaderImpl()) {
+                downloader.build();
+
+                Set<String> directKeys = new HashSet<>();
+                for (DepEntry d : allEntries) {
+                    directKeys.add(d.groupId() + ":" + d.artifactId());
+                }
+
+                boolean hasSnapshot = allEntries.stream()
+                        .anyMatch(d -> d.version() != null && 
d.version().contains("SNAPSHOT"));
+
+                Map<String, DepEntry> transitiveMap = new HashMap<>();
+                for (DepEntry direct : allEntries) {
+                    if (direct.version() == null) {
+                        continue;
+                    }
+                    String gav = direct.groupId() + ":" + direct.artifactId() 
+ ":" + direct.version();
+                    String parentKey = direct.groupId() + ":" + 
direct.artifactId();
+                    try {
+                        List<MavenArtifact> resolved = 
downloader.resolveArtifacts(
+                                List.of(gav), Set.of(), true, hasSnapshot);
+                        for (MavenArtifact ma : resolved) {
+                            MavenGav g = ma.getGav();
+                            if (skipArtifact(g.getGroupId(), 
g.getArtifactId())) {
+                                continue;
+                            }
+                            String key = g.getGroupId() + ":" + 
g.getArtifactId();
+                            if (!directKeys.contains(key) && 
!transitiveMap.containsKey(key)) {
+                                transitiveMap.put(key, new DepEntry(
+                                        g.getGroupId(), g.getArtifactId(), 
g.getVersion(), true, parentKey));
+                            }
+                        }
+                    } catch (Exception e) {
+                        // skip this dependency
+                    }
+                }
+
+                List<DepEntry> entries = new 
ArrayList<>(transitiveMap.values());
+                entries.sort(Comparator.comparing(DepEntry::display, 
String.CASE_INSENSITIVE_ORDER));
+                applyTransitiveResult(entries);
+            } catch (Exception e) {
+                applyTransitiveResult(Collections.emptyList());
+            }
+        });
+    }
+
+    private void applyTransitiveResult(List<DepEntry> entries) {
+        if (ctx.runner == null) {
+            return;
+        }
+        ctx.runner.runOnRenderThread(() -> {
+            transitiveEntries = entries;
+            transitiveLoading = false;
+            transitiveLoaded = true;
+            transitiveMode = true;
+            refilter();
+        });
+    }
+
+    private List<DepEntry> loadFromPomXml(Path pomFile) {
+        try {
+            DocumentBuilderFactory dbf = 
XmlHelper.createDocumentBuilderFactory();
+            DocumentBuilder db = dbf.newDocumentBuilder();
+            Document dom;
+            try (InputStream is = Files.newInputStream(pomFile)) {
+                dom = db.parse(is);
+            }
+
+            Map<String, String> properties = new HashMap<>();
+            NodeList propsList = dom.getElementsByTagName("properties");
+            if (propsList.getLength() > 0) {
+                Element propsEl = (Element) propsList.item(0);
+                for (int i = 0; i < propsEl.getChildNodes().getLength(); i++) {
+                    if (propsEl.getChildNodes().item(i) instanceof Element 
prop) {
+                        properties.put(prop.getTagName(), 
prop.getTextContent().trim());
+                    }
+                }
+            }
+
+            NodeList nl = dom.getElementsByTagName("dependency");
+            List<DepEntry> deps = new ArrayList<>();
+            String camelVersion = null;
+            String springBootVersion = null;
+            String quarkusVersion = null;
+
+            for (int i = 0; i < nl.getLength(); i++) {
+                Element node = (Element) nl.item(i);
+
+                String p = node.getParentNode().getNodeName();
+                String p2 = node.getParentNode().getParentNode().getNodeName();
+                boolean accept = ("dependencyManagement".equals(p2) || 
"project".equals(p2))
+                        && "dependencies".equals(p);
+                if (!accept) {
+                    continue;
+                }
+
+                String g = 
node.getElementsByTagName("groupId").item(0).getTextContent();
+                String a = 
node.getElementsByTagName("artifactId").item(0).getTextContent();
+                String v = null;
+                NodeList vl = node.getElementsByTagName("version");
+                if (vl.getLength() > 0) {
+                    v = vl.item(0).getTextContent();
+                }
+
+                v = resolveProperty(v, properties);
+
+                if ("org.apache.camel".equals(g) && "camel-bom".equals(a)) {
+                    camelVersion = v;
+                    continue;
+                }
+                if ("org.apache.camel.springboot".equals(g) && 
"camel-spring-boot-bom".equals(a)) {
+                    camelVersion = v;
+                    continue;
+                }
+                if ("org.springframework.boot".equals(g) && 
"spring-boot-dependencies".equals(a)) {
+                    springBootVersion = v;
+                    continue;
+                }
+                if (("${quarkus.platform.group-id}".equals(g) || 
"io.quarkus.platform".equals(g))
+                        && ("${quarkus.platform.artifact-id}".equals(a) || 
"quarkus-bom".equals(a))) {
+                    if ("${quarkus.platform.version}".equals(v)) {
+                        NodeList qvl = 
dom.getElementsByTagName("quarkus.platform.version");
+                        if (qvl.getLength() > 0) {
+                            quarkusVersion = qvl.item(0).getTextContent();
+                        }
+                    } else {
+                        quarkusVersion = v;
+                    }
+                    continue;
+                }
+
+                String scope = null;
+                NodeList sl = node.getElementsByTagName("scope");
+                if (sl.getLength() > 0) {
+                    scope = sl.item(0).getTextContent();
+                }
+                if ("test".equals(scope) || "import".equals(scope)) {
+                    continue;
+                }
+
+                if (v == null && "org.apache.camel".equals(g)) {
+                    v = camelVersion;
+                }
+                if (v == null && "org.apache.camel.springboot".equals(g)) {
+                    v = camelVersion;
+                }
+                if (v == null && "org.springframework.boot".equals(g)) {
+                    v = springBootVersion;
+                }
+                if (v == null && ("io.quarkus".equals(g) || 
"org.apache.camel.quarkus".equals(g))) {
+                    v = quarkusVersion;
+                }
+
+                g = resolveProperty(g, properties);
+                a = resolveProperty(a, properties);
+                v = resolveProperty(v, properties);
+
+                if (skipArtifact(g, a)) {
+                    continue;
+                }
+
+                deps.add(new DepEntry(g, a, v));
+            }
+
+            deps.sort(Comparator.comparing(DepEntry::display, 
String.CASE_INSENSITIVE_ORDER));
+            return deps;
+        } catch (Exception e) {
+            return Collections.emptyList();
+        }
+    }
+
+    private List<DepEntry> loadFromRunProperties(Path propsFile) {
+        try {
+            List<String> lines = Files.readAllLines(propsFile);
+            List<DepEntry> deps = new ArrayList<>();
+
+            for (String line : lines) {
+                line = line.trim();
+                if (!line.startsWith("dependency=")) {
+                    continue;
+                }
+                String value = line.substring("dependency=".length()).trim();
+                value = value.replace("\\:", ":");
+
+                if (value.startsWith("mvn:") || value.startsWith("mvn\\:")) {
+                    String gav = value.startsWith("mvn:") ? value.substring(4) 
: value.substring(5);
+                    MavenGav parsed = MavenGav.parseGav(gav);
+                    if (parsed.getGroupId() != null && parsed.getArtifactId() 
!= null) {
+                        if (!skipArtifact(parsed.getGroupId(), 
parsed.getArtifactId())) {
+                            deps.add(new DepEntry(parsed.getGroupId(), 
parsed.getArtifactId(), parsed.getVersion()));
+                        }
+                    }
+                }
+            }
+
+            deps.sort(Comparator.comparing(DepEntry::display, 
String.CASE_INSENSITIVE_ORDER));
+            return deps;
+        } catch (Exception e) {
+            return Collections.emptyList();
+        }
+    }
+
+    private static String resolveProperty(String value, Map<String, String> 
properties) {
+        if (value != null && value.startsWith("${") && value.endsWith("}")) {
+            String key = value.substring(2, value.length() - 1);
+            String resolved = properties.get(key);
+            if (resolved != null) {
+                return resolved;
+            }
+        }
+        return value;
+    }
+
+    private static String shortArtifact(String ga) {
+        if (ga == null) {
+            return "";
+        }
+        int colon = ga.indexOf(':');
+        return colon >= 0 ? ga.substring(colon + 1) : ga;
+    }
+
+    private static boolean skipArtifact(String groupId, String artifactId) {
+        if ("org.fusesource.jansi".equals(groupId)) {
+            return true;
+        }
+        if ("org.apache.logging.log4j".equals(groupId)) {
+            return true;
+        }
+        if ("org.apache.camel".equals(groupId) && 
"camel-kamelet-main".equals(artifactId)) {
+            return true;
+        }
+        if ("org.apache.camel".equals(groupId) && 
"camel-cli-connector".equals(artifactId)) {
+            return true;
+        }
+        return false;
+    }
+
+    private void applyResult(List<DepEntry> parsed, String source, String 
error) {
+        if (ctx.runner == null) {
+            return;
+        }
+        ctx.runner.runOnRenderThread(() -> {
+            allEntries = parsed;
+            errorMessage = error;
+            dataSource = source;
+            dataLoaded = true;
+            refilter();
+        });
+    }
+
+    private void refilter() {
+        List<DepEntry> source = transitiveMode
+                ? combinedEntries()
+                : allEntries;
+        List<DepEntry> result = new ArrayList<>();
+        String ft = filterTerm != null ? filterTerm.toLowerCase() : null;
+        String scope = SCOPES[scopeIndex];
+        for (DepEntry entry : source) {
+            if ("camel".equals(scope) && !entry.isCamel()) {
+                continue;
+            }
+            if ("other".equals(scope) && entry.isCamel()) {
+                continue;
+            }
+            if (ft != null && !entry.display().toLowerCase().contains(ft)) {
+                continue;
+            }
+            result.add(entry);
+        }
+        filteredEntries = result;
+        if (!filteredEntries.isEmpty()) {
+            tableState.select(0);
+        }
+    }
+
+    private List<DepEntry> combinedEntries() {
+        Set<String> directKeys = new HashSet<>();
+        for (DepEntry d : allEntries) {
+            directKeys.add(d.groupId() + ":" + d.artifactId());
+        }
+        List<DepEntry> combined = new ArrayList<>(allEntries);
+        for (DepEntry t : transitiveEntries) {
+            if (!directKeys.contains(t.groupId() + ":" + t.artifactId())) {
+                combined.add(t);
+            }
+        }
+        combined.sort(Comparator.comparing(DepEntry::display, 
String.CASE_INSENSITIVE_ORDER));
+        return combined;
+    }
+
+    @Override
+    public boolean setFilter(String filter) {
+        filterTerm = filter != null && !filter.isEmpty() ? filter : null;
+        refilter();
+        return true;
+    }
+
+    @Override
+    public boolean setInputValue(String field, String value) {
+        if ("filter".equals(field)) {
+            return setFilter(value);
+        }
+        return false;
+    }
+
+    @Override
+    public SelectionContext getSelectionContext() {
+        if (filteredEntries.isEmpty()) {
+            return null;
+        }
+        List<String> items = 
filteredEntries.stream().map(DepEntry::display).toList();
+        Integer sel = tableState.selected();
+        return new SelectionContext("table", items, sel != null ? sel : -1, 
items.size(), "Maven Dependencies");
+    }
+
+    record DepEntry(String groupId, String artifactId, String version, boolean 
transitive, String parent) {
+
+        DepEntry(String groupId, String artifactId, String version) {
+            this(groupId, artifactId, version, false, null);
+        }
+
+        String display() {
+            if (version != null) {
+                return groupId + ":" + artifactId + ":" + version;
+            }
+            return groupId + ":" + artifactId;
+        }
+
+        boolean isCamel() {
+            return groupId != null && groupId.startsWith("org.apache.camel");
+        }
+    }
+
+    @Override
+    public String description() {
+        return "Maven dependency entries with filtering";
+    }
+
+    @Override
+    public String getHelpText() {
+        return """
+                # Maven Dependencies
+
+                The Maven Dependencies tab shows the declared dependencies for 
the
+                selected integration, as they would appear in a pom.xml file. 
Unlike
+                the Classpath tab (which shows all JARs on the JVM classpath 
including
+                internal infrastructure), this tab filters out internal 
bootstrap JARs
+                and shows only the dependencies the application actually 
declares.
+
+                ## Data Sources
+
+                The tab discovers dependencies from (in order of priority):
+
+                - **pom.xml** — For exported Maven projects (Spring Boot, 
Quarkus).
+                  Parses compile-scoped dependencies from the project's 
pom.xml.
+                - **.camel-jbang/camel-jbang-run.properties** — For Camel CLI 
(JBang)
+                  mode. Reads the `dependency=mvn:...` lines that list all 
declared
+                  dependencies.
+
+                The data source is shown in the title bar (e.g., "pom.xml" or 
"jbang").
+
+                ## Table Columns
+
+                - **GROUP:ARTIFACT** — Maven coordinate (e.g., 
`org.apache.camel:camel-core`)
+                - **VERSION** — The dependency version (e.g., `4.22.0`)
+
+                Each row shows the Maven coordinate and its version.
+
+                ## Sort
+
+                Press `s` to cycle sort column (artifact, version).
+                Press `S` to reverse sort order.
+
+                ## Scope
+
+                Press `f` to cycle the scope filter:
+
+                - **all** — show all dependencies (default)
+                - **camel** — show only Apache Camel dependencies
+                - **other** — show only non-Camel (third-party) dependencies
+
+                The active scope is shown in the footer and title bar.
+
+                ## Transitive Dependencies
+
+                Press `t` to resolve transitive dependencies on demand. The 
first
+                press triggers Maven resolution (shown as "resolving..." in the
+                footer). Once resolved, transitive dependencies appear dimmed 
in
+                the table with a **VIA** column showing which direct dependency
+                pulled them in. Subsequent presses toggle between showing all
+                dependencies (direct + transitive) and direct only.
+
+                The title shows "(+transitive)" when transitive mode is active.
+                This is useful for CVE auditing — when a transitive JAR has a
+                known vulnerability, the VIA column tells you which direct
+                dependency to upgrade or exclude.
+
+                ## Filter
+
+                Press `/` to open the filter input. Type a search term and 
press
+                `Enter` to filter by substring match. For example, type 
`kafka` to
+                find Kafka-related dependencies, or `spring` to find Spring
+                dependencies. The scope and text filter work together.
+
+                ## When To Use
+
+                - **CVE auditing**: Review only the real application 
dependencies, not
+                  internal infrastructure JARs that leak in via 
camel-kamelet-main
+                - **Dependency review**: Understand what your integration 
actually
+                  depends on
+                - **Version checking**: Verify specific dependency versions
+                - **Transitive analysis**: See the full dependency tree 
similar to
+                  `mvn dependency:tree` (flat list)
+
+                ## Keys
+
+                - `s` — cycle sort column
+                - `S` — reverse sort order
+                - `f` — cycle scope (all, camel, other)
+                - `t` — resolve and toggle transitive dependencies
+                - `/` — open filter
+                - `Esc` — clear filter or back
+                """;
+    }
+
+    @Override
+    public JsonObject getTableDataAsJson() {
+        List<DepEntry> entries = filteredEntries;
+        if (entries.isEmpty()) {
+            return null;
+        }
+        JsonObject result = new JsonObject();
+        result.put("tab", "Maven Dependencies");
+        JsonArray rows = new JsonArray();
+        for (DepEntry d : entries) {
+            JsonObject row = new JsonObject();
+            row.put("groupId", d.groupId());
+            row.put("artifactId", d.artifactId());
+            if (d.version() != null) {
+                row.put("version", d.version());
+            }
+            if (d.transitive()) {
+                row.put("transitive", true);
+                if (d.parent() != null) {
+                    row.put("parent", d.parent());
+                }
+            }
+            rows.add(row);
+        }
+        result.put("rows", rows);
+        result.put("totalRows", entries.size());
+        Integer sel = tableState.selected();
+        result.put("selectedIndex", sel != null ? sel : -1);
+        if (dataSource != null) {
+            result.put("dataSource", dataSource);
+        }
+        return result;
+    }
+}
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 84dc86fed2c1..fbcd5724e4ec 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
@@ -80,6 +80,7 @@ class TabRegistry {
     private BeansTab beansTab;
     private BrowseTab browseTab;
     private ClasspathTab classpathTab;
+    private MavenDependenciesTab mavenDependenciesTab;
     private CveAuditTab cveAuditTab;
     private InflightTab inflightTab;
     private MemoryTab memoryTab;
@@ -126,6 +127,7 @@ class TabRegistry {
         beansTab = new BeansTab(ctx);
         browseTab = new BrowseTab(ctx);
         classpathTab = new ClasspathTab(ctx);
+        mavenDependenciesTab = new MavenDependenciesTab(ctx);
         cveAuditTab = new CveAuditTab(ctx);
         inflightTab = new InflightTab(ctx);
         memoryTab = new MemoryTab(ctx, dataService.metrics());
@@ -151,9 +153,10 @@ class TabRegistry {
                 new MoreTab(TuiIcons.TAB_CONFIGURATION, "Configuration", 
"Confi&guration", configurationTab),
                 new MoreTab(TuiIcons.TAB_CONSUMERS, "Consumers", "Co&nsumers", 
consumersTab),
                 new MoreTab(TuiIcons.TAB_CVE_AUDIT, "CVE Audit", "C&VE Audit", 
cveAuditTab),
-                new MoreTab(TuiIcons.TAB_DATASOURCE, "DataSource", 
"&DataSource", dataSourceTab),
                 new MoreTab(TuiIcons.TAB_HEAP, "Heap Histogram", "&Heap 
Histogram", heapHistogramTab),
                 new MoreTab(TuiIcons.TAB_INFLIGHT, "Inflight", "&Inflight", 
inflightTab),
+                new MoreTab(TuiIcons.TAB_DATASOURCE, "JDBC DataSource", "&JDBC 
DataSource", dataSourceTab),
+                new MoreTab(TuiIcons.TAB_MAVEN_DEPENDENCIES, "Maven 
Dependencies", "Maven &Dependencies", mavenDependenciesTab),
                 new MoreTab(TuiIcons.TAB_MEMORY, "Memory", "&Memory", 
memoryTab),
                 new MoreTab(TuiIcons.TAB_MEMORY_LEAK, "Memory Leak", "Memory 
Lea&k", memoryLeakTab),
                 new MoreTab(TuiIcons.TAB_METRICS, "Metrics", "M&etrics", 
metricsTab),
@@ -262,6 +265,7 @@ class TabRegistry {
         cveAuditTab.onIntegrationChanged();
         dataSourceTab.onIntegrationChanged();
         heapHistogramTab.onIntegrationChanged();
+        mavenDependenciesTab.onIntegrationChanged();
         memoryLeakTab.onIntegrationChanged();
         sqlQueryTab.onIntegrationChanged();
         sqlTraceTab.onIntegrationChanged();
@@ -332,6 +336,10 @@ class TabRegistry {
         return classpathTab;
     }
 
+    MavenDependenciesTab mavenDependenciesTab() {
+        return mavenDependenciesTab;
+    }
+
     CveAuditTab cveAuditTab() {
         return cveAuditTab;
     }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiIcons.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiIcons.java
index 0425aea301f4..e46cda174ace 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiIcons.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiIcons.java
@@ -131,6 +131,7 @@ final class TuiIcons {
     static final String TAB_DATASOURCE = "💿";
     static final String TAB_HEAP = MEMORY;
     static final String TAB_INFLIGHT = RESET;
+    static final String TAB_MAVEN_DEPENDENCIES = "📜";
     static final String TAB_MEMORY = MEMORY;
     static final String TAB_MEMORY_LEAK = "💧";
     static final String TAB_METRICS = "📈";
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/TabRegistryTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/TabRegistryTest.java
index 8e5a0757db69..cbe2757d0c96 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/TabRegistryTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/TabRegistryTest.java
@@ -82,8 +82,8 @@ class TabRegistryTest {
     }
 
     @Test
-    void moreTabsHasNineteenEntries() {
-        assertEquals(19, registry.moreTabs().size());
+    void moreTabsHasTwentyEntries() {
+        assertEquals(20, registry.moreTabs().size());
     }
 
     @Test
@@ -109,7 +109,7 @@ class TabRegistryTest {
         // MORE_SHORTCUTS array carried before the MoreTab refactor. A label 
edit that repoints a key must fail here.
         List<Character> shortcuts = 
registry.moreTabs().stream().map(TabRegistry.MoreTab::shortcut).toList();
         assertEquals(
-                List.of('B', 'W', 'C', 'A', 'G', 'N', 'V', 'D', 'H', 'I', 'M', 
'K', 'E', 'Q', 'R', 'O', 'P', 'S', 'T'),
+                List.of('B', 'W', 'C', 'A', 'G', 'N', 'V', 'H', 'I', 'J', 'D', 
'M', 'K', 'E', 'Q', 'R', 'O', 'P', 'S', 'T'),
                 shortcuts, "More tab shortcut letters must match the 
historical sequence");
     }
 

Reply via email to