Skip to content

Conversation

@ZedLi
Copy link
Collaborator

@ZedLi ZedLi commented Nov 4, 2025

Description

One of the changes that was made in #2981 was not retrieving all resources for the dropdown filters. This had an unintended consequence when displaying the selected filters as it's possible for the selected filter to not be in the list of allFilters.

There's two main scenarios this happens (the prerequisite is having more filter options than we display which is 250):

  1. When filtering down the dropdown filters which means it might not be in the allFilters options. This was fixed by keeping track of all the searched options to be able to display.
  2. A user uses a query string or bookmarked a URL and goes to it directly. If the option isn't in the initial load, we won't have the actual option. In this case, I changed it to at least just display the ID instead of not showing up at all. Otherwise I'd have to load these selected options separately from the initial load which doesn't seem worth for this edge case.

Screenshots (if appropriate)

Before:

Screen.Recording.2025-11-04.at.2.23.52.PM.mov

After:

Screen.Recording.2025-11-04.at.2.25.09.PM.mov

How to Test

Use this cluster. Try applying different searches for the target dropdown and confirm that the filter tags always appear.

Checklist

  • I have added before and after screenshots for UI changes
  • [ ] I have added JSON response output for API changes
  • I have added steps to reproduce and test for bug fixes in the description
  • I have commented on my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • [ ] I have added a11y-tests label to run a11y audit tests if needed

PCI review checklist

  • I have documented a clear reason for, and description of, the change I am making.
  • If applicable, I've documented a plan to revert these changes if they require more than reverting the pull request.
  • If applicable, I've documented the impact of any changes to security controls.
    Examples of changes to security controls include using new access control methods, adding or removing logging pipelines, etc.

@ZedLi ZedLi self-assigned this Nov 4, 2025
@ZedLi ZedLi requested a review from a team as a code owner November 4, 2025 20:13
@vercel
Copy link

vercel bot commented Nov 4, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
boundary-ui Ready Ready Preview Comment Nov 6, 2025 11:34pm
boundary-ui-desktop Ready Ready Preview Comment Nov 6, 2025 11:34pm

hashicc
hashicc previously approved these changes Nov 5, 2025
Copy link
Collaborator

@hashicc hashicc left a comment

Choose a reason for hiding this comment

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

It looks good, I have one partial suggestion and one comment for discussion, but nothing blocking. Thanks for looking back over the recent changes for this edge case.

name: item.name,
type: key,
}));
return uniqueSelectedFilters.filter(Boolean).map((item) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure how much this would change things in reality, but does it make sense to start with iterating on selectedFilters (as uniqueSelectedFilters) as the top-level loop instead of starting from allFilters? This would prevent valueMap being created if a filter doesn't exist in selectedFilters- which could be fixed with an early return but it seems like get filters() is focused on returning a mapped selectedFilters + augmented name which it needs from a lookup on allFilters.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think I get what you're saying but I think it would be same either way? The loop on allFilters would still be the same if it was on selectedFilters since the initial loop is over each filter type, and not the actual filters.
i.e. it's the same regardless of which one I iterate over:

allFilters: {
  users: [],
  targets: [],
  status: [],
},
selectedFilters: {
  users: [],
  targets: [],
  status: [],
},

The real loop is on uniqueSelectedFilters. The map was only an (debatable if needed) optimization so I could do an O(1) lookup on getting the filter names, it seems like the choice of using it would be the same either way regardless of which one I do the initial loop on.

Let me know if I misunderstood what you meant

Copy link
Collaborator

Choose a reason for hiding this comment

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

If a key of uniqueSelectedFilters has an empty array, does the map based on allFilters need to get set up at all? That makes sense that it doesn't really matter as long as allFilters and selectedFilters have the same set of keys which it looks like in reality they do

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah good point, it doesn't need need the map if it's empty. I added the early return to handle that

@tracked search;
@tracked options = [];
@tracked _options = [];
#allOptions = new Map();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm wondering if the interface should be: selectedOptions and options? I'm struggling with the idea that "all" is never really "all" in large filter sets, as the set could be constantly changing as 250 results get loaded based on different search terms and then options ends up just being a cache of any previously seen option... At least that's my understanding from reading the code. Or maybe allOptions needs a nice comment of what "all" means

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So it's actually kind of tough, these are also not the selectedOptions, since that's being tracked by the query params separately which I would find even more confusing if it was called selectedOptions. I think a comment might be better here because you're right, it's not "all" but it's just keeping track of any previously loaded/seen options from the dropdown.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That makes sense, I think some sort of hint would help

Copy link
Collaborator

@priya-patel04 priya-patel04 left a comment

Choose a reason for hiding this comment

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

Tested and works as expected. Thanks for the fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants