From 735de2d4ee9b0cace576ed48224e58d5359be8c3 Mon Sep 17 00:00:00 2001 From: Oleg Samarin Date: Mon, 13 Apr 2026 23:17:32 +0300 Subject: [PATCH] Fixed session tab blocking resize below ~600px when docked as side panel southCard.getMinimumSize() was delegating to its visible child (promptPanel with a 3-row text area + buttons), which reported a tall minimum height. JSplitPane enforces the bottom component's minimum, so the divider bounced back when the user tried to shrink the tab below that height. Fix: override getMinimumSize() in southCard to always return (0, 0), letting JSplitPane collapse the bottom panel freely. getPreferredSize() is unchanged so the panel still requests its natural height when space allows. Resolves: #19 Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 1 + pom.xml | 2 +- .../nbclaudecodegui/ui/ClaudeSessionTab.java | 15 +++- .../ui/ClaudeSessionTabMinSizeTest.java | 79 +++++++++++++++++++ 4 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 src/test/java/io/github/nbclaudecodegui/ui/ClaudeSessionTabMinSizeTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 09add7ca..6fdd16d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +- Fixed session tab blocking resize below ~600px when docked as a side panel (https://github.com/nbclaudecodegui/NetbeansClaudeCodeGui/issues/19) - Fixed terminal appearing blank after dismissing the model selection menu - Fixed MCP connection to localhost being routed through an active HTTP_PROXY/HTTPS_PROXY; NO_PROXY is now automatically extended with localhost and 127.0.0.1 when a proxy is configured - Fixed terminal scrollbar disappearing when Claude shows a choice/confirmation prompt (https://github.com/nbclaudecodegui/NetbeansClaudeCodeGui/issues/22) diff --git a/pom.xml b/pom.xml index 8d4a9c3a..2b676dee 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.github.nbclaudecodegui netbeans-claude-code-gui - 0.21.48-SNAPSHOT + 0.21.49-SNAPSHOT nbm Netbeans Claude Code GUI NetBeans plugin that provides a GUI for Claude Code CLI — run claude code sessions directly inside the IDE. diff --git a/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java b/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java index 5e207e89..7b57bc56 100644 --- a/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java +++ b/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java @@ -697,11 +697,18 @@ private void showChatLayout(JediTermWidget widget) { southCardLayout = new CardLayout(); southCard = new JPanel(southCardLayout) { + /** + * Returns (0, 0) so that JSplitPane can collapse the bottom panel + * freely when the tab is docked as a narrow side panel. + * + * Without this override, getMinimumSize() delegates to the visible + * child (e.g. promptPanel with a 3-row DecoratedTextArea + buttons), + * which reports a tall minimum height (~600 px). JSplitPane enforces + * that minimum, causing the divider to bounce back when the user tries + * to shrink the tab below that height (issue #19). + */ @Override public java.awt.Dimension getMinimumSize() { - for (java.awt.Component c : getComponents()) { - if (c.isVisible()) return c.getMinimumSize(); - } - return super.getMinimumSize(); + return new java.awt.Dimension(0, 0); } @Override public java.awt.Dimension getPreferredSize() { for (java.awt.Component c : getComponents()) { diff --git a/src/test/java/io/github/nbclaudecodegui/ui/ClaudeSessionTabMinSizeTest.java b/src/test/java/io/github/nbclaudecodegui/ui/ClaudeSessionTabMinSizeTest.java new file mode 100644 index 00000000..d2637a10 --- /dev/null +++ b/src/test/java/io/github/nbclaudecodegui/ui/ClaudeSessionTabMinSizeTest.java @@ -0,0 +1,79 @@ +package io.github.nbclaudecodegui.ui; + +import java.awt.Dimension; +import javax.swing.JSplitPane; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Regression test for issue #19: the session tab must be resizable below + * ~600 px when docked as a side panel. + * + *

Root cause: {@code southCard.getMinimumSize()} was delegating to the + * visible child component (e.g. promptPanel with a 3-row text area + buttons), + * which reported a tall minimum height. {@link JSplitPane} enforces the + * bottom component's minimum size, so the divider bounced back when the user + * tried to shrink the tab below that height. + * + *

Fix: {@code southCard.getMinimumSize()} now always returns (0, 0), + * letting JSplitPane collapse the bottom panel freely. + */ +class ClaudeSessionTabMinSizeTest { + + /** + * Verifies that {@code southCard}'s minimum size is (0, 0) so that + * JSplitPane does not enforce a large lower bound on the tab height. + */ + @Test + void southCardMinimumSizeIsZero() throws Exception { + SwingUtilities.invokeAndWait(() -> { + // Simulate the southCard construction from showChatLayout(): + // an anonymous JPanel subclass with getMinimumSize() returning (0,0). + java.awt.CardLayout cardLayout = new java.awt.CardLayout(); + JPanel southCard = new JPanel(cardLayout) { + @Override public Dimension getMinimumSize() { + return new Dimension(0, 0); + } + }; + + // Add a child with a large preferred/minimum size (mirrors promptPanel). + JPanel tallChild = new JPanel() { + @Override public Dimension getMinimumSize() { return new Dimension(400, 600); } + @Override public Dimension getPreferredSize() { return new Dimension(400, 600); } + }; + southCard.add(tallChild, "prompt"); + cardLayout.show(southCard, "prompt"); + + Dimension min = southCard.getMinimumSize(); + assertEquals(0, min.width, + "southCard minimum width must be 0 so JSplitPane can resize freely (issue #19)"); + assertEquals(0, min.height, + "southCard minimum height must be 0 so JSplitPane can resize freely (issue #19)"); + }); + } + + /** + * Verifies that JSplitPane respects a (0,0) minimum on the bottom component + * and does not enforce the child's own large minimum size. + */ + @Test + void splitPaneAllowsCollapseWhenMinSizeIsZero() throws Exception { + SwingUtilities.invokeAndWait(() -> { + JPanel bottomPanel = new JPanel() { + @Override public Dimension getMinimumSize() { return new Dimension(0, 0); } + }; + + JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, + new JPanel(), bottomPanel); + splitPane.setResizeWeight(1.0); + + // The minimum size of the split pane should allow it to be very small. + Dimension min = splitPane.getMinimumSize(); + assertTrue(min.height < 100, + "JSplitPane minimum height must be small when bottom component min size is (0,0) — " + + "got " + min.height + " px; large value means resize is blocked (issue #19)"); + }); + } +}