Block List Search Functionality #211#435
Conversation
…and UI updates - Implemented `runWithConcurrencyAndRetry` for async tasks with retry logic on 429 errors. - Added `fetchIsBlocking` and `fetchIsBlockedBy` functions for checking block status. - Enhanced `BlockPanelGeneric` to support searching for blocked accounts. - Updated CSS for search panel visibility. - Updated search functionality in `SearchAutoComplete` with filtering options. - Modified 'Blocked By' Panel and 'Blocking' Panel to pass `userHandle` and `isBlockingPanel` props.
…o feature/list-search-211
|
@rumanstheddy is attempting to deploy a commit to the Clearsky Team on Vercel. A member of the Team first needs to authorize it. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@rumanstheddy working this now. |
|
@rumanstheddy List search bar isn't working correctly. |
|
@thieflord06 Are the results not showing up? |
|
When I click on the search icon the bar to type doesn't show up. |
|
Could you please send a photo/video of what you see when you click the button? Screen.Recording.2026-02-04.174751.mp4 |
|
@rumanstheddy I'm on chrome. It seems that the deploy is messed up somehow. This is your latest deploy: |
|
@thieflord06 yeah, even the home page looks messed up.
|
|
@rumanstheddy can you push it again with a comment or something to see if that fixes it? I tried redeploying and it didn't fix it. |
|
@thieflord06 Sure. Just pushed a change. |
There was a problem hiding this comment.
Pull request overview
This PR adds search functionality to the block lists (Blocking and Blocked By panels) in the Clearsky application. Users can now search for specific accounts within their block lists to quickly verify block relationships.
Changes:
- Added customizable label prop and async filtering support to the SearchAutoComplete component
- Implemented new API endpoints (
fetchIsBlocking,fetchIsBlockedBy, and batch variants) with caching and retry logic for 429 errors - Integrated search UI into block panels with feature flag gating (
blocking-searching)
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| src/landing/search-autocomplete/search-autocomplete.jsx | Added filterOptionsAsync and label props to enable custom filtering and labels for the search component |
| src/detail-panels/blocking/index.jsx | Passed userHandle and isBlockingPanel props to enable search filtering in the blocking panel |
| src/detail-panels/blocked-by/index.jsx | Passed userHandle and isBlockingPanel props to enable search filtering in the blocked-by panel |
| src/detail-panels/block-panel-generic/block-panel-generic.jsx | Added search UI with toggle button, integrated SearchAutoComplete component, and implemented filtering logic |
| src/detail-panels/block-panel-generic/block-panel-generic.css | Added styles for search button, search container, and adjusted layout to accommodate search UI |
| src/api/blocklist.js | Implemented new API functions for checking block relationships with caching, concurrency control, and retry logic |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Attach cache keys to entries | ||
| const entriesWithCacheKey = entries.map((entry) => ({ | ||
| ...entry, | ||
| _cacheKey: `${handle}:blockedby:${entry.shortHandle}`, |
There was a problem hiding this comment.
The cache key uses a simple string concatenation pattern (e.g., 'handle:blocking:otherHandle'). If handles contain colons, this could lead to cache key collisions. While unlikely for valid Bluesky handles, consider using a more robust key generation approach such as JSON.stringify or a dedicated cache key builder function to prevent potential collisions.
| _cacheKey: `${handle}:blockedby:${entry.shortHandle}`, | |
| _cacheKey: JSON.stringify(['blockedby', handle, entry.shortHandle]), |
| '/' + | ||
| unwrapShortHandle(account.shortHandle) + | ||
| '/history/?q=' + | ||
| account.postID |
There was a problem hiding this comment.
The navigation URL construction for postID uses query parameter concatenation without proper encoding. If account.postID contains special characters, the URL could be malformed. Consider using URLSearchParams or encodeURIComponent to properly encode the postID value.
| account.postID | |
| encodeURIComponent(account.postID) |
| export async function fetchIsBlocking(handle1, handle2) { | ||
| const url = `blocklist-search-blocking/${unwrapShortHandle( | ||
| handle1 | ||
| )}/${unwrapShortHandle(handle2)}`; | ||
| const res = await fetchClearskyApi('v1', url); | ||
| return res?.data ?? null; | ||
| } |
There was a problem hiding this comment.
The fetchIsBlocking and fetchIsBlockedBy functions return null when the API response data is undefined, but the calling code in fetchIsBlockingMany/fetchIsBlockedByMany checks for valid data structure (lines 269-273, 299-304). If the API returns a successful response with an unexpected structure, it will be treated as undefined and filtered out. This is safe, but consider adding validation or logging to help identify API contract changes.
| // userHandle, | ||
| // isBlockingPanel, |
There was a problem hiding this comment.
These commented-out destructured props (userHandle, isBlockingPanel) are not used anywhere in the PanelHeader component. They were likely part of an earlier implementation where these values were passed directly to PanelHeader, but the final implementation passes filterOptionsAsync instead. These should be removed to avoid confusion.
| // userHandle, | |
| // isBlockingPanel, |
| * onAccountSelected?: (account: Partial<AccountInfo & SearchMatch>) => void, | ||
| * onResolveAccount?: (text: string) => Promise<AccountInfo[]> | ||
| * onResolveAccount?: (text: string) => Promise<AccountInfo[]>, | ||
| * filterOptionsAsync?: (entry: any) => Promise<boolean>, |
There was a problem hiding this comment.
The type annotation for filterOptionsAsync indicates it should return Promise, but the implementation in block-panel-generic.jsx returns Promise, and the code at lines 197-199 expects an array. This is a type mismatch that could lead to confusion. The type annotation should be changed to reflect that this function receives an array and returns a filtered array: (entries: any[]) => Promise<any[]>.
| * filterOptionsAsync?: (entry: any) => Promise<boolean>, | |
| * filterOptionsAsync?: (entries: any[]) => Promise<any[]>, |
| import { TableChart, TableRows } from '@mui/icons-material'; | ||
| import SearchIcon from '@mui/icons-material/Search'; | ||
| import { Button, CircularProgress } from '@mui/material'; | ||
| import { Box, Button, CircularProgress, IconButton } from '@mui/material'; |
There was a problem hiding this comment.
The Box import from '@mui/material' is added but never used in the component code. This unused import should be removed to keep the code clean.
| import { Box, Button, CircularProgress, IconButton } from '@mui/material'; | |
| import { Button, CircularProgress, IconButton } from '@mui/material'; |
| * onResolveAccount?: (text: string) => Promise<AccountInfo[]> | ||
| * onResolveAccount?: (text: string) => Promise<AccountInfo[]>, | ||
| * filterOptionsAsync?: (entry: any) => Promise<boolean>, | ||
| * label?: {en : string, localised: { [lang: string]: string }}, |
There was a problem hiding this comment.
There's inconsistent spacing in the JSDoc type definition. The line has 'en : string' with a space before the colon, while the standard TypeScript/JavaScript convention is to have no space before the colon. This should be 'en: string' for consistency with coding standards.
| * label?: {en : string, localised: { [lang: string]: string }}, | |
| * label?: {en: string, localised: { [lang: string]: string }}, |
| // const { accountFullHandle } = useAuth(); | ||
|
|
There was a problem hiding this comment.
This commented-out code appears to be from an earlier implementation that was abandoned in favor of passing userHandle as a prop. Since it's not being used and there's no clear reason to keep it for future reference, it should be removed to keep the codebase clean.
| // const { accountFullHandle } = useAuth(); |
| text-align: right; | ||
| } | ||
|
|
||
| .MuiBox-root .css-r82bso { |
There was a problem hiding this comment.
The CSS selector '.MuiBox-root .css-r82bso' targets a Material-UI auto-generated class name, which is not stable across versions or builds. These hashed class names can change with Material-UI version updates or configuration changes, causing the style to stop working. Consider using a custom class name on the component or a more stable selector approach instead.
| .MuiBox-root .css-r82bso { | |
| .MuiBox-root > :first-child { |
| // Simple in-memory cache for endpoint results | ||
| const _blocklistCache = new Map(); |
There was a problem hiding this comment.
The in-memory cache uses a Map without any size limits or TTL (time-to-live). This can lead to unbounded memory growth over time as users search for many different accounts. Consider implementing cache eviction strategies such as LRU (Least Recently Used) or setting a maximum cache size, or adding a TTL to expire old entries.
|
@thieflord06 did it help? |
|
@rumanstheddy No change. |
|
@thieflord06 is it fixed? |
|
@rumanstheddy When I run locally the home page looks normal. |

No description provided.