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