-
Notifications
You must be signed in to change notification settings - Fork 30
feat: Add search filter to sidebar #562
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds a search functionality to the "All workspaces" sidebar, allowing users to filter workspaces using fuzzy search. The implementation includes search buttons in the UI and smart search logic that prioritizes exact word matches over substring matches.
- Added search/filter functionality with clear and refresh buttons to the All Workspaces view
- Implemented fuzzy search that matches workspace name, owner, template, status, and agent metadata
- Added VS Code commands and UI integration for the search feature
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
File | Description |
---|---|
src/workspacesProvider.ts | Core search functionality with filter management and smart matching logic |
src/extension.ts | Command registration for search operations |
src/commands.ts | Search UI implementation using VS Code QuickPick |
package.json | Command definitions and menu integration for search buttons |
- Pre-compile regex patterns to avoid repeated compilation - Cache stringified metadata to reduce JSON serialization overhead - Extract input field processing into reusable helper method - Add input validation to prevent performance issues from long search terms - Add comprehensive error handling for edge cases and malformed data
- Add 150ms debounce delay to prevent excessive search operations - Implement immediate clear functionality without debouncing - Add proper cleanup for debounce timers to prevent memory leaks - Improve search responsiveness, especially for users with many workspaces
// Validate search term length to prevent performance issues | ||
if (filter.length > 200) { | ||
filter = filter.substring(0, 200); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what performance issue? why 200 characters?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, i'd like to note:
- each word in the search term gets compiled into a regex pattern even though we are moving to a word boundary search, we are then testing each word against every workspace
- we also run string operations .toLowerCase(), .split(), and multiple .includes() checks on concatenated text
- We're storing all of these regex patterns in memory
The 200 char limit was just an arbitrary number to limit the length of the search input
We could do the following -
const searchWords = searchTerm.split(/\s+/).filter(word => word.length > 0);
if (searchWords.length > 10) {
// Limit to first 10 words
}
Let me know how we should proceed or what you suggest
// Handle JSON serialization errors gracefully | ||
this.storage.output.warn( | ||
`Failed to serialize metadata for agent ${agent.id}: ${error}`, | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but now the metadata still gets cached even with a missing entry, right? this seems like a cache corruption bug
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed this - de2dd41. We now only cache the data if all metadata is serialized successfully
src/workspacesProvider.ts
Outdated
// Fall back to simple substring matching for this word | ||
continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
continue
at the end of a loop doesn't really do anything
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed - de2dd41
src/workspacesProvider.ts
Outdated
regexPatterns.length > 0 && | ||
regexPatterns.some((pattern) => { | ||
try { | ||
return pattern.test(allText); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does test
ever throw an error? it's only documented as returning a boolean
on MDN and I can't even get it to throw a TypeError
; it just coerces the value to bool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes you are correct here is my understanding of what it does -
Converts the argument to a string using ToString()
Returns true if the regex matches, false otherwise
Never throws an error - even with invalid inputs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it you're right it never throws an error. That was just a bit of over engineering here. Will be removing this in next commit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed - de2dd41
quickPick.value = currentFilter; | ||
} | ||
|
||
quickPick.ignoreFocusOut = true; // Keep open when clicking elsewhere |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems like an odd thing to set. can you explain your rationale?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, here was my thought process on user behavior -
When a user clicks outside the Quickpick (like on the workspace list or elsewhere in VS Code), the quickpick automatically closes
- They type "docker", see the filtered results, but accidentally click outside -> Quickpick closes
- User clicks on a workspace to see details, but that closes the search input
- User has to reopen the search every time they want to redefine their search
With the current approach it solves the above scenarios. The context is still preserved in state (private searchFilter) so the filtered results will not change if the input closes - its more so just a means for the user to not have to click on the search button again if they are not satisfied or have not completed their search
{ | ||
"command": "coder.refreshWorkspaces", | ||
"when": "coder.authenticated && coder.isOwner && view == allWorkspaces", | ||
"group": "navigation" | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
feels a little weird to put this in the middle
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where do you suggest we move it to? or should we remove it entirely?
src/workspacesProvider.ts
Outdated
const escapedWord = word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); | ||
regexPatterns.push(new RegExp(`\\b${escapedWord}\\b`, "i")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's a bit odd to me to try escaping these symbols instead of interpreting them as word boundaries
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're totally right! I was trying to solve: when searching "container", it should show Docker workspaces (since Docker is related to containers). So I wanted fuzzy matching rather than strict exact word matching. The regex approach gives us that flexibility - users can search for "container" and it'll match "Docker" workspaces. I can change this to interpret word boundaries.
Co-authored-by: ケイラ <mckayla@hey.com>
…ntion, update search filter logic to regex word boundaries
See - #330
Features added:
Before search
After search term typed