Hacktoberfest continues with Wren AI
Taking it a step further and contributing to a larger project
Introduction
If you read my last blog, I talked about a project called ZTM Quest, where I submitted 3 PRs to fix one issue due to a lot of changes in the repo and some back-and-forth communication between me, the people testing the repo, and the contributors and maintainers.
I managed to get 3 out of 4 PRs merged, which was required to complete Hacktoberfest. However, my goal isn’t just to complete Hacktoberfest - I want to contribute to projects beyond that! So, expect to see more posts here.
This time, I contributed to a company’s project mostly because I wanted to gain more experience working with larger codebases and see what it’s like to work on a bigger company's project. While looking for good first issues to contribute to for Hacktoberfest, I came across Canner's Wren AI project and found an issue I could help with.
Wren AI is a SQL AI agent that helps data teams get results and insights faster by asking business questions without writing SQL. It's a full-stack application, but they had a bug in the frontend where the dropdown menu wouldn’t close when scrolling around the website. I asked them to assign the issue to me, and they were happy to do so.
I also joined their Discord community and said hi - I was warmly welcomed, which was awesome! The community aspect of open source is something I love the most.
Working on the issue
Introduction to the Issue
As mentioned earlier, I worked on fixing a bug that involved a dropdown menu not closing when scrolling around the website. The issue was logged under issue #713.
I was eager to tackle the issue, thinking it would be a straightforward fix—just a simple dropdown issue, right? Well, it turned out to be more complex than I expected. As I dug deeper, I discovered that the problem wasn’t due to incorrect code in the dropdown itself, but rather how ReactFlow, one of the dependencies, was handling mouse events.
Debugging the Issue
After testing, I noticed that the dropdown behaved differently based on where the user clicked. Clicking in certain areas of the page would close the dropdown, while clicking in others wouldn’t. The root cause became clear: ReactFlow’s handling of mouse events was preventing the dropdown from detecting clicks. Specifically, ReactFlow treated some mouse actions as attempts to drag the screen, and these actions weren’t triggering the dropdown to close.
I came across discussions related to this issue in other repositories. The maintainers of ReactFlow acknowledged the problem and released version 12 to fix this, introducing the paneClickDistance
property, which allowed better configuration of mouse events. You can read more about the migration to version 12 in their migration guide.
Proposed Solutions
After investigating, I proposed three possible solutions to fix the issue:
Upgrade ReactFlow to Version 12: This was the ideal solution, as ReactFlow version 12 introduced the
paneClickDistance
property, which allowed better control over click events and solved similar problems for other users. We could upgrade from version 11.10.3 to the latest version to take advantage of these fixes. This would involve making updates to the code to match the new API changes in ReactFlow.Use the
onPaneClick
Handler: Another approach was to implement theonPaneClick
event handler in ReactFlow to detect clicks on the pane and update the dropdown’s state to close it. This method had a potential downside of mixing concerns, as we’d be using the pane click event to control a dropdown.Switch to a Hover-Based Dropdown: Alternatively, we could modify the dropdown to work on hover instead of a click. This would bypass the issue entirely, but it wasn’t ideal from a user experience perspective.
The maintainers responded that option 1 would be ideal if the ReactFlow upgrade worked, but if it didn’t, option 2 was an acceptable fallback. So I decided to try upgrading ReactFlow first and submitted a pull request to address the issue.
Initial Attempts and Solution
I initially tried upgrading the ReactFlow library, following the migration guide. Unfortunately, the upgrade didn’t resolve the issue. After further research, I found that the underlying cause was how the d3 zoom library, which ReactFlow uses under the hood, handled pointer events. Disabling pointer events allowed me to detect clicks, but it also disabled drag functionality, which was crucial for our use case.
To work around this, I wrote a function that programmatically triggered a mousedown
event whenever a click occurred inside the ReactFlow component. This ensured the dropdown closed as expected without affecting essential functionality like dragging. Here’s what I implemented:
const dispatchMouseEvent = (event: React.MouseEvent | MouseEvent) => {
if (event.isTrusted) {
const mouseDownEvent = new MouseEvent('mousedown', {
bubbles: true,
cancelable: true,
clientX: event.clientX,
clientY: event.clientY,
button: 0,
});
document.dispatchEvent(mouseDownEvent);
}
};
This function triggered a mousedown
event every time it was called, and the frontend library we were using (Ant Design) automatically closed the dropdown when it detected a mousedown
event.
I triggered this function within the onPaneClick
and onPointerDown
events of ReactFlow:
<ReactFlow
nodes={nodes}
edges={edges}
onPaneClick={(event) => dispatchMouseEvent(event)}
onPointerDown={(event) => dispatchMouseEvent(event)}
...
/>
Final Fix and Review
After submitting this solution, the maintainer pointed out an issue: the dropdown menu didn’t function correctly if the mousedown
event was dispatched too early, before the event flow reached the dropdown element. This was a critical insight that I hadn’t tested thoroughly enough.
To address this, I added a condition to ensure the mousedown
event was only dispatched if the user clicked outside of the dropdown. Here’s the final fix:
const dispatchMouseEvent = (event: React.MouseEvent | MouseEvent) => {
const dropdowns = document.querySelectorAll('.ant-dropdown');
const isTargetDropdown = Array.from(dropdowns).some((dropdown) =>
dropdown.contains(event.target as Node),
);
if (isTargetDropdown) return;
const mouseDownEvent = new MouseEvent('mousedown', {
bubbles: true,
cancelable: true,
clientX: event.clientX,
clientY: event.clientY,
button: 0,
});
document.dispatchEvent(mouseDownEvent);
};
This ensured that the event was only dispatched when clicking outside the dropdown, preserving the drag functionality and ensuring the dropdown closed as expected.
After thoroughly testing the solution, I demonstrated the fix with a video, and the maintainer was satisfied with the result. My PR was merged, and the issue was finally closed. I also received some exclusive Wren AI swag for my contribution!
Conclusion and Takeaways
This experience was a lot more involved than my previous contributions, especially since this was a larger project. Communication took longer, with slower responses due to the size of the codebase and the detailed reviews from the maintainers.
It was an excellent learning experience, not just for debugging and coding but also for collaborating with others on a large-scale project. I learned a ton from the team’s feedback and from the process of refining my code to meet their standards. I’m really excited to continue contributing to projects like these and growing as a developer!
Here are the links to my issue and PR:
Issue Link: https://github.com/Canner/WrenAI/issues/713
P.S. I also received an email from Hacktoberfest letting me know that I've completed all the PRs required to finish! Now, I'm in the review period, eagerly waiting for my contributions to be verified.
See you in the next one! 👋