feat: sender filter for message search with from:@user autocomplete
Type 'from:@name' in the search box to filter by sender — a dropdown of matching users (avatar + display name + full ID) appears as you type and selecting one converts it into a removable sender chip in the filter bar. Multiple senders supported. Also works via manual entry on submit. - SearchInput: detects trailing 'from:@...' pattern on every keystroke, shows PopOut autocomplete from mx.getUsers(), onMouseDown prevents input blur when selecting, cleans up fragment after selection - SearchFilters: selectedSenders/onSelectedSendersChange props, sender chips rendered with user icon and X to remove - useLocalMessageSearch: filters cached events by sender set when senders param is provided (encrypted room search respects the filter too) - MessageSearch: handleSenderAdd deduplicates and writes to ?senders= URL param; localResult now passes senders to the local search Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -214,9 +214,19 @@ export function MessageSearch({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const localResult = useMemo(() => {
|
||||
if (!msgSearchParams.term) return null;
|
||||
return searchLocalMessages(localSearchRooms, msgSearchParams.term);
|
||||
return searchLocalMessages({
|
||||
term: msgSearchParams.term,
|
||||
roomIds: localSearchRooms,
|
||||
senders: msgSearchParams.senders,
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchLocalMessages, localSearchRooms, msgSearchParams.term, cacheVersion]);
|
||||
}, [
|
||||
searchLocalMessages,
|
||||
localSearchRooms,
|
||||
msgSearchParams.term,
|
||||
msgSearchParams.senders,
|
||||
cacheVersion,
|
||||
]);
|
||||
|
||||
const { status, data, error, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({
|
||||
enabled: !!msgSearchParams.term,
|
||||
@@ -297,6 +307,29 @@ export function MessageSearch({
|
||||
});
|
||||
};
|
||||
|
||||
const handleSelectedSendersChange = useCallback(
|
||||
(newSenders?: string[]) => {
|
||||
setSearchParams((prevParams) => {
|
||||
const p = new URLSearchParams(prevParams);
|
||||
p.delete('senders');
|
||||
if (newSenders && newSenders.length > 0) {
|
||||
p.append('senders', encodeSearchParamValueArray(newSenders));
|
||||
}
|
||||
return p;
|
||||
});
|
||||
},
|
||||
[setSearchParams],
|
||||
);
|
||||
|
||||
const handleSenderAdd = useCallback(
|
||||
(userId: string) => {
|
||||
const current = searchParamsSenders ?? [];
|
||||
if (current.includes(userId)) return;
|
||||
handleSelectedSendersChange([...current, userId]);
|
||||
},
|
||||
[searchParamsSenders, handleSelectedSendersChange],
|
||||
);
|
||||
|
||||
const lastVItem = vItems[vItems.length - 1];
|
||||
const lastVItemIndex: number | undefined = lastVItem?.index;
|
||||
const lastGroupIndex = groups.length - 1;
|
||||
@@ -332,6 +365,7 @@ export function MessageSearch({
|
||||
searchInputRef={searchInputRef}
|
||||
onSearch={handleSearch}
|
||||
onReset={handleSearchClear}
|
||||
onSenderAdd={handleSenderAdd}
|
||||
/>
|
||||
<SearchFilters
|
||||
defaultRoomsFilterName={defaultRoomsFilterName}
|
||||
@@ -343,6 +377,8 @@ export function MessageSearch({
|
||||
onGlobalChange={handleGlobalChange}
|
||||
order={msgSearchParams.order}
|
||||
onOrderChange={handleOrderChange}
|
||||
selectedSenders={searchParamsSenders}
|
||||
onSelectedSendersChange={handleSelectedSendersChange}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user