Skip to content

Conversation

@bennymagid
Copy link

@bennymagid bennymagid commented Jan 4, 2026

Description

Add draggable resize handle to tool list panel with min/max width
constraints, visual feedback, and localStorage persistence.

PR Checklist

Thank you for opening a Pull Request! Before submitting your PR, there are a
few things you can do to make sure it goes smoothly:

  • Make sure you reviewed
    CONTRIBUTING.md
  • Make sure to open an issue as a
    bug/issue
    before writing your code! That way we can discuss the change, evaluate
    designs, and agree on the general idea
  • Ensure the tests and linter pass
  • Code coverage does not decrease (if any source code was changed)
  • Appropriate docs were updated (if necessary)
  • Make sure to add ! if this involve a breaking change

🛠️ Fixes #1729

Add draggable resize handle to tool list panel with min/max width
constraints, visual feedback, and localStorage persistence.

Fixes googleapis#1729
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @bennymagid, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant user interface improvement by making the tool list panel dynamically resizable. Users can now adjust the width of this panel to their preference using a new draggable handle, with the chosen dimensions being saved locally for a consistent experience. This change enhances the flexibility and usability of the application's layout.

Highlights

  • Resizable Tool List Panel: The UI now features a resizable tool list panel, enhancing user customization and flexibility.
  • Draggable Resize Handle: A dedicated draggable handle has been added to the panel's edge, allowing for intuitive width adjustments.
  • Width Constraints and Persistence: The panel respects defined minimum and maximum width constraints, and the user's preferred size is automatically saved to localStorage for consistent experience across sessions.
  • Visual Feedback: The resize handle provides clear visual feedback (color change) when hovered over and actively being dragged.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a resizable tool list panel, a great usability improvement. The implementation correctly handles min/max width constraints and persists the user's preference using localStorage. My review focuses on improving the JavaScript event handling to prevent potential resource leaks and on minor code cleanup in both CSS and JavaScript for better maintainability. Overall, the changes are well-structured and effective.

Comment on lines 41 to 78
let isResizing = false;
let startX = 0;
let startWidth = 0;

resizeHandle.addEventListener('mousedown', (e) => {
isResizing = true;
startX = e.clientX;
startWidth = secondNav.offsetWidth;
resizeHandle.classList.add('active');
document.body.style.cursor = 'ew-resize';
document.body.style.userSelect = 'none';
e.preventDefault();
});

document.addEventListener('mousemove', (e) => {
if (!isResizing) {
return;
}

const deltaX = e.clientX - startX;
const newWidth = startWidth + deltaX;
const maxWidth = (window.innerWidth * MAX_WIDTH_PERCENT) / 100;

const clampedWidth = Math.max(MIN_WIDTH, Math.min(newWidth, maxWidth));
setPanelWidth(secondNav, clampedWidth);
});

document.addEventListener('mouseup', () => {
if (isResizing) {
isResizing = false;
resizeHandle.classList.remove('active');
document.body.style.cursor = '';
document.body.style.userSelect = '';

// Save width to localStorage
localStorage.setItem(STORAGE_KEY, secondNav.offsetWidth.toString());
}
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current implementation adds mousemove and mouseup event listeners to the global document object and never removes them. This can lead to unnecessary event processing and potential memory leaks over time. A more robust and efficient pattern is to add these listeners only during the drag operation (on mousedown) and remove them immediately after (on mouseup). This refactoring also simplifies the logic by eliminating the need for the isResizing flag.

    let startX = 0;
    let startWidth = 0;

    const onMouseMove = (e) => {
        const deltaX = e.clientX - startX;
        const newWidth = startWidth + deltaX;
        const maxWidth = (window.innerWidth * MAX_WIDTH_PERCENT) / 100;

        const clampedWidth = Math.max(MIN_WIDTH, Math.min(newWidth, maxWidth));
        setPanelWidth(secondNav, clampedWidth);
    };

    const onMouseUp = () => {
        document.removeEventListener('mousemove', onMouseMove);
        document.removeEventListener('mouseup', onMouseUp);

        resizeHandle.classList.remove('active');
        document.body.style.cursor = '';
        document.body.style.userSelect = '';

        // Save width to localStorage
        localStorage.setItem(STORAGE_KEY, secondNav.offsetWidth.toString());
    };

    resizeHandle.addEventListener('mousedown', (e) => {
        startX = e.clientX;
        startWidth = secondNav.offsetWidth;
        resizeHandle.classList.add('active');
        document.body.style.cursor = 'ew-resize';
        document.body.style.userSelect = 'none';
        e.preventDefault();

        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseup', onMouseUp);
    });

Comment on lines 110 to 116
.resize-handle:hover {
background-color: var(--toolbox-blue);
}

.resize-handle.active {
background-color: var(--toolbox-blue);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The styles for :hover and .active states of the resize handle are identical. To reduce code duplication and improve maintainability, you can group these selectors.

Suggested change
.resize-handle:hover {
background-color: var(--toolbox-blue);
}
.resize-handle.active {
background-color: var(--toolbox-blue);
}
.resize-handle:hover,
.resize-handle.active {
background-color: var(--toolbox-blue);
}

Comment on lines 95 to 98
function setPanelWidth(panel, width) {
panel.style.flex = `0 0 ${width}px`;
panel.style.width = `${width}px`;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When an element is a flex item, setting flex-basis (via the flex shorthand property) is sufficient to control its size along the main axis. The width property is redundant in this case because flex-basis will take precedence. You can simplify this function by removing the line that sets panel.style.width.

function setPanelWidth(panel, width) {
    panel.style.flex = `0 0 ${width}px`;
}

- Fix event listener memory leak by adding/removing listeners during drag
- Remove redundant width property from setPanelWidth
- Combine duplicate CSS selectors for hover and active states
@bennymagid bennymagid marked this pull request as ready for review January 4, 2026 01:57
@bennymagid bennymagid requested a review from a team as a code owner January 4, 2026 01:57
@bennymagid bennymagid marked this pull request as draft January 4, 2026 01:57
@bennymagid bennymagid marked this pull request as ready for review January 4, 2026 01:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Make Toolbox Web UI Tool List Panel Resizable

2 participants