Week 10: My first PR
Sorry for the late blog post, I didn’t realize we had one due (but I probably should have assumed we did).
My Progress
Last weekend, I submitted my PR for the issue I chose to work on. This was fun to work on, and definitely a bit challenging. The problem ended up being much bigger than what was initially reported, but it was still narrow in scope, which let me be really comprehensive within the file I was working on and get a deeper understanding of that part of the codebase.
The bug initially reported that there was an issue in filtering Category Groups when changing the operator from “is” to “contains”, where it would populate the input field with the UUID of the Category Group instead of the display name. After reproducing the issue myself, I realized it extended beyond Category Groups. It also affected “contains”, “matches”, and “does not contain” for Accounts, Categories, Category Groups, and Payees.
I first focused on fixing the issue in one direction: going from ID-based operators (like “is”) to text-based ones (like “contains”). This part was relatively straightforward since I could map the stored ID to its corresponding display label.
Then I had to handle the reverse direction, which was more challenging. Converting from a label back to an ID isn’t always clean, since a string might not uniquely map to a single entity. I added logic to only convert back when there was exactly one valid match, and otherwise avoid making a potentially incorrect assumption.
Another layer of complexity came from the fact that different operators expect different data shapes. Some operators store a single ID, while others (like “one of”) store arrays of IDs. So I had to define clear behavior when switching between them. For example, going from a multi-ID operator to a text-based one only works cleanly if there’s exactly one value, otherwise the input has to be cleared. Similarly, when going from text to a multi-ID operator, I resolve to a single ID (if possible) and then wrap it in an array. A lot of this PR ended up being about making consistent decisions like this so the system behaves predictably.
While working through this, I also realized that certain account-specific operators (like “is on budget” and “is off budget”) don’t actually use input values at all, which was throwing off the logic. I updated the behavior so that these operators preserve whatever value was previously there, but don’t attempt to render or transform it until switching back to a normal operator.
After implementing these changes, I submitted my PR and went through a round of CodeRabbit feedback. One of the main issues it flagged was that the data shape wasn’t always what the system expected, specifically around when values should be arrays versus single values. Based on that feedback, I tightened the logic to consistently normalize values depending on the operator type, which fixed the inconsistencies.
I also tested a lot of operator transitions across accounts, categories, category groups, and payees to make sure everything behaved correctly (like ID → text, text → ID, single → multi, multi → text, etc.), and to ensure that UUIDs never leak into the UI again.
Overall, this was a great first PR experience. It forced me to think carefully about bidirectional data transformations, data shape consistency, and edge cases in UI behavior. It also showed how a small bug can reveal deeper inconsistencies in how a system handles state.