From 7fa5ee9fc6567d8e8b4f3fa6ad5f92dc8228b9c3 Mon Sep 17 00:00:00 2001 From: Ajay Bura <32841439+ajbura@users.noreply.github.com> Date: Tue, 25 Aug 2026 14:45:03 +0530 Subject: [PATCH] move search messages to new sdk --- src/app/components/RenderMessageContent.tsx | 2 +- .../features/message-search/MessageSearch.tsx | 57 ++- .../features/message-search/SearchFilters.tsx | 90 ++-- .../message-search/SearchResultGroup.tsx | 469 ++++++++---------- .../message-search/useMessageSearch.ts | 70 +-- src/app/hooks/useMessageParserOptions.ts | 5 +- src/app/pages/Router.tsx | 4 +- src/app/pages/client/space/Search.tsx | 16 +- 8 files changed, 364 insertions(+), 349 deletions(-) diff --git a/src/app/components/RenderMessageContent.tsx b/src/app/components/RenderMessageContent.tsx index 3e93b213..c9ab38d2 100644 --- a/src/app/components/RenderMessageContent.tsx +++ b/src/app/components/RenderMessageContent.tsx @@ -55,7 +55,7 @@ export function RenderMessageContent({ } if (eventType !== MessageEvent.RoomMessage) { - return ; + return ; } const renderCaption = () => { diff --git a/src/app/features/message-search/MessageSearch.tsx b/src/app/features/message-search/MessageSearch.tsx index 3bcf1eed..161c0d20 100644 --- a/src/app/features/message-search/MessageSearch.tsx +++ b/src/app/features/message-search/MessageSearch.tsx @@ -4,9 +4,8 @@ import { useAtomValue } from 'jotai'; import { useVirtualizer } from '@tanstack/react-virtual'; import { useInfiniteQuery } from '@tanstack/react-query'; import { useSearchParams } from 'react-router-dom'; -import { SearchOrderBy } from 'matrix-js-sdk'; +import { SearchEventOrder } from 'neurone/lib/api/types'; import { PageHero, PageHeroEmpty, PageHeroSection } from '../../components/page'; -import { useMatrixClient } from '../../hooks/useMatrixClient'; import { _SearchPathSearchParams } from '../../pages/paths'; import { useSettings } from '../../state/hooks/settings'; import { SequenceCard } from '../../components/sequence-card'; @@ -18,10 +17,15 @@ import { useRooms } from '../../state/hooks/roomList'; import { allRoomsAtom } from '../../state/room-list/roomList'; import { mDirectAtom } from '../../state/mDirectList'; import { MessageSearchParams, useMessageSearch } from './useMessageSearch'; -import { SearchResultGroup } from './SearchResultGroup'; +import { SearchGroupMessages, SearchResultGroup } from './SearchResultGroup'; import { SearchInput } from './SearchInput'; import { SearchFilters } from './SearchFilters'; import { VirtualTile } from '../../components/virtualizer'; +import { useClient } from '../../hooks/useClient'; +import { useObservableValue } from '../../hooks/useObservableValue'; +import { useRoomHeroes } from '../../hooks/storage/useRoomHeros'; +import { useGetRoomName } from '../../hooks/storage/useGetRoomName'; +import { useGetRoomAvatar } from '../../hooks/storage/useGetRoomAvatar'; const useSearchPathSearchParams = (searchParams: URLSearchParams): _SearchPathSearchParams => useMemo( @@ -49,9 +53,9 @@ export function MessageSearch({ senders, scrollRef, }: MessageSearchProps) { - const mx = useMatrixClient(); + const ct = useClient(); const mDirects = useAtomValue(mDirectAtom); - const allRooms = useRooms(mx, allRoomsAtom, mDirects); + const allRooms = useRooms(ct, allRoomsAtom, mDirects); const { mediaAutoLoad, urlPreview, legacyUsernameColor, hour24Clock, dateFormatString } = useSettings(); @@ -81,9 +85,11 @@ export function MessageSearch({ const isGlobal = searchPathSearchParams.global === 'true'; const defaultRooms = isGlobal ? undefined : rooms; + const { order } = searchPathSearchParams; + return { term: searchPathSearchParams.term, - order: searchPathSearchParams.order ?? SearchOrderBy.Recent, + order: order && order === 'rank' ? 'rank' : 'recent', rooms: searchParamRooms ?? defaultRooms, senders: searchParamsSenders ?? senders, }; @@ -159,7 +165,7 @@ export function MessageSearch({ }); }; - const handleOrderChange = (order?: string) => { + const handleOrderChange = (order?: SearchEventOrder) => { setSearchParams((prevParams) => { const newParams = new URLSearchParams(prevParams); newParams.delete('order'); @@ -184,6 +190,13 @@ export function MessageSearch({ } }, [lastVItemIndex, lastGroupIndex, fetchNextPage, isFetchingNextPage, hasNextPage]); + const roomToTimeline = useObservableValue(ct.roomToTimeline); + const [getRoomHeroes, roomToHeroMembersResult] = useRoomHeroes( + searchPathSearchParams.global === 'true' ? allRooms : rooms + ); + const getRoomName = useGetRoomName(getRoomHeroes, roomToHeroMembersResult.value); + const getRoomAvatar = useGetRoomAvatar(getRoomHeroes, roomToHeroMembersResult.value); + return ( @@ -216,6 +229,7 @@ export function MessageSearch({ onGlobalChange={handleGlobalChange} order={msgSearchParams.order} onOrderChange={handleOrderChange} + getRoomName={getRoomName} /> @@ -269,8 +283,6 @@ export function MessageSearch({ {vItems.map((vItem) => { const group = groups[vItem.index]; if (!group) return null; - const groupRoom = mx.getRoom(group.roomId); - if (!groupRoom) return null; return ( + getRoomName={getRoomName} + getRoomAvatar={getRoomAvatar} + > + + ); })} diff --git a/src/app/features/message-search/SearchFilters.tsx b/src/app/features/message-search/SearchFilters.tsx index 6883e363..3618f170 100644 --- a/src/app/features/message-search/SearchFilters.tsx +++ b/src/app/features/message-search/SearchFilters.tsx @@ -25,11 +25,9 @@ import { Badge, RectCords, } from 'folds'; -import { SearchOrderBy } from 'matrix-js-sdk'; import FocusTrap from 'focus-trap-react'; import { useVirtualizer } from '@tanstack/react-virtual'; -import { useMatrixClient } from '../../hooks/useMatrixClient'; -import { getRoomIconSrc } from '../../utils/room'; +import { SearchEventOrder } from 'neurone/lib/api/types'; import { factoryRoomIdByAtoZ } from '../../utils/sort'; import { SearchItemStrGetter, @@ -39,16 +37,19 @@ import { import { DebounceOptions, useDebounce } from '../../hooks/useDebounce'; import { VirtualTile } from '../../components/virtualizer'; import { stopPropagation } from '../../utils/keyboard'; +import { GetRoomNameCallback } from '../../hooks/storage/useGetRoomName'; +import { useClient } from '../../hooks/useClient'; +import { RoomIcon } from '../../components/room-avatar'; type OrderButtonProps = { - order?: string; - onChange: (order?: string) => void; + order?: SearchEventOrder; + onChange: (order?: SearchEventOrder) => void; }; function OrderButton({ order, onChange }: OrderButtonProps) { const [menuAnchor, setMenuAnchor] = useState(); - const rankOrder = order === SearchOrderBy.Rank; + const rankOrder = order === 'rank'; - const setOrder = (o?: string) => { + const setOrder = (o?: SearchEventOrder) => { setMenuAnchor(undefined); onChange(o); }; @@ -86,7 +87,7 @@ function OrderButton({ order, onChange }: OrderButtonProps) { Recent setOrder(SearchOrderBy.Rank)} + onClick={() => setOrder('rank')} variant="Surface" size="300" radii="300" @@ -125,16 +126,22 @@ type SelectRoomButtonProps = { roomList: string[]; selectedRooms?: string[]; onChange: (rooms?: string[]) => void; + getRoomName: GetRoomNameCallback; }; -function SelectRoomButton({ roomList, selectedRooms, onChange }: SelectRoomButtonProps) { - const mx = useMatrixClient(); +function SelectRoomButton({ + roomList, + selectedRooms, + onChange, + getRoomName, +}: SelectRoomButtonProps) { + const ct = useClient(); const scrollRef = useRef(null); const [menuAnchor, setMenuAnchor] = useState(); const [localSelected, setLocalSelected] = useState(selectedRooms); const getRoomNameStr: SearchItemStrGetter = useCallback( - (rId) => mx.getRoom(rId)?.name ?? rId, - [mx] + (rId) => getRoomName(rId) ?? 'Unknown', + [getRoomName] ); const [searchResult, _searchRoom, resetSearch] = useAsyncSearch( @@ -142,7 +149,7 @@ function SelectRoomButton({ roomList, selectedRooms, onChange }: SelectRoomButto getRoomNameStr, SEARCH_OPTS ); - const rooms = Array.from(searchResult?.items ?? roomList).sort(factoryRoomIdByAtoZ(mx)); + const rooms = Array.from(searchResult?.items ?? roomList).sort(factoryRoomIdByAtoZ(getRoomName)); const virtualizer = useVirtualizer({ count: rooms.length, @@ -253,8 +260,6 @@ function SelectRoomButton({ roomList, selectedRooms, onChange }: SelectRoomButto > {vItems.map((vItem) => { const roomId = rooms[vItem.index]; - const room = mx.getRoom(roomId); - if (!room) return null; const selected = localSelected?.includes(roomId); return ( @@ -272,14 +277,16 @@ function SelectRoomButton({ roomList, selectedRooms, onChange }: SelectRoomButto radii="300" aria-pressed={selected} before={ - } > - {room.name} + {getRoomName(roomId) ?? 'Unknown'} @@ -333,8 +340,9 @@ type SearchFiltersProps = { onSelectedRoomsChange: (selectedRooms?: string[]) => void; global?: boolean; onGlobalChange: (global?: boolean) => void; - order?: string; - onOrderChange: (order?: string) => void; + order?: SearchEventOrder; + onOrderChange: (order?: SearchEventOrder) => void; + getRoomName: GetRoomNameCallback; }; export function SearchFilters({ defaultRoomsFilterName, @@ -346,8 +354,9 @@ export function SearchFilters({ order, onGlobalChange, onOrderChange, + getRoomName, }: SearchFiltersProps) { - const mx = useMatrixClient(); + const ct = useClient(); return ( @@ -379,29 +388,30 @@ export function SearchFilters({ variant="Surface" size="300" /> - {selectedRooms?.map((roomId) => { - const room = mx.getRoom(roomId); - if (!room) return null; - - return ( - onSelectedRoomsChange(selectedRooms.filter((rId) => rId !== roomId))} - radii="Pill" - before={ - - } - after={} - > - {room.name} - - ); - })} + {selectedRooms?.map((roomId) => ( + onSelectedRoomsChange(selectedRooms.filter((rId) => rId !== roomId))} + radii="Pill" + before={ + + } + after={} + > + {getRoomName(roomId)} + + ))} diff --git a/src/app/features/message-search/SearchResultGroup.tsx b/src/app/features/message-search/SearchResultGroup.tsx index 14817cc4..025627bd 100644 --- a/src/app/features/message-search/SearchResultGroup.tsx +++ b/src/app/features/message-search/SearchResultGroup.tsx @@ -1,46 +1,34 @@ /* eslint-disable react/destructuring-assignment */ -import React, { MouseEventHandler, useMemo } from 'react'; -import { IEventWithRoomId, JoinRule, RelationType, Room } from 'matrix-js-sdk'; -import { HTMLReactParserOptions } from 'html-react-parser'; +import React, { MouseEventHandler, ReactNode, useMemo } from 'react'; import { Avatar, Box, Chip, Header, Icon, Icons, Text, config } from 'folds'; -import { Opts as LinkifyOpts } from 'linkifyjs'; -import { useMatrixClient } from '../../hooks/useMatrixClient'; -import { - factoryRenderLinkifyWithMention, - getReactCustomHtmlParser, - LINKIFY_OPTS, - makeHighlightRegex, - makeMentionCustomProps, - renderMatrixMention, -} from '../../plugins/react-custom-html-parser'; -import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix'; -import { useMatrixEventRenderer } from '../../hooks/useMatrixEventRenderer'; -import { GetContentCallback, MessageEvent, StateEvent } from '../../../types/matrix/room'; +import { makeHighlightRegex } from '../../plugins/react-custom-html-parser'; import { AvatarBase, - ImageContent, - MSticker, ModernLayout, RedactedContent, - Reply, Time, Username, UsernameBold, } from '../../components/message'; import { RenderMessageContent } from '../../components/RenderMessageContent'; -import { Image } from '../../components/media'; -import { ImageViewer } from '../../components/image-viewer'; -import * as customHtmlCss from '../../styles/CustomHtml.css'; import { RoomAvatar, RoomIcon } from '../../components/room-avatar'; -import { getMemberAvatarMxc, getMemberDisplayName, getRoomAvatarUrl } from '../../utils/room'; +import { getLatestEditEvent } from '../../utils/room'; import { ResultItem } from './useMessageSearch'; import { SequenceCard } from '../../components/sequence-card'; import { UserAvatar } from '../../components/user-avatar'; -import { useMentionClickHandler } from '../../hooks/useMentionClickHandler'; -import { useSpoilerClickHandler } from '../../hooks/useSpoilerClickHandler'; import { useMediaAuthentication } from '../../hooks/useMediaAuthentication'; -import { usePowerLevels } from '../../hooks/usePowerLevels'; -import { usePowerLevelTags } from '../../hooks/usePowerLevelTags'; +import { + PowerLevelsContextProvider, + usePowerLevels, + usePowerLevelsContext, + usePowerLevelsState, +} from '../../hooks/usePowerLevels'; +import { + PowerLevelTagsContextProvider, + usePowerLevelTags, + usePowerLevelTagsContext, + usePowerLevelTagsState, +} from '../../hooks/usePowerLevelTags'; import { useTheme } from '../../hooks/useTheme'; import { PowerIcon } from '../../components/power'; import colorMXID from '../../../util/colorMXID'; @@ -51,279 +39,256 @@ import { } from '../../hooks/useMemberPowerTag'; import { useRoomCreators } from '../../hooks/useRoomCreators'; import { useRoomCreatorsTag } from '../../hooks/useRoomCreatorsTag'; +import { mxcToHttp } from '../../../client/mxcToHttp'; +import { + RoomMembersAPIProvider, + useRoomMembers, + useRoomMembersAPI, +} from '../../hooks/useRoomMembers'; +import { useClient } from '../../hooks/useClient'; +import { GetRoomNameCallback } from '../../hooks/storage/useGetRoomName'; +import { GetRoomAvatarCallback } from '../../hooks/storage/useGetRoomAvatar'; +import { Timeline } from '../../../client/room'; +import { useObservableValueOptionally } from '../../hooks/useObservableValue'; +import { useMessageParserOptions } from '../../hooks/useMessageParserOptions'; +import { MessageContent } from '../../components/MessageContent'; +import { rContent } from '../../../client/reader'; -type SearchResultGroupProps = { - room: Room; - highlights: string[]; +type SearchGroupMessagesProps = { + roomId: string; + timeline?: Timeline; items: ResultItem[]; + highlights: string[]; mediaAutoLoad?: boolean; urlPreview?: boolean; - onOpen: (roomId: string, eventId: string) => void; legacyUsernameColor?: boolean; hour24Clock: boolean; dateFormatString: string; + getRoomName: GetRoomNameCallback; + onOpen: (roomId: string, eventId: string) => void; }; -export function SearchResultGroup({ - room, - highlights, +export function SearchGroupMessages({ + roomId, + timeline, items, + highlights, mediaAutoLoad, urlPreview, - onOpen, legacyUsernameColor, hour24Clock, dateFormatString, -}: SearchResultGroupProps) { - const mx = useMatrixClient(); + getRoomName, + onOpen, +}: SearchGroupMessagesProps) { + const ct = useClient(); + const membersAPI = useRoomMembersAPI(); const useAuthentication = useMediaAuthentication(); const highlightRegex = useMemo(() => makeHighlightRegex(highlights), [highlights]); - const powerLevels = usePowerLevels(room); - const creators = useRoomCreators(room); + const redacted = useObservableValueOptionally(timeline?.relations.redacted); + const edits = useObservableValueOptionally(timeline?.relations.edits.eventToRelations); + const creators = useRoomCreators(roomId); + const powerLevels = usePowerLevelsContext(); + const getMemberPowerTag = useGetMemberPowerTag(creators, powerLevels); const creatorsTag = useRoomCreatorsTag(); - const powerLevelTags = usePowerLevelTags(room, powerLevels); - const getMemberPowerTag = useGetMemberPowerTag(room, creators, powerLevels); + const powerLevelTags = usePowerLevelTagsContext(); const theme = useTheme(); const accessibleTagColors = useAccessiblePowerTagColors(theme.kind, creatorsTag, powerLevelTags); - const mentionClickHandler = useMentionClickHandler(room.roomId); - const spoilerClickHandler = useSpoilerClickHandler(); - - const linkifyOpts = useMemo( - () => ({ - ...LINKIFY_OPTS, - render: factoryRenderLinkifyWithMention((href) => - renderMatrixMention(mx, room.roomId, href, makeMentionCustomProps(mentionClickHandler)) - ), - }), - [mx, room, mentionClickHandler] - ); - const htmlReactParserOptions = useMemo( - () => - getReactCustomHtmlParser(mx, room.roomId, { - linkifyOpts, - highlightRegex, - useAuthentication, - handleSpoilerClick: spoilerClickHandler, - handleMentionClick: mentionClickHandler, - }), - [ - mx, - room, - linkifyOpts, - highlightRegex, - mentionClickHandler, - spoilerClickHandler, - useAuthentication, - ] - ); - - const renderMatrixEvent = useMatrixEventRenderer<[IEventWithRoomId, string, GetContentCallback]>( - { - [MessageEvent.RoomMessage]: (event, displayName, getContent) => { - if (event.unsigned?.redacted_because) { - return ; - } - - return ( - - ); - }, - [MessageEvent.Reaction]: (event, displayName, getContent) => { - if (event.unsigned?.redacted_because) { - return ; - } - return ( - ( - } - renderViewer={(p) => } - /> - )} - /> - ); - }, - [StateEvent.RoomTombstone]: (event) => { - const { content } = event; - return ( - - - Room Tombstone. {content.body} - - - ); - }, - }, - undefined, - (event) => { - if (event.unsigned?.redacted_because) { - return ; - } - return ( - - - {event.type} - {' event'} - - - ); - } + const { linkifyOpts, htmlReactParserOptions } = useMessageParserOptions( + roomId, + getRoomName, + membersAPI.getName, + highlightRegex ); const handleOpenClick: MouseEventHandler = (evt) => { const eventId = evt.currentTarget.getAttribute('data-event-id'); if (!eventId) return; - onOpen(room.roomId, eventId); + onOpen(roomId, eventId); }; + return ( + + {items.map((item) => { + const { event } = item; + + const displayName = membersAPI.getName(event.sender); + + const senderAvatarMxc = membersAPI.getAvatar(event.sender); + + const memberPowerTag = getMemberPowerTag(event.sender); + const tagColor = memberPowerTag?.color + ? accessibleTagColors?.get(memberPowerTag.color) + : undefined; + const tagIconSrc = memberPowerTag?.icon + ? getPowerTagIconSrc(ct, useAuthentication, memberPowerTag.icon) + : undefined; + + const usernameColor = legacyUsernameColor ? colorMXID(event.sender) : tagColor; + + const editEvents = edits?.get(event.event_id); + const editedEvent = editEvents && getLatestEditEvent(event.sender, editEvents, redacted); + + return ( + + + + } + /> + + + } + > + + + + + + {displayName} + + + {tagIconSrc && } + + + + + Open + + + + {redacted?.has(event.event_id) ? ( + + ) : ( + + {(contentEvent) => ( + + )} + + )} + + + ); + })} + + ); +} + +type SearchResultGroupProps = { + roomId: string; + items: ResultItem[]; + getRoomName: GetRoomNameCallback; + getRoomAvatar: GetRoomAvatarCallback; + children: ReactNode; +}; +export function SearchResultGroup({ + roomId, + items, + getRoomName, + getRoomAvatar, + children, +}: SearchResultGroupProps) { + const ct = useClient(); + const useAuthentication = useMediaAuthentication(); + + const users = useMemo(() => Array.from(new Set(items.map((i) => i.event.sender))), [items]); + + const avatarMxc = getRoomAvatar(roomId); + + const powerLevelStateResult = usePowerLevelsState(roomId); + const powerLevels = usePowerLevels(powerLevelStateResult.value); + + const powerLevelTagsStateResult = usePowerLevelTagsState(roomId); + const powerLevelTags = usePowerLevelTags(powerLevels, powerLevelTagsStateResult.value); + + const membersAPI = useRoomMembers(roomId, users); + return (
( )} /> - {room.name} + {getRoomName(roomId) ?? 'Unknown'}
- - {items.map((item) => { - const { event } = item; - - const displayName = - getMemberDisplayName(room, event.sender) ?? - getMxIdLocalPart(event.sender) ?? - event.sender; - const senderAvatarMxc = getMemberAvatarMxc(room, event.sender); - - const relation = event.content['m.relates_to']; - const mainEventId = - relation?.rel_type === RelationType.Replace ? relation.event_id : event.event_id; - - const getContent = (() => - event.content['m.new_content'] ?? event.content) as GetContentCallback; - - const replyEventId = relation?.['m.in_reply_to']?.event_id; - const threadRootId = - relation?.rel_type === RelationType.Thread ? relation.event_id : undefined; - - const memberPowerTag = getMemberPowerTag(event.sender); - const tagColor = memberPowerTag?.color - ? accessibleTagColors?.get(memberPowerTag.color) - : undefined; - const tagIconSrc = memberPowerTag?.icon - ? getPowerTagIconSrc(mx, useAuthentication, memberPowerTag.icon) - : undefined; - - const usernameColor = legacyUsernameColor ? colorMXID(event.sender) : tagColor; - - return ( - - - - } - /> - - - } - > - - - - - - {displayName} - - - {tagIconSrc && } - - - - - Open - - - - {replyEventId && ( - - )} - {renderMatrixEvent(event.type, false, event, displayName, getContent)} - - - ); - })} - + + + + {children} + + +
); } diff --git a/src/app/features/message-search/useMessageSearch.ts b/src/app/features/message-search/useMessageSearch.ts index ded6d4b7..1dd7cbac 100644 --- a/src/app/features/message-search/useMessageSearch.ts +++ b/src/app/features/message-search/useMessageSearch.ts @@ -1,18 +1,18 @@ -import { - IEventWithRoomId, - IResultContext, - ISearchRequestBody, - ISearchResponse, - ISearchResult, - SearchOrderBy, -} from 'matrix-js-sdk'; import { useCallback } from 'react'; -import { useMatrixClient } from '../../hooks/useMatrixClient'; +import { + ClientEvent, + SearchEventContext, + SearchEventOrder, + SearchResult, +} from 'neurone/lib/api/types'; +import { postSearch, PostSearchBody, PostSearchOK } from 'neurone/lib/api/matrix/client/v3/search'; +import { parseMatrixResp } from 'neurone/lib/matrix-request'; +import { useClient } from '../../hooks/useClient'; export type ResultItem = { rank: number; - event: IEventWithRoomId; - context: IResultContext; + event: ClientEvent; + context: SearchEventContext; }; export type ResultGroup = { @@ -20,21 +20,24 @@ export type ResultGroup = { items: ResultItem[]; }; -export type SearchResult = { +export type MessageSearchResult = { nextToken?: string; highlights: string[]; groups: ResultGroup[]; }; -const groupSearchResult = (results: ISearchResult[]): ResultGroup[] => { +const groupSearchResult = (results: SearchResult[]): ResultGroup[] => { const groups: ResultGroup[] = []; results.forEach((item) => { - const roomId = item.result.room_id; + const { rank, result, context } = item; + if (!result || typeof rank !== 'number' || !context) return; + + const roomId = result.room_id; const resultItem: ResultItem = { - rank: item.rank, - event: item.result, - context: item.context, + rank, + event: result, + context, }; const lastAddedGroup: ResultGroup | undefined = groups[groups.length - 1]; @@ -51,10 +54,10 @@ const groupSearchResult = (results: ISearchResult[]): ResultGroup[] => { return groups; }; -const parseSearchResult = (result: ISearchResponse): SearchResult => { +const parseSearchResult = (result: PostSearchOK): MessageSearchResult => { const roomEvents = result.search_categories.room_events; - const searchResult: SearchResult = { + const searchResult: MessageSearchResult = { nextToken: roomEvents?.next_batch, highlights: roomEvents?.highlights ?? [], groups: groupSearchResult(roomEvents?.results ?? []), @@ -65,12 +68,12 @@ const parseSearchResult = (result: ISearchResponse): SearchResult => { export type MessageSearchParams = { term?: string; - order?: string; + order?: SearchEventOrder; rooms?: string[]; senders?: string[]; }; export const useMessageSearch = (params: MessageSearchParams) => { - const mx = useMatrixClient(); + const ct = useClient(); const { term, order, rooms, senders } = params; const searchMessages = useCallback( @@ -82,7 +85,7 @@ export const useMessageSearch = (params: MessageSearchParams) => { }; const limit = 20; - const requestBody: ISearchRequestBody = { + const requestBody: PostSearchBody = { search_categories: { room_events: { event_context: { @@ -96,19 +99,28 @@ export const useMessageSearch = (params: MessageSearchParams) => { senders, }, include_state: false, - order_by: order as SearchOrderBy.Recent, + order_by: order, search_term: term, }, }, }; - const r = await mx.search({ - body: requestBody, - next_batch: nextBatch === '' ? undefined : nextBatch, - }); - return parseSearchResult(r); + const resp = await ct.requestAuthJSON( + postSearch({ + searchParams: { next_batch: nextBatch === '' ? undefined : nextBatch }, + body: requestBody, + }) + ); + + const [err, result] = await parseMatrixResp(resp); + + if (err) { + throw new Error(err.data.error ?? err.data.errcode); + } + + return parseSearchResult(result); }, - [mx, term, order, rooms, senders] + [ct, term, order, rooms, senders] ); return searchMessages; diff --git a/src/app/hooks/useMessageParserOptions.ts b/src/app/hooks/useMessageParserOptions.ts index 6fadca79..de0beeb6 100644 --- a/src/app/hooks/useMessageParserOptions.ts +++ b/src/app/hooks/useMessageParserOptions.ts @@ -19,7 +19,8 @@ import { useMediaAuthentication } from './useMediaAuthentication'; export const useMessageParserOptions = ( roomId: string, getRoomName: GetRoomNameCallback, - getMemberName: GetRoomMemberNameCallback + getMemberName: GetRoomMemberNameCallback, + highlightRegex?: RegExp ) => { const ct = useClient(); const useAuthentication = useMediaAuthentication(); @@ -49,6 +50,7 @@ export const useMessageParserOptions = ( getReactCustomHtmlParser(ct, roomId, { linkifyOpts, useAuthentication, + highlightRegex, handleSpoilerClick: spoilerClickHandler, handleMentionClick: mentionClickHandler, getMemberName, @@ -58,6 +60,7 @@ export const useMessageParserOptions = ( ct, roomId, linkifyOpts, + highlightRegex, spoilerClickHandler, mentionClickHandler, useAuthentication, diff --git a/src/app/pages/Router.tsx b/src/app/pages/Router.tsx index 72580f00..72a34755 100644 --- a/src/app/pages/Router.tsx +++ b/src/app/pages/Router.tsx @@ -122,7 +122,7 @@ export const createRouter = (clientConfig: ClientConfig, screenSize: ScreenSize) {mobile ? null : } />} } /> join

} /> - {/* } /> */} + } /> )} } /> - {/*} /> */} + } /> (null); - const space = useSpace(); + const spaceId = useSpace(); const screenSize = useScreenSizeContext(); const mDirects = useAtomValue(mDirectAtom); const roomToParents = useAtomValue(roomToParentsAtom); const rooms = useSpaceChildren( allRoomsAtom, - space.roomId, - useRecursiveChildRoomScopeFactory(mx, mDirects, roomToParents) + spaceId, + useRecursiveChildRoomScopeFactory(ct, mDirects, roomToParents) ); return ( @@ -55,7 +55,11 @@ export function SpaceSearch() {