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 c41b6ba5d7f1 chore: Fix actions menu alignment for Switch Integration
item
c41b6ba5d7f1 is described below
commit c41b6ba5d7f100d5cbfbf2d4e6f9ddd758d56f23
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Jul 6 22:28:26 2026 +0200
chore: Fix actions menu alignment for Switch Integration item
chore: TUI polish - mouse support, popup alignment, emoji fixes
- Add mouse scroll wheel and click-to-select in SourceViewer and
FilesBrowser
- Route mouse events to FilesBrowser in CamelMonitor instead of dropping
them
- Add mouse scroll support in DocViewerPopup and Endpoints detail panel
- Align popup y-axis consistently across RunOptionsForm page 2,
FolderBrowser, FolderInputPopup
- Fix DEV_PROFILE emoji from narrow U+1F6E0 to wide U+1F528 to prevent
garbage chars
- Use wide SWITCH emoji for Switch Integration menu item alignment
- Show endpoint option values in bold instead of dimmed code formatting
chore: Add mouse support to Run from Folder browser
- Add mouse scroll and click-to-select in FolderBrowser
- Add handleMouseEvent to FolderInputPopup to delegate to FolderBrowser
- Wire mouse events from ActionsPopup to FolderInputPopup
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../dsl/jbang/core/commands/tui/ActionsPopup.java | 10 ++++++--
.../dsl/jbang/core/commands/tui/CamelMonitor.java | 2 +-
.../jbang/core/commands/tui/DocViewerPopup.java | 17 +++++++++++++
.../dsl/jbang/core/commands/tui/EndpointsTab.java | 16 +++++++++++-
.../dsl/jbang/core/commands/tui/FilesBrowser.java | 27 ++++++++++++++++++++
.../dsl/jbang/core/commands/tui/FolderBrowser.java | 29 +++++++++++++++++++++-
.../jbang/core/commands/tui/FolderInputPopup.java | 10 +++++++-
.../jbang/core/commands/tui/RunOptionsForm.java | 4 ++-
.../dsl/jbang/core/commands/tui/SourceViewer.java | 28 +++++++++++++++++++++
.../dsl/jbang/core/commands/tui/TuiIcons.java | 3 ++-
10 files changed, 138 insertions(+), 8 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 f1c64d419b77..7682441e0c14 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
@@ -649,6 +649,12 @@ class ActionsPopup {
return handleListPopupMouse(me, docViewerPopup.getPickerRect(),
docViewerPopup.getPickerState(),
docViewerPopup.getPickerIntegrations().size(), i -> false);
}
+ if (docViewerPopup.isVisible()) {
+ return docViewerPopup.handleMouseEvent(me);
+ }
+ if (folderInputPopup.isVisible()) {
+ return folderInputPopup.handleMouseEvent(me);
+ }
// Other sub-popups (forms, viewers) stay modal: consume the event
without acting on it.
return true;
}
@@ -824,8 +830,8 @@ class ActionsPopup {
// Group 0: Navigation
items.add(ListItem.from(TuiIcons.menuItem(TuiIcons.GO_TO, "Go
to...")));
items.add(canSwitch
- ? ListItem.from(TuiIcons.menuItem(TuiIcons.ARROW_BOTH, "Switch
Integration (F3)"))
- : ListItem.from(TuiIcons.menuItem(TuiIcons.ARROW_BOTH, "Switch
Integration (F3)")).style(Style.EMPTY.dim()));
+ ? ListItem.from(TuiIcons.menuItem(TuiIcons.SWITCH, "Switch
Integration (F3)"))
+ : ListItem.from(TuiIcons.menuItem(TuiIcons.SWITCH, "Switch
Integration (F3)")).style(Style.EMPTY.dim()));
items.add(ListItem.from(divider).style(Style.EMPTY.dim()));
// Group 1: User Actions
boolean hasSelection = ctx != null && ctx.selectedPid != null &&
!ctx.isInfraSelected();
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 72085c2b530f..6b49fd544b88 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
@@ -837,7 +837,7 @@ public class CamelMonitor extends CamelCommand {
return popupManager.handleMouseEvent(me,
tabRegistry.selectedTabIndex(), TAB_LOG);
}
if (filesBrowser.isVisible()) {
- return false;
+ return filesBrowser.handleMouseEvent(me);
}
MonitorTab activeTab = tabRegistry.activeTab();
if (activeTab != null && activeTab.handleMouseEvent(me,
lastContentArea)) {
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocViewerPopup.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocViewerPopup.java
index 3aaac13f7b6f..643428ef4c66 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocViewerPopup.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocViewerPopup.java
@@ -34,6 +34,8 @@ import dev.tamboui.text.Span;
import dev.tamboui.text.Text;
import dev.tamboui.tui.event.KeyCode;
import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.tui.event.MouseEvent;
+import dev.tamboui.tui.event.MouseEventKind;
import dev.tamboui.widgets.Clear;
import dev.tamboui.widgets.block.Block;
import dev.tamboui.widgets.block.BorderType;
@@ -175,6 +177,21 @@ class DocViewerPopup {
return false;
}
+ boolean handleMouseEvent(MouseEvent me) {
+ if (showViewer) {
+ if (me.kind() == MouseEventKind.SCROLL_UP) {
+ docScroll = Math.max(0, docScroll - 3);
+ return true;
+ }
+ if (me.kind() == MouseEventKind.SCROLL_DOWN) {
+ docScroll += 3;
+ return true;
+ }
+ return true;
+ }
+ return false;
+ }
+
void render(Frame frame, Rect area) {
if (showPicker) {
renderPicker(frame, area);
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 48faaea58ca1..53680458b40b 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
@@ -39,6 +39,7 @@ import dev.tamboui.text.Span;
import dev.tamboui.tui.event.KeyCode;
import dev.tamboui.tui.event.KeyEvent;
import dev.tamboui.tui.event.MouseEvent;
+import dev.tamboui.tui.event.MouseEventKind;
import dev.tamboui.widgets.block.Block;
import dev.tamboui.widgets.block.BorderType;
import dev.tamboui.widgets.block.Borders;
@@ -82,6 +83,7 @@ class EndpointsTab extends AbstractTableTab {
private int chartMode = CHART_ALL;
private int panelMode = PANEL_CHART;
private int detailScroll;
+ private Rect lastDetailArea;
private int chartPanelHeight = 16;
private final DragSplit vSplit = new DragSplit();
private int flowPanelWidth = 38;
@@ -141,6 +143,16 @@ class EndpointsTab extends AbstractTableTab {
@Override
public boolean handleMouseEvent(MouseEvent me, Rect area) {
+ if (panelMode == PANEL_DETAIL && lastDetailArea != null &&
lastDetailArea.contains(me.x(), me.y())) {
+ if (me.kind() == MouseEventKind.SCROLL_UP) {
+ detailScroll = Math.max(0, detailScroll - 3);
+ return true;
+ }
+ if (me.kind() == MouseEventKind.SCROLL_DOWN) {
+ detailScroll += 3;
+ return true;
+ }
+ }
if (vSplit.handleMouse(me, me.y())) {
if (vSplit.isDragging()) {
chartPanelHeight = Math.max(5, Math.min(area.y() +
area.height() - me.y(), area.height() - 5));
@@ -310,8 +322,10 @@ class EndpointsTab extends AbstractTableTab {
if (showPanel && panelMode == PANEL_DETAIL) {
hSplit.clearBorderPos();
+ lastDetailArea = chunks.get(1);
renderDetail(frame, chunks.get(1), sortedEndpoints, info);
} else if (showPanel) {
+ lastDetailArea = null;
// Determine selected endpoint URI for single-endpoint chart
String selectedUri = null;
if (chartMode == CHART_SINGLE) {
@@ -744,7 +758,7 @@ class EndpointsTab extends AbstractTableTab {
BaseOptionModel doc = optionDocs.get(optName);
md.append("---\n\n");
- md.append("**").append(optName).append("** =
`").append(optValue).append("`\n\n");
+ md.append("**").append(optName).append("** =
**").append(optValue).append("**\n\n");
if (doc != null) {
if (doc.getDescription() != null &&
!doc.getDescription().isEmpty()) {
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FilesBrowser.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FilesBrowser.java
index 4b442b1c84bd..2d19824247e5 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FilesBrowser.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FilesBrowser.java
@@ -32,6 +32,8 @@ import dev.tamboui.text.CharWidth;
import dev.tamboui.text.Line;
import dev.tamboui.text.Span;
import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.tui.event.MouseEvent;
+import dev.tamboui.tui.event.MouseEventKind;
import dev.tamboui.widgets.Clear;
import dev.tamboui.widgets.block.Block;
import dev.tamboui.widgets.block.BorderType;
@@ -54,6 +56,7 @@ class FilesBrowser {
private final ListState listState = new ListState();
private List<FileEntry> entries = Collections.emptyList();
private final SourceViewer sourceViewer = new SourceViewer();
+ private Rect lastPopup;
boolean isVisible() {
return visible;
@@ -132,6 +135,29 @@ class FilesBrowser {
return true;
}
+ boolean handleMouseEvent(MouseEvent me) {
+ if (sourceViewer.isVisible()) {
+ return sourceViewer.handleMouseEvent(me);
+ }
+ if (me.kind() == MouseEventKind.SCROLL_UP) {
+ listState.selectPrevious();
+ return true;
+ }
+ if (me.kind() == MouseEventKind.SCROLL_DOWN) {
+ listState.selectNext(entries.size());
+ return true;
+ }
+ if (me.isClick() && lastPopup != null && lastPopup.contains(me.x(),
me.y())) {
+ int innerTop = lastPopup.top() + 1;
+ int clicked = listState.offset() + (me.y() - innerTop);
+ if (clicked >= 0 && clicked < entries.size()) {
+ listState.select(clicked);
+ }
+ return true;
+ }
+ return true;
+ }
+
boolean handleKeyEvent(KeyEvent ke) {
if (sourceViewer.isVisible()) {
if (sourceViewer.handleKeyEvent(ke)) {
@@ -227,6 +253,7 @@ class FilesBrowser {
int y = area.top() + 2;
Rect popup = new Rect(x, y, Math.min(popupW, area.width()),
Math.min(popupH, area.height() - 2));
+ lastPopup = popup;
frame.renderWidget(Clear.INSTANCE, popup);
int innerWidth = popupW - 2;
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FolderBrowser.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FolderBrowser.java
index d3d279f2ba8c..b176c318de12 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FolderBrowser.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FolderBrowser.java
@@ -35,6 +35,8 @@ import dev.tamboui.text.Line;
import dev.tamboui.text.Span;
import dev.tamboui.tui.event.KeyCode;
import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.tui.event.MouseEvent;
+import dev.tamboui.tui.event.MouseEventKind;
import dev.tamboui.widgets.Clear;
import dev.tamboui.widgets.block.Block;
import dev.tamboui.widgets.block.BorderType;
@@ -59,6 +61,7 @@ class FolderBrowser {
private char lastJumpChar;
private int lastJumpIndex = -1;
private final SourceViewer sourceViewer = new SourceViewer();
+ private Rect lastPopup;
boolean isVisible() {
return visible;
@@ -153,6 +156,29 @@ class FolderBrowser {
}
}
+ boolean handleMouseEvent(MouseEvent me) {
+ if (sourceViewer.isVisible()) {
+ return sourceViewer.handleMouseEvent(me);
+ }
+ if (me.kind() == MouseEventKind.SCROLL_UP) {
+ listState.selectPrevious();
+ return true;
+ }
+ if (me.kind() == MouseEventKind.SCROLL_DOWN) {
+ listState.selectNext(entries.size());
+ return true;
+ }
+ if (me.isClick() && lastPopup != null && lastPopup.contains(me.x(),
me.y())) {
+ int innerTop = lastPopup.top() + 1;
+ int clicked = listState.offset() + (me.y() - innerTop);
+ if (clicked >= 0 && clicked < entries.size()) {
+ listState.select(clicked);
+ }
+ return true;
+ }
+ return true;
+ }
+
boolean handleKeyEvent(KeyEvent ke) {
if (sourceViewer.isVisible()) {
if (ke.isCancel()) {
@@ -306,9 +332,10 @@ class FolderBrowser {
int popupH = Math.min(area.height() - 4, Math.max(12, entries.size() +
2));
int x = area.left() + Math.max(0, (area.width() - popupW) / 2);
- int y = area.top() + 2;
+ int y = area.top() + Math.max(0, (area.height() - 17) / 4);
Rect popup = new Rect(x, y, Math.min(popupW, area.width()),
Math.min(popupH, area.height() - 2));
+ lastPopup = popup;
frame.renderWidget(Clear.INSTANCE, popup);
ListItem[] items = new ListItem[entries.size()];
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FolderInputPopup.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FolderInputPopup.java
index 86aa365f0a94..6cd85a92e040 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FolderInputPopup.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/FolderInputPopup.java
@@ -29,6 +29,7 @@ import dev.tamboui.text.Line;
import dev.tamboui.text.Span;
import dev.tamboui.tui.event.KeyCode;
import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.tui.event.MouseEvent;
import dev.tamboui.widgets.Clear;
import dev.tamboui.widgets.block.Block;
import dev.tamboui.widgets.block.BorderType;
@@ -126,6 +127,13 @@ class FolderInputPopup {
folderBrowser.close();
}
+ boolean handleMouseEvent(MouseEvent me) {
+ if (folderBrowser.isVisible()) {
+ return folderBrowser.handleMouseEvent(me);
+ }
+ return false;
+ }
+
boolean handleKeyEvent(KeyEvent ke) {
if (folderBrowser.isVisible()) {
folderBrowser.handleKeyEvent(ke);
@@ -290,7 +298,7 @@ class FolderInputPopup {
int popupW = Math.min(70, area.width() - 4);
int popupH = 4;
int x = area.left() + Math.max(0, (area.width() - popupW) / 2);
- int y = area.top() + 2;
+ int y = area.top() + Math.max(0, (area.height() - 17) / 4);
Rect popup = new Rect(x, y, Math.min(popupW, area.width()),
Math.min(popupH, area.height()));
frame.renderWidget(Clear.INSTANCE, popup);
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RunOptionsForm.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RunOptionsForm.java
index ec4fde3fa82d..17da115c8d89 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RunOptionsForm.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RunOptionsForm.java
@@ -608,7 +608,9 @@ class RunOptionsForm {
int propCount = properties != null ? properties.size() : 0;
int popupH = Math.min(propCount + 2, Math.min(20, area.height() - 4));
int x = area.left() + Math.max(0, (area.width() - popupW) / 2);
- int y = area.top() + Math.max(0, (area.height() - popupH) / 4);
+ // use same y-offset as page 1 (based on page 1's fixed height) so
both pages align
+ int page1H = 17;
+ int y = area.top() + Math.max(0, (area.height() - page1H) / 4);
Rect popup = new Rect(x, y, Math.min(popupW, area.width()),
Math.min(popupH, area.height()));
frame.renderWidget(Clear.INSTANCE, popup);
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
index 3e3cb1e35ec4..c2d85af40a2b 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
@@ -37,6 +37,8 @@ import dev.tamboui.text.Span;
import dev.tamboui.text.Text;
import dev.tamboui.tui.event.KeyCode;
import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.tui.event.MouseEvent;
+import dev.tamboui.tui.event.MouseEventKind;
import dev.tamboui.widgets.block.Block;
import dev.tamboui.widgets.block.BorderType;
import dev.tamboui.widgets.block.Borders;
@@ -81,6 +83,7 @@ class SourceViewer {
private String currentRouteId;
private MonitorContext currentCtx;
private String currentPid;
+ private Rect lastInnerArea;
private record CachedSource(
List<String> lines, List<JsonObject> codeData,
@@ -214,6 +217,30 @@ class SourceViewer {
return true;
}
+ boolean handleMouseEvent(MouseEvent me) {
+ if (!visible) {
+ return false;
+ }
+ if (me.kind() == MouseEventKind.SCROLL_UP) {
+ selectedLine = Math.max(0, selectedLine - 3);
+ return true;
+ }
+ if (me.kind() == MouseEventKind.SCROLL_DOWN) {
+ if (!lines.isEmpty()) {
+ selectedLine = Math.min(lines.size() - 1, selectedLine + 3);
+ }
+ return true;
+ }
+ if (me.isClick() && lastInnerArea != null &&
lastInnerArea.contains(me.x(), me.y())) {
+ int clickedLine = scrollY + (me.y() - lastInnerArea.top());
+ if (clickedLine >= 0 && clickedLine < lines.size()) {
+ selectedLine = clickedLine;
+ }
+ return true;
+ }
+ return true;
+ }
+
boolean isSearchInputActive() {
return search.isSearchInputActive();
}
@@ -228,6 +255,7 @@ class SourceViewer {
.title(buildTitle())
.build();
Rect inner = block.inner(area);
+ lastInnerArea = inner;
frame.renderWidget(block, area);
if (lines.isEmpty()) {
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 e46cda174ace..9d524eef2624 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
@@ -30,7 +30,7 @@ final class TuiIcons {
static final String CAMEL = "🐪";
static final String SPRING_BOOT = "🍃";
static final String QUARKUS = "🚀";
- static final String DEV_PROFILE = "🛠";
+ static final String DEV_PROFILE = "🔨";
static final String PROD_PROFILE = "📦";
static final String INFRA = "🔧";
@@ -81,6 +81,7 @@ final class TuiIcons {
static final String MEMORY = "💾";
// ---- Misc UI ----
+ static final String SWITCH = "🔃";
static final String KEY = "🔑";
static final String TIP = "💡";
static final String COMPUTER = "💻";