From a5bc5a5effcb87cd8a55b7651ba0683240aff799 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Sun, 12 Feb 2023 13:09:32 -0300 Subject: [PATCH 01/10] Prepare to customize the tab --- apps/meteor/app/search/README.md | 66 -------- .../app/search/client/{index.js => index.ts} | 5 +- .../app/search/client/provider/result.js | 2 + .../app/search/client/search/search.html | 2 +- .../meteor/app/search/client/search/search.js | 103 ++++++------- apps/meteor/app/search/client/style/style.css | 2 + .../views/room/components/BlazeTemplate.tsx | 3 +- .../room/components/VerticalBarOldActions.tsx | 3 +- .../room/contextualBar/MessageSearchTab.tsx | 33 ++++ .../views/room/lib/Toolbox/defaultActions.ts | 2 +- .../client/views/room/lib/Toolbox/index.tsx | 3 +- .../externals/meteor/templating.d.ts | 145 ++++++++++-------- .../ui-contexts/src/ServerContext/methods.ts | 27 ++++ 13 files changed, 200 insertions(+), 196 deletions(-) delete mode 100644 apps/meteor/app/search/README.md rename apps/meteor/app/search/client/{index.js => index.ts} (53%) create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab.tsx diff --git a/apps/meteor/app/search/README.md b/apps/meteor/app/search/README.md deleted file mode 100644 index 7029a8aaa74f..000000000000 --- a/apps/meteor/app/search/README.md +++ /dev/null @@ -1,66 +0,0 @@ -## Rocketchat Search - -This module enables search for messages and other things within Rocket.Chat. -It provides the basic infrastructure for *Search Providers*, which enables everybody to easily add another -search (e.g. with special functions) to the Rocket.Chat infrastructure. In addition it provides a defautl implementation -based on MongoDB. - -### Providers - -A new Provider just extends the provider class and registers itself in the *SearchProviderService*. -```ecmascript 6 -class MyProvider extends SearchProvider { - constructor() { - super('myProvider'); //a unique id for the provider - }; - - search(text, context, payload, callback) { - //do some search and call the callback with the result - }; -} - -searchProviderService.register(new MyProvider()); -``` - -### Settings -In order to enable Settings within the admin UI for your own provider, you can add it (e.g. in the constructor). -```ecmascript 6 -this._settings.add('PageSize', 'int', 15, { - i18nLabel: 'Search_Page_Size' - }); -``` -The setting values are loaded, when you use your provider. The values can be easily accessed. -```ecmascript 6 -this._settings.get('PageSize') -``` - -### Search UI -Search provider can have their own result template. The template is loaded with data. -```ecmascript 6 -{ - searching, //reactive var if search results are loading - result, //reactive var with the result - text, //reactive var with the search text - settings //the settings of the provider, - parentPayload, //the main search payload (not reset for new searches) - payload, //the payload (reseted when new search is issed from search field) - search //the search function -} -``` - -### Search Result -In order to provide a proper validation of the results the search function of the provider must follow at the following (extendable) format: -```ecmascript 6 -{ - message: { - docs:[{_id},...] - }, - room: { - docs:[{_id},...] - }, - user: { - docs:[{_id},...] - } -} -``` - diff --git a/apps/meteor/app/search/client/index.js b/apps/meteor/app/search/client/index.ts similarity index 53% rename from apps/meteor/app/search/client/index.js rename to apps/meteor/app/search/client/index.ts index 1f9b82c4ccc1..64dad78b4be6 100644 --- a/apps/meteor/app/search/client/index.js +++ b/apps/meteor/app/search/client/index.ts @@ -1,6 +1,5 @@ -import './search/search.html'; -import './search/search'; +import './search/search.js'; import './provider/suggestion.html'; import './provider/result.html'; -import './provider/result'; +import './provider/result.js'; import './style/style.css'; diff --git a/apps/meteor/app/search/client/provider/result.js b/apps/meteor/app/search/client/provider/result.js index a733b862fc55..05f8ba489f79 100644 --- a/apps/meteor/app/search/client/provider/result.js +++ b/apps/meteor/app/search/client/provider/result.js @@ -13,6 +13,8 @@ import { Rooms } from '../../../models/client'; import { getCommonRoomEvents } from '../../../ui/client/views/app/lib/getCommonRoomEvents'; import { goToRoomById } from '../../../../client/lib/utils/goToRoomById'; +import './result.html'; + Meteor.startup(function () { MessageAction.addButton({ id: 'jump-to-search-message', diff --git a/apps/meteor/app/search/client/search/search.html b/apps/meteor/app/search/client/search/search.html index dbb6c5a7f179..a52ea505b8f5 100644 --- a/apps/meteor/app/search/client/search/search.html +++ b/apps/meteor/app/search/client/search/search.html @@ -2,7 +2,7 @@ {{#unless isActive}} {{#if error}}
- {{_ error}} + {{error}}
{{/if}} {{else}} diff --git a/apps/meteor/app/search/client/search/search.js b/apps/meteor/app/search/client/search/search.js index 536e37babed9..9d79e16081c9 100644 --- a/apps/meteor/app/search/client/search/search.js +++ b/apps/meteor/app/search/client/search/search.js @@ -3,10 +3,12 @@ import { Tracker } from 'meteor/tracker'; import { Session } from 'meteor/session'; import { Template } from 'meteor/templating'; import { ReactiveVar } from 'meteor/reactive-var'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import _ from 'underscore'; +import './search.html'; import { dispatchToastMessage } from '../../../../client/lib/toast'; +import { withDebouncing } from '../../../../lib/utils/highOrderFunctions'; +import { t } from '../../../utils/client'; +import { call } from '../../../../client/lib/utils/call'; Template.RocketSearch.onCreated(function () { this.provider = new ReactiveVar(); @@ -15,15 +17,20 @@ Template.RocketSearch.onCreated(function () { this.suggestions = new ReactiveVar(); this.suggestionActive = new ReactiveVar(); - Meteor.call('rocketchatSearch.getProvider', (error, provider) => { - if (!error && provider) { + call('rocketchatSearch.getProvider').then( + (provider) => { + if (!provider) { + throw new Error('Current search provider is not active'); + } + this.scope.settings = provider.settings; this.provider.set(provider); this.isActive.set(true); - } else { - this.error.set('Search_current_provider_not_active'); - } - }); + }, + () => { + this.error.set(t('Search_current_provider_not_active')); + }, + ); const _search = () => { const _p = Object.assign({}, this.scope.parentPayload, this.scope.payload); @@ -31,22 +38,17 @@ Template.RocketSearch.onCreated(function () { if (this.scope.text.get()) { this.scope.searching.set(true); - Meteor.call( - 'rocketchatSearch.search', - this.scope.text.get(), - { rid: Session.get('openedRoom'), uid: Meteor.userId() }, - _p, - (err, result) => { - if (err) { - dispatchToastMessage({ - type: 'error', - message: TAPi18n.__('Search_message_search_failed'), - }); - this.scope.searching.set(false); - } else { - this.scope.searching.set(false); - this.scope.result.set(result); - } + call('rocketchatSearch.search', this.scope.text.get(), { rid: Session.get('openedRoom'), uid: Meteor.userId() }, _p).then( + (result) => { + this.scope.searching.set(false); + this.scope.result.set(result); + }, + () => { + dispatchToastMessage({ + type: 'error', + message: t('Search_message_search_failed'), + }); + this.scope.searching.set(false); }, ); } @@ -74,27 +76,16 @@ Template.RocketSearch.onCreated(function () { const _p = Object.assign({}, this.scope.parentPayload, this.scope.payload); - Meteor.call( - 'rocketchatSearch.suggest', - value, - { rid: Session.get('openedRoom'), uid: Meteor.userId() }, - this.scope.parentPayload, - _p, - (err, result) => { - if (err) { - // TODO what should happen - } else { - this.suggestionActive.set(undefined); - if (value !== this.scope.text.get()) { - this.suggestions.set(result); - } - } - }, - ); + call('rocketchatSearch.suggest', value, { rid: Session.get('openedRoom'), uid: Meteor.userId() }, _p).then((result) => { + this.suggestionActive.set(undefined); + if (value !== this.scope.text.get()) { + this.suggestions.set(result); + } + }); }; }); -Template.RocketSearch.events = { +Template.RocketSearch.events({ 'keydown #message-search'(evt, t) { if (evt.keyCode === 13) { if (t.suggestionActive.get() !== undefined) { @@ -126,7 +117,7 @@ Template.RocketSearch.events = { t.suggestionActive.set(suggestionActive !== undefined && suggestionActive === 0 ? suggestions.length - 1 : suggestionActive - 1); } }, - 'keyup #message-search': _.debounce(function (evt, t) { + 'keyup #message-search': withDebouncing({ wait: 300 })(function (evt, t) { if (evt.keyCode === 13) { return evt.preventDefault(); } @@ -142,7 +133,7 @@ Template.RocketSearch.events = { } else { t.suggest(value); } - }, 300), + }), 'click .rocket-search-suggestion-item'(e, t) { if (this.action) { const value = this.action(); @@ -158,7 +149,7 @@ Template.RocketSearch.events = { 'mouseenter .rocket-search-suggestion-item'(e, t) { t.suggestionActive.set(t.suggestions.get().indexOf(this)); }, -}; +}); Template.RocketSearch.helpers({ error() { @@ -189,21 +180,15 @@ Template.RocketSearch.helpers({ // add closer to suggestions Template.RocketSearch.onRendered(function () { - $(document).on(`click.suggestionclose.${this.data.rid}`, () => { - // if (e.target.id !== 'rocket-search-suggestions' && !$(e.target).parents('#rocket-search-suggestions').length) { - this.suggestions.set(); - // } - }); Tracker.autorun((c) => { - if (this.isActive.get() === true) { - Tracker.afterFlush(() => { - document.querySelector('#message-search').focus(); - }); - c.stop(); + if (!this.isActive.get()) { + return; } - }); -}); -Template.RocketSearch.onDestroyed(function () { - $(document).off(`click.suggestionclose.${this.data.rid}`); + Tracker.afterFlush(() => { + document.querySelector('#message-search').focus(); + }); + + c.stop(); + }); }); diff --git a/apps/meteor/app/search/client/style/style.css b/apps/meteor/app/search/client/style/style.css index e7c5361afcc2..3d2459a3bbcb 100644 --- a/apps/meteor/app/search/client/style/style.css +++ b/apps/meteor/app/search/client/style/style.css @@ -21,6 +21,8 @@ overflow-x: hidden; flex-direction: column; flex: 1 1 0; + + margin: 0 -24px; } .rocket-default-search-settings { diff --git a/apps/meteor/client/views/room/components/BlazeTemplate.tsx b/apps/meteor/client/views/room/components/BlazeTemplate.tsx index dc9687894ec0..282c9c808b18 100644 --- a/apps/meteor/client/views/room/components/BlazeTemplate.tsx +++ b/apps/meteor/client/views/room/components/BlazeTemplate.tsx @@ -1,6 +1,7 @@ import { Box } from '@rocket.chat/fuselage'; import { Blaze } from 'meteor/blaze'; import { ReactiveVar } from 'meteor/reactive-var'; +import type { BlazeTemplates } from 'meteor/templating'; import { Template } from 'meteor/templating'; import type { ComponentProps, FC } from 'react'; import React, { memo, useLayoutEffect, useRef } from 'react'; @@ -11,7 +12,7 @@ import { useRoomMessageContext } from './body/useRoomMessageContext'; const BlazeTemplate: FC< Omit, 'children'> & { - name: string; + name: keyof BlazeTemplates; } & Record > = ({ name, flexShrink, overflow, onClick, w, ...props }) => { const [portals, portalsSubscription] = useBlazePortals(); diff --git a/apps/meteor/client/views/room/components/VerticalBarOldActions.tsx b/apps/meteor/client/views/room/components/VerticalBarOldActions.tsx index f8455088396f..b4ba69dbb88b 100644 --- a/apps/meteor/client/views/room/components/VerticalBarOldActions.tsx +++ b/apps/meteor/client/views/room/components/VerticalBarOldActions.tsx @@ -2,6 +2,7 @@ import type { IRoom } from '@rocket.chat/core-typings'; import type { Icon } from '@rocket.chat/fuselage'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useTranslation } from '@rocket.chat/ui-contexts'; +import type { BlazeTemplates } from 'meteor/templating'; import type { ReactElement, ComponentProps } from 'react'; import React from 'react'; @@ -11,7 +12,7 @@ import { useTabBarClose } from '../contexts/ToolboxContext'; import BlazeTemplate from './BlazeTemplate'; type VerticalBarOldActionsProps = { - name: string; + name: keyof BlazeTemplates; rid: IRoom['_id']; _id: IRoom['_id']; icon?: ComponentProps['name']; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab.tsx new file mode 100644 index 000000000000..9cb08fac560e --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab.tsx @@ -0,0 +1,33 @@ +import { useTranslation } from '@rocket.chat/ui-contexts'; +import React from 'react'; + +import VerticalBarClose from '../../../components/VerticalBar/VerticalBarClose'; +import VerticalBarContent from '../../../components/VerticalBar/VerticalBarContent'; +import VerticalBarHeader from '../../../components/VerticalBar/VerticalBarHeader'; +import VerticalBarIcon from '../../../components/VerticalBar/VerticalBarIcon'; +import VerticalBarText from '../../../components/VerticalBar/VerticalBarText'; +import BlazeTemplate from '../components/BlazeTemplate'; +import { useRoom } from '../contexts/RoomContext'; +import { useToolboxContext } from '../contexts/ToolboxContext'; + +const MessageSearchTab = () => { + const room = useRoom(); + const toolbox = useToolboxContext(); + + const t = useTranslation(); + + return ( + <> + + {'magnifier' && } + {t('Search_Messages')} + {close && } + + + + + + ); +}; + +export default MessageSearchTab; diff --git a/apps/meteor/client/views/room/lib/Toolbox/defaultActions.ts b/apps/meteor/client/views/room/lib/Toolbox/defaultActions.ts index 6cc26abff31f..52d0eef9a2b3 100644 --- a/apps/meteor/client/views/room/lib/Toolbox/defaultActions.ts +++ b/apps/meteor/client/views/room/lib/Toolbox/defaultActions.ts @@ -8,7 +8,7 @@ addAction('rocket-search', { id: 'rocket-search', title: 'Search_Messages', icon: 'magnifier', - template: 'RocketSearch', + template: lazy(() => import('../../contextualBar/MessageSearchTab')), order: 6, }); diff --git a/apps/meteor/client/views/room/lib/Toolbox/index.tsx b/apps/meteor/client/views/room/lib/Toolbox/index.tsx index b024d7a3af5d..52f7d250c405 100644 --- a/apps/meteor/client/views/room/lib/Toolbox/index.tsx +++ b/apps/meteor/client/views/room/lib/Toolbox/index.tsx @@ -1,6 +1,7 @@ import type { IRoom } from '@rocket.chat/core-typings'; import type { Box, Option, Icon } from '@rocket.chat/fuselage'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; +import type { BlazeTemplates } from 'meteor/templating'; import type { ReactNode, MouseEvent, ComponentProps, ComponentType } from 'react'; import type { ToolboxContextValue } from '../../contexts/ToolboxContext'; @@ -37,7 +38,7 @@ export type ToolboxActionConfig = { 'hotkey'?: string; 'action'?: (e?: MouseEvent) => void; 'template'?: - | string + | keyof BlazeTemplates | ComponentType<{ tabBar: ToolboxContextValue; _id: IRoom['_id']; diff --git a/apps/meteor/definition/externals/meteor/templating.d.ts b/apps/meteor/definition/externals/meteor/templating.d.ts index 5319c649f839..e4af1dd7c8b1 100644 --- a/apps/meteor/definition/externals/meteor/templating.d.ts +++ b/apps/meteor/definition/externals/meteor/templating.d.ts @@ -1,6 +1,7 @@ import 'meteor/templating'; import type { Blaze } from 'meteor/blaze'; import type { ReactiveVar } from 'meteor/reactive-var'; +import type { IRoom } from '@rocket.chat/core-typings'; declare module 'meteor/blaze' { namespace Blaze { @@ -22,54 +23,70 @@ declare module 'meteor/blaze' { } declare module 'meteor/templating' { - interface TemplateStatic { - requiresPermission: Blaze.Template>; - ChatpalAdmin: Blaze.Template>; - ChatpalSearchResultTemplate: Blaze.Template>; - ChatpalSearchSingleTemplate: Blaze.Template>; - ChatpalSearchSingleUser: Blaze.Template>; - ChatpalSearchSingleRoom: Blaze.Template>; - ChatpalSuggestionItemTemplate: Blaze.Template>; - emojiPicker: Blaze.Template>; - lazyloadImage: Blaze.Template>; - customFieldsForm: Blaze.Template>; - ExternalFrameContainer: Blaze.Template>; - broadcastView: Blaze.Template>; - liveStreamBroadcast: Blaze.Template>; - liveStreamTab: Blaze.Template>; - liveStreamView: Blaze.Template>; - inputAutocomplete: Blaze.Template>; - textareaAutocomplete: Blaze.Template>; - _autocompleteContainer: Blaze.Template>; - _noMatch: Blaze.Template>; - authorize: Blaze.Template>; - oauth404: Blaze.Template>; - oembedBaseWidget: Blaze.Template>; - oembedAudioWidget: Blaze.Template>; - oembedFrameWidget: Blaze.Template>; - oembedImageWidget: Blaze.Template>; - oembedUrlWidget: Blaze.Template>; - oembedVideoWidget: Blaze.Template>; - oembedYoutubeWidget: Blaze.Template>; - DefaultSearchResultTemplate: Blaze.Template>; - DefaultSuggestionItemTemplate: Blaze.Template>; - RocketSearch: Blaze.Template>; - icon: Blaze.Template>; - popupList: Blaze.Template>; - popupList_default: Blaze.Template>; - popupList_item_default: Blaze.Template>; - popupList_loading: Blaze.Template>; - popupList_item_channel: Blaze.Template>; - popupList_item_custom: Blaze.Template>; - selectDropdown: Blaze.Template>; - CodeMirror: Blaze.Template>; - photoswipeContent: Blaze.Template>; - roomSearch: Blaze.Template>; - roomSearchEmpty: Blaze.Template>; - avatar: Blaze.Template>; - username: Blaze.Template< + type BlazeTemplate> = Blaze.Template< + TData, + Blaze.TemplateInstance & TInstanceExtras + >; + + type BlazeTemplates = { + requiresPermission: BlazeTemplate; + ChatpalAdmin: BlazeTemplate; + ChatpalSearchResultTemplate: BlazeTemplate; + ChatpalSearchSingleTemplate: BlazeTemplate; + ChatpalSearchSingleUser: BlazeTemplate; + ChatpalSearchSingleRoom: BlazeTemplate; + ChatpalSuggestionItemTemplate: BlazeTemplate; + emojiPicker: BlazeTemplate; + lazyloadImage: BlazeTemplate; + customFieldsForm: BlazeTemplate; + ExternalFrameContainer: BlazeTemplate; + broadcastView: BlazeTemplate; + liveStreamBroadcast: BlazeTemplate; + liveStreamTab: BlazeTemplate; + liveStreamView: BlazeTemplate; + inputAutocomplete: BlazeTemplate; + textareaAutocomplete: BlazeTemplate; + _autocompleteContainer: BlazeTemplate; + _noMatch: BlazeTemplate; + authorize: BlazeTemplate; + oauth404: BlazeTemplate; + oembedBaseWidget: BlazeTemplate; + oembedAudioWidget: BlazeTemplate; + oembedFrameWidget: BlazeTemplate; + oembedImageWidget: BlazeTemplate; + oembedUrlWidget: BlazeTemplate; + oembedVideoWidget: BlazeTemplate; + oembedYoutubeWidget: BlazeTemplate; + DefaultSearchResultTemplate: BlazeTemplate; + DefaultSuggestionItemTemplate: BlazeTemplate; + RocketSearch: BlazeTemplate< + { + rid: IRoom['_id']; + }, + { + provider: ReactiveVar; + isActive: ReactiveVar; + error: ReactiveVar; + suggestions: ReactiveVar; + suggestionActive: ReactiveVar; + } + >; + icon: BlazeTemplate; + popupList: BlazeTemplate; + popupList_default: BlazeTemplate; + popupList_item_default: BlazeTemplate; + popupList_loading: BlazeTemplate; + popupList_item_channel: BlazeTemplate; + popupList_item_custom: BlazeTemplate; + selectDropdown: BlazeTemplate; + CodeMirror: BlazeTemplate; + photoswipeContent: BlazeTemplate; + roomSearch: BlazeTemplate; + roomSearchEmpty: BlazeTemplate; + avatar: BlazeTemplate; + username: BlazeTemplate< Record, - Blaze.TemplateInstance> & { + { customFields: ReactiveVar unknown; } >; - error: Blaze.Template>; - loading: Blaze.Template>; - message: Blaze.Template>; - messageThread: Blaze.Template>; - messagePopup: Blaze.Template>; - messagePopupChannel: Blaze.Template>; - messagePopupConfig: Blaze.Template>; - messagePopupEmoji: Blaze.Template>; - messagePopupSlashCommand: Blaze.Template>; - messagePopupSlashCommandPreview: Blaze.Template>; - messagePopupUser: Blaze.Template>; - collapseArrow: Blaze.Template>; - rc_modal: Blaze.Template>; - popout: Blaze.Template>; - popover: Blaze.Template>; - messagePopupCannedResponse: Blaze.Template>; + error: BlazeTemplate; + loading: BlazeTemplate; + message: BlazeTemplate; + messageThread: BlazeTemplate; + messagePopup: BlazeTemplate; + messagePopupChannel: BlazeTemplate; + messagePopupConfig: BlazeTemplate; + messagePopupEmoji: BlazeTemplate; + messagePopupSlashCommand: BlazeTemplate; + messagePopupSlashCommandPreview: BlazeTemplate; + messagePopupUser: BlazeTemplate; + collapseArrow: BlazeTemplate; + rc_modal: BlazeTemplate; + popout: BlazeTemplate; + popover: BlazeTemplate; + messagePopupCannedResponse: BlazeTemplate; + }; + interface TemplateStatic extends BlazeTemplates { instance(): TemplateStatic[TTemplateName] extends Blaze.Template ? I : never; } } diff --git a/packages/ui-contexts/src/ServerContext/methods.ts b/packages/ui-contexts/src/ServerContext/methods.ts index 8e183f9611bc..16c1fd18f5b3 100644 --- a/packages/ui-contexts/src/ServerContext/methods.ts +++ b/packages/ui-contexts/src/ServerContext/methods.ts @@ -267,6 +267,33 @@ export interface ServerMethods { 'private-settings/get': (updatedSince?: Date) => ISetting[] | { update: ISetting[]; remove: ISetting[] }; 'pinMessage': (message: IMessage) => void; 'unpinMessage': (message: IMessage) => void; + 'rocketchatSearch.getProvider': () => + | { + key: string; + description: TranslationKey; + icon: string; + resultTemplate: string; + supportsSuggestions: boolean; + suggestionItemTemplate: string | undefined; + settings: unknown[]; + } + | undefined; + 'rocketchatSearch.search': ( + text: string, + context: { uid: IUser['_id']; rid: IRoom['_id'] }, + payload: unknown, + ) => { + message: IMessage; + room: IRoom; + }; + 'rocketchatSearch.suggest': ( + text: string, + context: { uid: IUser['_id']; rid: IRoom['_id'] }, + payload: unknown, + ) => { + message: IMessage; + room: IRoom; + }; } export type ServerMethodName = keyof ServerMethods; From ff1cc56db4f09c0bacad804ef22c6fddd2ca6575 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Mon, 13 Feb 2023 03:55:24 -0300 Subject: [PATCH 02/10] Create subcomponents --- apps/meteor/app/search/client/index.ts | 1 - .../app/search/client/search/search.html | 44 ---- .../meteor/app/search/client/search/search.js | 194 ------------------ apps/meteor/app/search/client/style/style.css | 12 +- .../views/room/components/BlazeTemplate.tsx | 51 ++++- .../room/components/VerticalBarOldActions.tsx | 6 +- .../room/contextualBar/MessageSearchTab.tsx | 33 --- .../MessageSearchTab/MessageSearchTab.tsx | 43 ++++ .../MessageSearchFormWithSuggestions.tsx | 164 +++++++++++++++ .../MessageSearchFormWithoutSuggestions.tsx | 67 ++++++ .../components/MessageSearchPanel.tsx | 130 ++++++++++++ .../components/MessageSearchSuggestion.tsx | 35 ++++ .../hooks/useSearchProviderQuery.ts | 14 ++ .../hooks/useStateAsReactiveVar.ts | 31 +++ .../contextualBar/MessageSearchTab/index.ts | 1 + .../externals/meteor/templating.d.ts | 59 ++++-- packages/core-typings/src/index.ts | 2 + .../src/search/ISearchProvider.ts | 11 + packages/core-typings/src/search/index.ts | 1 + .../ui-contexts/src/ServerContext/methods.ts | 27 +-- 20 files changed, 589 insertions(+), 337 deletions(-) delete mode 100644 apps/meteor/app/search/client/search/search.html delete mode 100644 apps/meteor/app/search/client/search/search.js delete mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab.tsx create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithoutSuggestions.tsx create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchPanel.tsx create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useSearchProviderQuery.ts create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useStateAsReactiveVar.ts create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/index.ts create mode 100644 packages/core-typings/src/search/ISearchProvider.ts create mode 100644 packages/core-typings/src/search/index.ts diff --git a/apps/meteor/app/search/client/index.ts b/apps/meteor/app/search/client/index.ts index 64dad78b4be6..15941258e4fd 100644 --- a/apps/meteor/app/search/client/index.ts +++ b/apps/meteor/app/search/client/index.ts @@ -1,4 +1,3 @@ -import './search/search.js'; import './provider/suggestion.html'; import './provider/result.html'; import './provider/result.js'; diff --git a/apps/meteor/app/search/client/search/search.html b/apps/meteor/app/search/client/search/search.html deleted file mode 100644 index a52ea505b8f5..000000000000 --- a/apps/meteor/app/search/client/search/search.html +++ /dev/null @@ -1,44 +0,0 @@ - diff --git a/apps/meteor/app/search/client/search/search.js b/apps/meteor/app/search/client/search/search.js deleted file mode 100644 index 9d79e16081c9..000000000000 --- a/apps/meteor/app/search/client/search/search.js +++ /dev/null @@ -1,194 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Tracker } from 'meteor/tracker'; -import { Session } from 'meteor/session'; -import { Template } from 'meteor/templating'; -import { ReactiveVar } from 'meteor/reactive-var'; -import './search.html'; - -import { dispatchToastMessage } from '../../../../client/lib/toast'; -import { withDebouncing } from '../../../../lib/utils/highOrderFunctions'; -import { t } from '../../../utils/client'; -import { call } from '../../../../client/lib/utils/call'; - -Template.RocketSearch.onCreated(function () { - this.provider = new ReactiveVar(); - this.isActive = new ReactiveVar(false); - this.error = new ReactiveVar(); - this.suggestions = new ReactiveVar(); - this.suggestionActive = new ReactiveVar(); - - call('rocketchatSearch.getProvider').then( - (provider) => { - if (!provider) { - throw new Error('Current search provider is not active'); - } - - this.scope.settings = provider.settings; - this.provider.set(provider); - this.isActive.set(true); - }, - () => { - this.error.set(t('Search_current_provider_not_active')); - }, - ); - - const _search = () => { - const _p = Object.assign({}, this.scope.parentPayload, this.scope.payload); - - if (this.scope.text.get()) { - this.scope.searching.set(true); - - call('rocketchatSearch.search', this.scope.text.get(), { rid: Session.get('openedRoom'), uid: Meteor.userId() }, _p).then( - (result) => { - this.scope.searching.set(false); - this.scope.result.set(result); - }, - () => { - dispatchToastMessage({ - type: 'error', - message: t('Search_message_search_failed'), - }); - this.scope.searching.set(false); - }, - ); - } - }; - - this.scope = { - searching: new ReactiveVar(false), - result: new ReactiveVar(), - text: new ReactiveVar(), - settings: {}, - parentPayload: {}, - payload: {}, - search: _search, - }; - - this.search = (value) => { - this.scope.result.set(undefined); - this.scope.payload = {}; - this.scope.text.set(value); - _search(); - }; - - this.suggest = (value) => { - this.suggestions.set(); - - const _p = Object.assign({}, this.scope.parentPayload, this.scope.payload); - - call('rocketchatSearch.suggest', value, { rid: Session.get('openedRoom'), uid: Meteor.userId() }, _p).then((result) => { - this.suggestionActive.set(undefined); - if (value !== this.scope.text.get()) { - this.suggestions.set(result); - } - }); - }; -}); - -Template.RocketSearch.events({ - 'keydown #message-search'(evt, t) { - if (evt.keyCode === 13) { - if (t.suggestionActive.get() !== undefined) { - const suggestion = t.suggestions.get()[t.suggestionActive.get()]; - if (suggestion.action) { - const value = suggestion.action(); - if (value) { - t.search(value); - } - } else { - t.search(suggestion.text); - } - } else { - t.search(evt.target.value.trim()); - } - t.suggestions.set(); - return evt.preventDefault(); - } - - const suggestions = t.suggestions.get(); - const suggestionActive = t.suggestionActive.get(); - - if (evt.keyCode === 40 && suggestions) { - t.suggestionActive.set(suggestionActive !== undefined && suggestionActive < suggestions.length - 1 ? suggestionActive + 1 : 0); - return; - } - - if (evt.keyCode === 38 && suggestions) { - t.suggestionActive.set(suggestionActive !== undefined && suggestionActive === 0 ? suggestions.length - 1 : suggestionActive - 1); - } - }, - 'keyup #message-search': withDebouncing({ wait: 300 })(function (evt, t) { - if (evt.keyCode === 13) { - return evt.preventDefault(); - } - - const { value } = evt.target; - - if (evt.keyCode === 40 || evt.keyCode === 38) { - return evt.preventDefault(); - } - - if (!t.provider.get().supportsSuggestions) { - t.search(value); - } else { - t.suggest(value); - } - }), - 'click .rocket-search-suggestion-item'(e, t) { - if (this.action) { - const value = this.action(); - if (value) { - t.search(value); - } else { - t.suggestions.set(); - } - } else { - t.search(this.text); - } - }, - 'mouseenter .rocket-search-suggestion-item'(e, t) { - t.suggestionActive.set(t.suggestions.get().indexOf(this)); - }, -}); - -Template.RocketSearch.helpers({ - error() { - return Template.instance().error.get(); - }, - provider() { - return Template.instance().provider.get(); - }, - scope() { - return Template.instance().scope; - }, - text() { - return Template.instance().scope.text.get(); - }, - isActive() { - return Template.instance().isActive.get(); - }, - suggestions() { - return Template.instance().suggestions.get(); - }, - suggestionActive() { - return Template.instance().suggestionActive.get(); - }, - suggestionSelected(index) { - return Template.instance().suggestionActive.get() === index ? 'active' : ''; - }, -}); - -// add closer to suggestions -Template.RocketSearch.onRendered(function () { - Tracker.autorun((c) => { - if (!this.isActive.get()) { - return; - } - - Tracker.afterFlush(() => { - document.querySelector('#message-search').focus(); - }); - - c.stop(); - }); -}); diff --git a/apps/meteor/app/search/client/style/style.css b/apps/meteor/app/search/client/style/style.css index 3d2459a3bbcb..1f3908b98c88 100644 --- a/apps/meteor/app/search/client/style/style.css +++ b/apps/meteor/app/search/client/style/style.css @@ -5,18 +5,12 @@ padding: 0 !important; } -.rocket-search-tab { - display: flex; - flex-direction: column; - flex: 1; -} - .rocket-default-search-results { overflow: auto; overflow-x: hidden; } -.rocket-search-result { +.rocket-search-result.rocket-search-result { display: flex; overflow-x: hidden; flex-direction: column; @@ -34,10 +28,6 @@ padding-left: 70px !important; } -.rocket-search-error { - padding: 0 24px; -} - .rocket-default-search-results .js-list { overflow: hidden; } diff --git a/apps/meteor/client/views/room/components/BlazeTemplate.tsx b/apps/meteor/client/views/room/components/BlazeTemplate.tsx index 282c9c808b18..a489c31cb5e8 100644 --- a/apps/meteor/client/views/room/components/BlazeTemplate.tsx +++ b/apps/meteor/client/views/room/components/BlazeTemplate.tsx @@ -3,18 +3,45 @@ import { Blaze } from 'meteor/blaze'; import { ReactiveVar } from 'meteor/reactive-var'; import type { BlazeTemplates } from 'meteor/templating'; import { Template } from 'meteor/templating'; -import type { ComponentProps, FC } from 'react'; +import type { ComponentProps } from 'react'; import React, { memo, useLayoutEffect, useRef } from 'react'; import { useBlazePortals } from '../../../lib/portals/blazePortals'; import { useRoom } from '../contexts/RoomContext'; import { useRoomMessageContext } from './body/useRoomMessageContext'; -const BlazeTemplate: FC< - Omit, 'children'> & { - name: keyof BlazeTemplates; - } & Record -> = ({ name, flexShrink, overflow, onClick, w, ...props }) => { +type PropsFromBox = 'className' | 'display' | 'flexGrow' | 'flexShrink' | 'flexDirection' | 'overflow' | 'w' | 'onClick' | 'onMouseEnter'; + +type AllBlazeTemplateProps = { + [TTemplateName in keyof BlazeTemplates]: BlazeTemplates[TTemplateName] extends Blaze.Template + ? symbol extends D + ? { + name: TTemplateName; + } & Pick, PropsFromBox> + : { + name: TTemplateName; + } & Pick, Exclude> & + D + : never; +}; + +type BlazeTemplateProps = TTemplateName extends any + ? AllBlazeTemplateProps[TTemplateName] + : never; + +const BlazeTemplate = ({ + name, + className, + display, + flexGrow, + flexShrink, + flexDirection, + overflow, + w, + onClick, + onMouseEnter, + ...props +}: BlazeTemplateProps) => { const [portals, portalsSubscription] = useBlazePortals(); const roomMessageContext = useRoomMessageContext(useRoom()); @@ -46,12 +73,16 @@ const BlazeTemplate: FC< <> {portals} diff --git a/apps/meteor/client/views/room/components/VerticalBarOldActions.tsx b/apps/meteor/client/views/room/components/VerticalBarOldActions.tsx index b4ba69dbb88b..b6baf70b69b2 100644 --- a/apps/meteor/client/views/room/components/VerticalBarOldActions.tsx +++ b/apps/meteor/client/views/room/components/VerticalBarOldActions.tsx @@ -14,13 +14,13 @@ import BlazeTemplate from './BlazeTemplate'; type VerticalBarOldActionsProps = { name: keyof BlazeTemplates; rid: IRoom['_id']; - _id: IRoom['_id']; + _id: string; icon?: ComponentProps['name']; tabBar: ToolboxContextValue['tabBar']; title: TranslationKey; }; -const VerticalBarOldActions = ({ name, rid, icon, tabBar, title, ...props }: VerticalBarOldActionsProps): ReactElement => { +const VerticalBarOldActions = ({ name, icon, title, ...props }: VerticalBarOldActionsProps): ReactElement => { const close = useTabBarClose(); const t = useTranslation(); @@ -32,7 +32,7 @@ const VerticalBarOldActions = ({ name, rid, icon, tabBar, title, ...props }: Ver {close && } - + ); diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab.tsx deleted file mode 100644 index 9cb08fac560e..000000000000 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { useTranslation } from '@rocket.chat/ui-contexts'; -import React from 'react'; - -import VerticalBarClose from '../../../components/VerticalBar/VerticalBarClose'; -import VerticalBarContent from '../../../components/VerticalBar/VerticalBarContent'; -import VerticalBarHeader from '../../../components/VerticalBar/VerticalBarHeader'; -import VerticalBarIcon from '../../../components/VerticalBar/VerticalBarIcon'; -import VerticalBarText from '../../../components/VerticalBar/VerticalBarText'; -import BlazeTemplate from '../components/BlazeTemplate'; -import { useRoom } from '../contexts/RoomContext'; -import { useToolboxContext } from '../contexts/ToolboxContext'; - -const MessageSearchTab = () => { - const room = useRoom(); - const toolbox = useToolboxContext(); - - const t = useTranslation(); - - return ( - <> - - {'magnifier' && } - {t('Search_Messages')} - {close && } - - - - - - ); -}; - -export default MessageSearchTab; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx new file mode 100644 index 000000000000..3be0c905c2d1 --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx @@ -0,0 +1,43 @@ +import { Callout } from '@rocket.chat/fuselage'; +import { useTranslation } from '@rocket.chat/ui-contexts'; +import React, { useCallback } from 'react'; + +import VerticalBarClose from '../../../../components/VerticalBar/VerticalBarClose'; +import VerticalBarContent from '../../../../components/VerticalBar/VerticalBarContent'; +import VerticalBarHeader from '../../../../components/VerticalBar/VerticalBarHeader'; +import VerticalBarIcon from '../../../../components/VerticalBar/VerticalBarIcon'; +import VerticalBarText from '../../../../components/VerticalBar/VerticalBarText'; +import { useTabBarClose } from '../../contexts/ToolboxContext'; +import MessageSearchPanel from './components/MessageSearchPanel'; +import { useSearchProviderQuery } from './hooks/useSearchProviderQuery'; + +const MessageSearchTab = () => { + const providerQuery = useSearchProviderQuery(); + + const tabBarClose = useTabBarClose(); + const handleCloseButtonClick = useCallback(() => { + tabBarClose(); + }, [tabBarClose]); + + const t = useTranslation(); + + return ( + <> + + + {t('Search_Messages')} + + + + {providerQuery.isSuccess && } + {providerQuery.isError && ( + + {t('Search_current_provider_not_active')} + + )} + + + ); +}; + +export default MessageSearchTab; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx new file mode 100644 index 000000000000..4920fa5e9170 --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx @@ -0,0 +1,164 @@ +import type { ISearchProvider } from '@rocket.chat/core-typings'; +import { Box } from '@rocket.chat/fuselage'; +import { useDebouncedCallback, useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useMethod, useTranslation, useUserId } from '@rocket.chat/ui-contexts'; +import { useMutation } from '@tanstack/react-query'; +import type { KeyboardEvent, UIEvent } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useForm } from 'react-hook-form'; + +import BlazeTemplate from '../../../components/BlazeTemplate'; +import { useRoom } from '../../../contexts/RoomContext'; +import MessageSearchSuggestion from './MessageSearchSuggestion'; + +const getSuggestionText = (suggestion?: { action(): string } | { text: string }): string | undefined => { + if (!suggestion) { + return undefined; + } + + return 'text' in suggestion ? suggestion.text : suggestion.action(); +}; + +type MessageSearchFormWithSuggestionsProps = { + provider: ISearchProvider; + getPayload: () => Record; + onSearch: (searchText: string) => void; +}; + +const MessageSearchFormWithSuggestions = ({ provider, getPayload, onSearch }: MessageSearchFormWithSuggestionsProps) => { + const { handleSubmit, register, setFocus, setValue } = useForm({ + defaultValues: { + 'message-search': '', + }, + }); + + useEffect(() => { + setFocus('message-search'); + }, [setFocus]); + + const submitHandler = handleSubmit(({ 'message-search': searchText }) => { + suggestionsMutation.reset(); + onSearch(searchText); + }); + + const uid = useUserId() ?? undefined; + const room = useRoom(); + const getSearchSuggestions = useMethod('rocketchatSearch.suggest'); + const suggestionsMutation = useMutation( + ['rooms', room._id, 'message-search', 'suggestions', { uid, rid: room._id }] as const, + async ({ searchText }: { searchText: string }) => { + const suggestions = await getSearchSuggestions(searchText, { rid: room._id, uid }, getPayload()); + + if (!suggestions || suggestions.length === 0) { + return [{ text: 'Test' }]; + } + + return suggestions; + }, + { + onMutate: () => { + setSuggestionIndex(0); + }, + }, + ); + + const debouncedSuggestionsMutate = useDebouncedCallback(useMutableCallback(suggestionsMutation.mutate), 300); + + const handleInput = useCallback( + (event: UIEvent) => { + const searchText = event.currentTarget.value; + debouncedSuggestionsMutate({ searchText }); + }, + [debouncedSuggestionsMutate], + ); + + const [suggestionIndex, setSuggestionIndex] = useState(0); + + const handleKeyDown = useMutableCallback((event: KeyboardEvent) => { + const suggestions = suggestionsMutation.data; + + if (event.code === 'Enter') { + const suggestion = suggestionIndex >= 0 ? suggestions?.[suggestionIndex] : undefined; + const suggestionText = getSuggestionText(suggestion); + if (!suggestionText) { + return; + } + + setValue('message-search', suggestionText); + return; + } + + if (!suggestions) { + return; + } + + if (event.code === 'ArrowDown') { + setSuggestionIndex((suggestionIndex) => { + return suggestionIndex < suggestions.length - 1 ? suggestionIndex + 1 : 0; + }); + return; + } + + if (event.code === 'ArrowUp') { + setSuggestionIndex((suggestionIndex) => { + return suggestionIndex === 0 ? suggestions.length - 1 : suggestionIndex - 1; + }); + } + }); + + const handleSuggestionClick = useMutableCallback((suggestion: { action(): string } | { text: string }) => { + const suggestionText = getSuggestionText(suggestion); + if (!suggestionText) { + return; + } + + setValue('message-search', suggestionText); + onSearch(suggestionText); + suggestionsMutation.reset(); + }); + + const handleSuggestionHover = useMutableCallback((suggestion: { action(): string } | { text: string }) => { + setSuggestionIndex(suggestionsMutation.data?.indexOf(suggestion) ?? 0); + }); + + const t = useTranslation(); + + return ( + +
+ +
+ {suggestionsMutation.isSuccess && suggestionsMutation.data && ( +
+ {suggestionsMutation.data.map((suggestion, index) => ( + + ))} +
+ )} +
+ ); +}; + +export default MessageSearchFormWithSuggestions; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithoutSuggestions.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithoutSuggestions.tsx new file mode 100644 index 000000000000..27afb4d59276 --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithoutSuggestions.tsx @@ -0,0 +1,67 @@ +import type { ISearchProvider } from '@rocket.chat/core-typings'; +import { Box } from '@rocket.chat/fuselage'; +import { useDebouncedCallback, useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useTranslation } from '@rocket.chat/ui-contexts'; +import type { UIEvent } from 'react'; +import React, { useCallback, useEffect } from 'react'; +import { useForm } from 'react-hook-form'; + +import BlazeTemplate from '../../../components/BlazeTemplate'; + +type MessageSearchFormWithoutSuggestionsProps = { + provider: ISearchProvider; + onSearch: (searchText: string) => void; +}; + +const MessageSearchFormWithoutSuggestions = ({ provider, onSearch }: MessageSearchFormWithoutSuggestionsProps) => { + const { handleSubmit, register, setFocus } = useForm({ + defaultValues: { + 'message-search': '', + }, + }); + + useEffect(() => { + setFocus('message-search'); + }, [setFocus]); + + const debouncedOnSearch = useDebouncedCallback(useMutableCallback(onSearch), 300); + + const submitHandler = handleSubmit(({ 'message-search': searchText }) => { + debouncedOnSearch.cancel(); + debouncedOnSearch(searchText); + }); + + const handleInput = useCallback( + (event: UIEvent) => { + const { value } = event.currentTarget; + debouncedOnSearch(value); + }, + [debouncedOnSearch], + ); + + const t = useTranslation(); + + return ( + +
+ +
+
+ ); +}; + +export default MessageSearchFormWithoutSuggestions; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchPanel.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchPanel.tsx new file mode 100644 index 000000000000..3b29bf3ac6a3 --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchPanel.tsx @@ -0,0 +1,130 @@ +import type { ISearchProvider, ISetting } from '@rocket.chat/core-typings'; +import { Box } from '@rocket.chat/fuselage'; +import type { TranslationKey } from '@rocket.chat/ui-contexts'; +import { useUserId, useToastMessageDispatch, useMethod, useTranslation } from '@rocket.chat/ui-contexts'; +import { useMutation } from '@tanstack/react-query'; +import type { ReactElement } from 'react'; +import React, { useCallback, useMemo, useRef, useState } from 'react'; + +import BlazeTemplate from '../../../components/BlazeTemplate'; +import { useRoom } from '../../../contexts/RoomContext'; +import { useStateAsReactiveVar } from '../hooks/useStateAsReactiveVar'; +import MessageSearchFormWithSuggestions from './MessageSearchFormWithSuggestions'; +import MessageSearchFormWithoutSuggestions from './MessageSearchFormWithoutSuggestions'; + +type MessageSearchPanelProps = { + provider: ISearchProvider; +}; + +const MessageSearchPanel = ({ provider }: MessageSearchPanelProps): ReactElement => { + const uid = useUserId() ?? undefined; + const room = useRoom(); + + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const parentPayloadRef = useRef>({}); + const payloadRef = useRef>({}); + + const getPayload = () => ({ ...parentPayloadRef.current, ...payloadRef.current }); + + const searchMessages = useMethod('rocketchatSearch.search'); + const searchMessagesMutation = useMutation( + ['rooms', room._id, 'message-search', 'result', { uid, rid: room._id }] as const, + async ({ searchText }: { searchText: string }) => { + if (!searchText) { + return null; + } + + return searchMessages(searchText, { uid, rid: room._id }, getPayload()); + }, + { + onError: () => { + dispatchToastMessage({ + type: 'error', + message: t('Search_message_search_failed'), + }); + }, + }, + ); + + const settingsRef = useRef>({}); + + const [searchText, setSearchText] = useState(''); + + const search = useCallback( + (searchText: string) => { + payloadRef.current = {}; + setSearchText(searchText); + searchMessagesMutation.mutate({ searchText }); + }, + [searchMessagesMutation], + ); + + const { current: scope } = useRef({ + searching: useStateAsReactiveVar( + useMemo( + () => [searchMessagesMutation.isLoading, () => searchMessagesMutation.mutate({ searchText })], + [searchMessagesMutation, searchText], + ), + ), + result: useStateAsReactiveVar( + useMemo( + () => [searchMessagesMutation.data ?? undefined, () => searchMessagesMutation.mutate({ searchText })], + [searchMessagesMutation, searchText], + ), + ), + text: useStateAsReactiveVar([searchText, setSearchText]), + get settings() { + return settingsRef.current; + }, + set settings(value) { + settingsRef.current = value; + }, + get parentPayload() { + return parentPayloadRef.current; + }, + set parentPayload(value) { + parentPayloadRef.current = value; + }, + get payload() { + return payloadRef.current; + }, + search: () => searchMessagesMutation.mutate({ searchText }), + }); + + scope.search = () => searchMessagesMutation.mutate({ searchText }); + + const handleSearch = useCallback( + (searchText: string) => { + searchMessagesMutation.mutate({ searchText }); + }, + [searchMessagesMutation], + ); + + return ( + <> + {provider.description && ( +
+

+

+ )} + + + {provider.supportsSuggestions ? ( + + ) : ( + + )} + + + + + ); +}; + +export default MessageSearchPanel; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx new file mode 100644 index 000000000000..7cad86150f2b --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx @@ -0,0 +1,35 @@ +import type { ISearchProvider } from '@rocket.chat/core-typings'; +import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import React from 'react'; + +import BlazeTemplate from '../../../components/BlazeTemplate'; + +type MessageSearchSuggestionProps = { + provider: ISearchProvider; + suggestion: { action(): string } | { text: string }; + active: boolean; + onClick: (suggestion: { action(): string } | { text: string }) => void; + onHover: (suggestion: { action(): string } | { text: string }) => void; +}; + +const MessageSearchSuggestion = ({ provider, suggestion, active, onClick, onHover }: MessageSearchSuggestionProps) => { + const handleClick = useMutableCallback(() => { + onClick(suggestion); + }); + + const handleMouseEnter = useMutableCallback(() => { + onHover(suggestion); + }); + + return ( + + ); +}; + +export default MessageSearchSuggestion; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useSearchProviderQuery.ts b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useSearchProviderQuery.ts new file mode 100644 index 000000000000..8d364852102d --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useSearchProviderQuery.ts @@ -0,0 +1,14 @@ +import { useMethod } from '@rocket.chat/ui-contexts'; +import { useQuery } from '@tanstack/react-query'; + +export const useSearchProviderQuery = () => { + const getSearchProvider = useMethod('rocketchatSearch.getProvider'); + return useQuery(['search', 'provider'] as const, async () => { + const provider = await getSearchProvider(); + if (provider === undefined) { + throw new Error('Search provider not found'); + } + + return provider; + }); +}; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useStateAsReactiveVar.ts b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useStateAsReactiveVar.ts new file mode 100644 index 000000000000..259d1de87797 --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useStateAsReactiveVar.ts @@ -0,0 +1,31 @@ +import type { ReactiveVar } from 'meteor/reactive-var'; +import { Tracker } from 'meteor/tracker'; +import type { Dispatch, SetStateAction } from 'react'; +import { useEffect, useRef } from 'react'; + +export const useStateAsReactiveVar = ([value, setValue]: [value: T, setValue: Dispatch>]): ReactiveVar => { + const ref = useRef({ + value, + setValue, + dep: new Tracker.Dependency(), + }); + ref.current.value = value; + ref.current.setValue = setValue; + + const { current: reactiveVar } = useRef>({ + get() { + ref.current.dep.depend(); + return ref.current.value; + }, + set(newValue) { + ref.current.value = newValue; + ref.current.setValue(newValue); + }, + }); + + useEffect(() => { + ref.current.dep.changed(); + }, [value]); + + return reactiveVar; +}; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/index.ts b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/index.ts new file mode 100644 index 000000000000..c1c6f6c729cf --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/index.ts @@ -0,0 +1 @@ +export { default } from './MessageSearchTab'; diff --git a/apps/meteor/definition/externals/meteor/templating.d.ts b/apps/meteor/definition/externals/meteor/templating.d.ts index e4af1dd7c8b1..4bdf323d7bfb 100644 --- a/apps/meteor/definition/externals/meteor/templating.d.ts +++ b/apps/meteor/definition/externals/meteor/templating.d.ts @@ -1,20 +1,20 @@ import 'meteor/templating'; import type { Blaze } from 'meteor/blaze'; import type { ReactiveVar } from 'meteor/reactive-var'; -import type { IRoom } from '@rocket.chat/core-typings'; +import type { IRoom, ISetting } from '@rocket.chat/core-typings'; declare module 'meteor/blaze' { namespace Blaze { - interface Template { + interface Template> { events( eventsMap: Record< string, ( - this: TInstance, + this: any, event: { - [K in keyof JQuery.TriggeredEvent]: any; + [K in keyof JQuery.TriggeredEvent | keyof JQuery.KeyboardEventBase]: any; }, - instance: TInstance, + instance: T, ) => void >, ): void; @@ -31,7 +31,15 @@ declare module 'meteor/templating' { type BlazeTemplates = { requiresPermission: BlazeTemplate; ChatpalAdmin: BlazeTemplate; - ChatpalSearchResultTemplate: BlazeTemplate; + ChatpalSearchResultTemplate: BlazeTemplate<{ + searching: ReactiveVar; + result: ReactiveVar; + text: ReactiveVar; + settings: Record; + parentPayload: Record; + payload: Record; + search(): void; + }>; ChatpalSearchSingleTemplate: BlazeTemplate; ChatpalSearchSingleUser: BlazeTemplate; ChatpalSearchSingleRoom: BlazeTemplate; @@ -57,21 +65,20 @@ declare module 'meteor/templating' { oembedUrlWidget: BlazeTemplate; oembedVideoWidget: BlazeTemplate; oembedYoutubeWidget: BlazeTemplate; - DefaultSearchResultTemplate: BlazeTemplate; + DefaultSearchResultTemplate: BlazeTemplate<{ + searching: ReactiveVar; + result: ReactiveVar; + text: ReactiveVar; + settings: Record; + parentPayload: Record; + payload: Record; + search(): void; + }>; DefaultSuggestionItemTemplate: BlazeTemplate; - RocketSearch: BlazeTemplate< - { - rid: IRoom['_id']; - }, - { - provider: ReactiveVar; - isActive: ReactiveVar; - error: ReactiveVar; - suggestions: ReactiveVar; - suggestionActive: ReactiveVar; - } - >; - icon: BlazeTemplate; + icon: BlazeTemplate<{ + block: string; + icon: string; + }>; popupList: BlazeTemplate; popupList_default: BlazeTemplate; popupList_item_default: BlazeTemplate; @@ -114,10 +121,18 @@ declare module 'meteor/templating' { messageThread: BlazeTemplate; messagePopup: BlazeTemplate; messagePopupChannel: BlazeTemplate; - messagePopupConfig: BlazeTemplate; + messagePopupConfig: BlazeTemplate<{ + tmid: IMessage['_id']; + rid: IRoom['_id']; + getInput: () => HTMLTextAreaElement | null; + }>; messagePopupEmoji: BlazeTemplate; messagePopupSlashCommand: BlazeTemplate; - messagePopupSlashCommandPreview: BlazeTemplate; + messagePopupSlashCommandPreview: BlazeTemplate<{ + tmid: IMessage['_id']; + rid: IRoom['_id']; + getInput: () => HTMLTextAreaElement | null; + }>; messagePopupUser: BlazeTemplate; collapseArrow: BlazeTemplate; rc_modal: BlazeTemplate; diff --git a/packages/core-typings/src/index.ts b/packages/core-typings/src/index.ts index b18656932b3f..4c509fcdbf0b 100644 --- a/packages/core-typings/src/index.ts +++ b/packages/core-typings/src/index.ts @@ -117,3 +117,5 @@ export * from './VideoConferenceCapabilities'; export * from './VideoConferenceOptions'; export * from './SpotlightUser'; + +export * from './search'; diff --git a/packages/core-typings/src/search/ISearchProvider.ts b/packages/core-typings/src/search/ISearchProvider.ts new file mode 100644 index 000000000000..864192a95e73 --- /dev/null +++ b/packages/core-typings/src/search/ISearchProvider.ts @@ -0,0 +1,11 @@ +import type { ISetting } from '../ISetting'; + +export interface ISearchProvider { + key: string; + description: string; + icon: string; + resultTemplate: string; + supportsSuggestions: boolean; + suggestionItemTemplate?: string; + settings: Record; +} diff --git a/packages/core-typings/src/search/index.ts b/packages/core-typings/src/search/index.ts new file mode 100644 index 000000000000..51b4e5008e47 --- /dev/null +++ b/packages/core-typings/src/search/index.ts @@ -0,0 +1 @@ +export * from './ISearchProvider'; diff --git a/packages/ui-contexts/src/ServerContext/methods.ts b/packages/ui-contexts/src/ServerContext/methods.ts index 16c1fd18f5b3..3f4fd7767b8c 100644 --- a/packages/ui-contexts/src/ServerContext/methods.ts +++ b/packages/ui-contexts/src/ServerContext/methods.ts @@ -5,6 +5,7 @@ import type { IMessage, IPermission, IRoom, + ISearchProvider, ISetting, ISubscription, ISupportedLanguage, @@ -267,33 +268,21 @@ export interface ServerMethods { 'private-settings/get': (updatedSince?: Date) => ISetting[] | { update: ISetting[]; remove: ISetting[] }; 'pinMessage': (message: IMessage) => void; 'unpinMessage': (message: IMessage) => void; - 'rocketchatSearch.getProvider': () => - | { - key: string; - description: TranslationKey; - icon: string; - resultTemplate: string; - supportsSuggestions: boolean; - suggestionItemTemplate: string | undefined; - settings: unknown[]; - } - | undefined; + 'rocketchatSearch.getProvider': () => ISearchProvider | undefined; 'rocketchatSearch.search': ( text: string, - context: { uid: IUser['_id']; rid: IRoom['_id'] }, + context: { uid?: IUser['_id']; rid: IRoom['_id'] }, payload: unknown, ) => { - message: IMessage; - room: IRoom; + message: { + docs: IMessage[]; + }; }; 'rocketchatSearch.suggest': ( text: string, - context: { uid: IUser['_id']; rid: IRoom['_id'] }, + context: { uid?: IUser['_id']; rid: IRoom['_id'] }, payload: unknown, - ) => { - message: IMessage; - room: IRoom; - }; + ) => ({ action(): string } | { text: string })[]; } export type ServerMethodName = keyof ServerMethods; From a2e9c927d44f7ca39ff995eca69e200054b5551c Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Mon, 13 Feb 2023 10:46:47 -0300 Subject: [PATCH 03/10] Refactor suggestions --- .../meteor/app/chatpal-search/client/index.js | 7 ----- .../meteor/app/chatpal-search/client/index.ts | 5 ++++ .../client/template/suggestion.html | 9 ------ .../client/template/suggestion.js | 9 ------ apps/meteor/app/search/client/index.ts | 1 - .../search/client/provider/suggestion.html | 5 ---- .../MessageSearchFormWithSuggestions.tsx | 14 +++------ .../components/MessageSearchSuggestion.tsx | 30 ++++++++++++++----- .../lib/ChatpalMessageSearchSuggestion.ts | 4 +++ .../lib/DefaultMessageSearchSuggestion.ts | 3 ++ .../lib/MessageSearchSuggestion.ts | 4 +++ .../MessageSearchTab/lib/getSuggestionText.ts | 9 ++++++ .../externals/meteor/templating.d.ts | 2 +- .../ui-contexts/src/ServerContext/methods.ts | 2 +- 14 files changed, 54 insertions(+), 50 deletions(-) delete mode 100644 apps/meteor/app/chatpal-search/client/index.js create mode 100644 apps/meteor/app/chatpal-search/client/index.ts delete mode 100644 apps/meteor/app/chatpal-search/client/template/suggestion.html delete mode 100644 apps/meteor/app/chatpal-search/client/template/suggestion.js delete mode 100644 apps/meteor/app/search/client/provider/suggestion.html create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/ChatpalMessageSearchSuggestion.ts create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/DefaultMessageSearchSuggestion.ts create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/MessageSearchSuggestion.ts create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/getSuggestionText.ts diff --git a/apps/meteor/app/chatpal-search/client/index.js b/apps/meteor/app/chatpal-search/client/index.js deleted file mode 100644 index 6bf6d22ad237..000000000000 --- a/apps/meteor/app/chatpal-search/client/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import './template/admin.html'; -import './template/result.html'; -import './template/suggestion.html'; -import './template/admin'; -import './template/result'; -import './template/suggestion'; -import './style.css'; diff --git a/apps/meteor/app/chatpal-search/client/index.ts b/apps/meteor/app/chatpal-search/client/index.ts new file mode 100644 index 000000000000..1317676eab11 --- /dev/null +++ b/apps/meteor/app/chatpal-search/client/index.ts @@ -0,0 +1,5 @@ +import './template/admin.html'; +import './template/result.html'; +import './template/admin.js'; +import './template/result.js'; +import './style.css'; diff --git a/apps/meteor/app/chatpal-search/client/template/suggestion.html b/apps/meteor/app/chatpal-search/client/template/suggestion.html deleted file mode 100644 index b003193c8af3..000000000000 --- a/apps/meteor/app/chatpal-search/client/template/suggestion.html +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/apps/meteor/app/chatpal-search/client/template/suggestion.js b/apps/meteor/app/chatpal-search/client/template/suggestion.js deleted file mode 100644 index 8f6e64c8775f..000000000000 --- a/apps/meteor/app/chatpal-search/client/template/suggestion.js +++ /dev/null @@ -1,9 +0,0 @@ -import { Template } from 'meteor/templating'; - -Template.ChatpalSuggestionItemTemplate.onCreated(function () { - if (this.data.type === 'link') { - this.data.action = () => { - console.log('an example for an external link'); - }; - } -}); diff --git a/apps/meteor/app/search/client/index.ts b/apps/meteor/app/search/client/index.ts index 15941258e4fd..0c10dea486a4 100644 --- a/apps/meteor/app/search/client/index.ts +++ b/apps/meteor/app/search/client/index.ts @@ -1,4 +1,3 @@ -import './provider/suggestion.html'; import './provider/result.html'; import './provider/result.js'; import './style/style.css'; diff --git a/apps/meteor/app/search/client/provider/suggestion.html b/apps/meteor/app/search/client/provider/suggestion.html deleted file mode 100644 index 1aeaf6469ca0..000000000000 --- a/apps/meteor/app/search/client/provider/suggestion.html +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx index 4920fa5e9170..7c58e670ba3d 100644 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx @@ -9,16 +9,10 @@ import { useForm } from 'react-hook-form'; import BlazeTemplate from '../../../components/BlazeTemplate'; import { useRoom } from '../../../contexts/RoomContext'; +import type { MessageSearchSuggestion as MessageSearchSuggestionType } from '../lib/MessageSearchSuggestion'; +import { getSuggestionText } from '../lib/getSuggestionText'; import MessageSearchSuggestion from './MessageSearchSuggestion'; -const getSuggestionText = (suggestion?: { action(): string } | { text: string }): string | undefined => { - if (!suggestion) { - return undefined; - } - - return 'text' in suggestion ? suggestion.text : suggestion.action(); -}; - type MessageSearchFormWithSuggestionsProps = { provider: ISearchProvider; getPayload: () => Record; @@ -106,7 +100,7 @@ const MessageSearchFormWithSuggestions = ({ provider, getPayload, onSearch }: Me } }); - const handleSuggestionClick = useMutableCallback((suggestion: { action(): string } | { text: string }) => { + const handleSuggestionClick = useMutableCallback((suggestion: MessageSearchSuggestionType) => { const suggestionText = getSuggestionText(suggestion); if (!suggestionText) { return; @@ -117,7 +111,7 @@ const MessageSearchFormWithSuggestions = ({ provider, getPayload, onSearch }: Me suggestionsMutation.reset(); }); - const handleSuggestionHover = useMutableCallback((suggestion: { action(): string } | { text: string }) => { + const handleSuggestionHover = useMutableCallback((suggestion: MessageSearchSuggestionType) => { setSuggestionIndex(suggestionsMutation.data?.indexOf(suggestion) ?? 0); }); diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx index 7cad86150f2b..a33c881166b5 100644 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx @@ -1,15 +1,18 @@ import type { ISearchProvider } from '@rocket.chat/core-typings'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; import BlazeTemplate from '../../../components/BlazeTemplate'; +import type { MessageSearchSuggestion as MessageSearchSuggestionType } from '../lib/MessageSearchSuggestion'; +import { getSuggestionText } from '../lib/getSuggestionText'; type MessageSearchSuggestionProps = { provider: ISearchProvider; - suggestion: { action(): string } | { text: string }; + suggestion: MessageSearchSuggestionType; active: boolean; - onClick: (suggestion: { action(): string } | { text: string }) => void; - onHover: (suggestion: { action(): string } | { text: string }) => void; + onClick: (suggestion: MessageSearchSuggestionType) => void; + onHover: (suggestion: MessageSearchSuggestionType) => void; }; const MessageSearchSuggestion = ({ provider, suggestion, active, onClick, onHover }: MessageSearchSuggestionProps) => { @@ -21,14 +24,27 @@ const MessageSearchSuggestion = ({ provider, suggestion, active, onClick, onHove onHover(suggestion); }); + const t = useTranslation(); + return ( - + > + {provider.suggestionItemTemplate === 'ChatpalSuggestionItemTemplate' && ( +
+ {getSuggestionText(suggestion)} + + {t('Chatpal_run_search')} + + +
+ )} + {provider.suggestionItemTemplate === 'DefaultSuggestionItemTemplate' && ( +
{getSuggestionText(suggestion)}
+ )} + ); }; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/ChatpalMessageSearchSuggestion.ts b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/ChatpalMessageSearchSuggestion.ts new file mode 100644 index 000000000000..b1c0736ee2bc --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/ChatpalMessageSearchSuggestion.ts @@ -0,0 +1,4 @@ +export type ChatpalMessageSearchSuggestion = { + type: string; + action(): string; +}; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/DefaultMessageSearchSuggestion.ts b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/DefaultMessageSearchSuggestion.ts new file mode 100644 index 000000000000..13eacdee1acf --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/DefaultMessageSearchSuggestion.ts @@ -0,0 +1,3 @@ +export type DefaultMessageSearchSuggestion = { + text: string; +}; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/MessageSearchSuggestion.ts b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/MessageSearchSuggestion.ts new file mode 100644 index 000000000000..250689892f6f --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/MessageSearchSuggestion.ts @@ -0,0 +1,4 @@ +import type { ChatpalMessageSearchSuggestion } from './ChatpalMessageSearchSuggestion'; +import type { DefaultMessageSearchSuggestion } from './DefaultMessageSearchSuggestion'; + +export type MessageSearchSuggestion = DefaultMessageSearchSuggestion | ChatpalMessageSearchSuggestion; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/getSuggestionText.ts b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/getSuggestionText.ts new file mode 100644 index 000000000000..16a04ad89eff --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/getSuggestionText.ts @@ -0,0 +1,9 @@ +import type { MessageSearchSuggestion as MessageSearchSuggestionType } from './MessageSearchSuggestion'; + +export const getSuggestionText = (suggestion?: MessageSearchSuggestionType): string | undefined => { + if (!suggestion) { + return undefined; + } + + return 'text' in suggestion ? suggestion.text : suggestion.action(); +}; diff --git a/apps/meteor/definition/externals/meteor/templating.d.ts b/apps/meteor/definition/externals/meteor/templating.d.ts index 4bdf323d7bfb..4c2ef251e4fd 100644 --- a/apps/meteor/definition/externals/meteor/templating.d.ts +++ b/apps/meteor/definition/externals/meteor/templating.d.ts @@ -76,7 +76,7 @@ declare module 'meteor/templating' { }>; DefaultSuggestionItemTemplate: BlazeTemplate; icon: BlazeTemplate<{ - block: string; + block?: string; icon: string; }>; popupList: BlazeTemplate; diff --git a/packages/ui-contexts/src/ServerContext/methods.ts b/packages/ui-contexts/src/ServerContext/methods.ts index 3f4fd7767b8c..5a99544fc61f 100644 --- a/packages/ui-contexts/src/ServerContext/methods.ts +++ b/packages/ui-contexts/src/ServerContext/methods.ts @@ -282,7 +282,7 @@ export interface ServerMethods { text: string, context: { uid?: IUser['_id']; rid: IRoom['_id'] }, payload: unknown, - ) => ({ action(): string } | { text: string })[]; + ) => ({ type: string; action(): string } | { text: string })[]; } export type ServerMethodName = keyof ServerMethods; From 0d3c9af2f85ed20c4639601ab73c0b61b39465a0 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Mon, 13 Feb 2023 17:30:43 -0300 Subject: [PATCH 04/10] Get rid of result templates --- apps/meteor/app/search/client/index.ts | 2 - .../app/search/client/provider/result.html | 31 ---- .../app/search/client/provider/result.js | 141 ------------------ apps/meteor/app/search/client/style/style.css | 2 + .../app/ui-utils/client/lib/MessageAction.ts | 3 +- .../app/ui-utils/client/lib/messageContext.ts | 3 - apps/meteor/client/lib/utils/jumpToMessage.ts | 17 ++- .../client/startup/actionButtons/index.ts | 1 + .../actionButtons/jumpToSearchMessage.ts | 20 +++ .../components/MessageSearch.tsx | 130 ++++++++++++++++ .../MessageSearchFormWithSuggestions.tsx | 5 +- .../components/MessageSearchPanel.tsx | 106 ++----------- .../components/MessageSearchSuggestion.tsx | 13 -- .../hooks/useMessageSearchQuery.ts | 27 ++++ .../externals/meteor/templating.d.ts | 38 +++-- 15 files changed, 236 insertions(+), 303 deletions(-) delete mode 100644 apps/meteor/app/search/client/provider/result.html delete mode 100644 apps/meteor/app/search/client/provider/result.js create mode 100644 apps/meteor/client/startup/actionButtons/jumpToSearchMessage.ts create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearch.tsx create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useMessageSearchQuery.ts diff --git a/apps/meteor/app/search/client/index.ts b/apps/meteor/app/search/client/index.ts index 0c10dea486a4..ac8fac5e940a 100644 --- a/apps/meteor/app/search/client/index.ts +++ b/apps/meteor/app/search/client/index.ts @@ -1,3 +1 @@ -import './provider/result.html'; -import './provider/result.js'; import './style/style.css'; diff --git a/apps/meteor/app/search/client/provider/result.html b/apps/meteor/app/search/client/provider/result.html deleted file mode 100644 index ab0624e35c65..000000000000 --- a/apps/meteor/app/search/client/provider/result.html +++ /dev/null @@ -1,31 +0,0 @@ - diff --git a/apps/meteor/app/search/client/provider/result.js b/apps/meteor/app/search/client/provider/result.js deleted file mode 100644 index 05f8ba489f79..000000000000 --- a/apps/meteor/app/search/client/provider/result.js +++ /dev/null @@ -1,141 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Tracker } from 'meteor/tracker'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { FlowRouter } from 'meteor/kadira:flow-router'; -import { Session } from 'meteor/session'; -import { Template } from 'meteor/templating'; -import _ from 'underscore'; - -import { createMessageContext } from '../../../ui-utils/client/lib/messageContext'; -import { MessageAction, RoomHistoryManager } from '../../../ui-utils'; -import { messageArgs } from '../../../../client/lib/utils/messageArgs'; -import { Rooms } from '../../../models/client'; -import { getCommonRoomEvents } from '../../../ui/client/views/app/lib/getCommonRoomEvents'; -import { goToRoomById } from '../../../../client/lib/utils/goToRoomById'; - -import './result.html'; - -Meteor.startup(function () { - MessageAction.addButton({ - id: 'jump-to-search-message', - icon: 'jump', - label: 'Jump_to_message', - context: ['search'], - action(_, props) { - const { message = messageArgs(this).msg } = props; - if (message.tmid) { - return FlowRouter.go( - FlowRouter.getRouteName(), - { - tab: 'thread', - context: message.tmid, - rid: message.rid, - name: Rooms.findOne({ _id: message.rid }).name, - }, - { - ...FlowRouter.current().queryParams, - jump: message._id, - }, - ); - } - - if (Session.get('openedRoom') === message.rid) { - return RoomHistoryManager.getSurroundingMessages(message); - } - - goToRoomById(message.rid); - // RocketChat.MessageAction.hideDropDown(); - - if (window.matchMedia('(max-width: 500px)').matches) { - Template.instance().tabBar.close(); - } - - window.setTimeout(() => { - RoomHistoryManager.getSurroundingMessages(message); - }, 400); - // 400ms is popular among game devs as a good delay before transition starts - // ie. 50, 100, 200, 400, 800 are the favored timings - }, - order: 100, - group: 'menu', - }); -}); - -Template.DefaultSearchResultTemplate.onRendered(function () { - const list = this.firstNode.parentNode.querySelector('.rocket-default-search-results'); - this.autorun(() => { - const result = this.data.result.get(); - if (result && this.hasMore.get()) { - Tracker.afterFlush(() => { - if (list.scrollHeight < list.offsetHeight) { - this.data.payload.limit = (this.data.payload.limit || this.pageSize) + this.pageSize; - this.data.search(); - } - }); - } - }); -}); - -Template.DefaultSearchResultTemplate.onCreated(function () { - // paging - this.pageSize = this.data.settings.PageSize; - - // global search - this.globalSearchEnabled = this.data.settings.GlobalSearchEnabled; - // default value for global search - this.data.parentPayload.searchAll = false; - - this.hasMore = new ReactiveVar(true); - - this.autorun(() => { - const result = this.data.result.get(); - this.hasMore.set(!(result && result.message.docs.length < (this.data.payload.limit || this.pageSize))); - }); -}); - -Template.DefaultSearchResultTemplate.events({ - ...getCommonRoomEvents(), - 'change #global-search'(e, t) { - t.data.parentPayload.searchAll = e.target.checked; - t.data.payload.limit = t.pageSize; - t.data.result.set(undefined); - t.data.search(); - }, - 'scroll .rocket-default-search-results': _.throttle(function (e, t) { - if (e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight && t.hasMore.get()) { - t.data.payload.limit = (t.data.payload.limit || t.pageSize) + t.pageSize; - t.data.search(); - } - }, 200), -}); - -Template.DefaultSearchResultTemplate.helpers({ - result() { - return Template.instance().data.result.get(); - }, - globalSearchEnabled() { - return Template.instance().globalSearchEnabled; - }, - searching() { - return Template.instance().data.searching.get(); - }, - hasMore() { - return Template.instance().hasMore.get(); - }, - messageParse(msg) { - const text = Template.instance().data.text.get(); - msg.searchedText = text; - return { customClass: 'search', actionContext: 'search', ...msg, groupable: false }; - }, - messageContext() { - const result = createMessageContext.call(this, { rid: Session.get('openedRoom') }); - return { - ...result, - settings: { - ...result.settings, - showReplyButton: false, - showreply: false, - }, - }; - }, -}); diff --git a/apps/meteor/app/search/client/style/style.css b/apps/meteor/app/search/client/style/style.css index 1f3908b98c88..f16cdbb58b89 100644 --- a/apps/meteor/app/search/client/style/style.css +++ b/apps/meteor/app/search/client/style/style.css @@ -26,6 +26,8 @@ .rocket-default-search-results .list .message { padding-right: 8px !important; padding-left: 70px !important; + + list-style: none; } .rocket-default-search-results .js-list { diff --git a/apps/meteor/app/ui-utils/client/lib/MessageAction.ts b/apps/meteor/app/ui-utils/client/lib/MessageAction.ts index 1ed1b5253281..7260b6c85012 100644 --- a/apps/meteor/app/ui-utils/client/lib/MessageAction.ts +++ b/apps/meteor/app/ui-utils/client/lib/MessageAction.ts @@ -43,7 +43,8 @@ export type MessageActionContext = | 'starred' | 'mentions' | 'federated' - | 'videoconf'; + | 'videoconf' + | 'search'; type MessageActionConditionProps = { message: IMessage; diff --git a/apps/meteor/app/ui-utils/client/lib/messageContext.ts b/apps/meteor/app/ui-utils/client/lib/messageContext.ts index 14f519d7d348..dec1c6f958f5 100644 --- a/apps/meteor/app/ui-utils/client/lib/messageContext.ts +++ b/apps/meteor/app/ui-utils/client/lib/messageContext.ts @@ -2,7 +2,6 @@ import { Meteor } from 'meteor/meteor'; import { Template } from 'meteor/templating'; import { Tracker } from 'meteor/tracker'; import type { IRoom, ISubscription, IUser } from '@rocket.chat/core-typings'; -import type { Blaze } from 'meteor/blaze'; import { Subscriptions, Rooms, Users } from '../../../models/client'; import { hasPermission } from '../../../authorization/client'; @@ -77,8 +76,6 @@ export const createMessageContext = ({ rid?: IRoom['_id']; room?: Omit; subscription?: Pick; - instance?: Blaze.TemplateInstance | ((actionId: string, context: string) => void); - embeddedLayout?: boolean; translateLanguage?: unknown; autoImageLoad?: unknown; saveMobileBandwidth?: unknown; diff --git a/apps/meteor/client/lib/utils/jumpToMessage.ts b/apps/meteor/client/lib/utils/jumpToMessage.ts index f80f6a224cb2..1f1807b6535a 100644 --- a/apps/meteor/client/lib/utils/jumpToMessage.ts +++ b/apps/meteor/client/lib/utils/jumpToMessage.ts @@ -3,10 +3,11 @@ import { FlowRouter } from 'meteor/kadira:flow-router'; import { ChatRoom } from '../../../app/models/client'; import { RoomHistoryManager } from '../../../app/ui-utils/client'; +import { goToRoomById } from './goToRoomById'; -export const jumpToMessage = (message: IMessage) => { +export const jumpToMessage = async (message: IMessage) => { if (matchMedia('(max-width: 500px)').matches) { - (Template.instance() as any).tabBar.close(); + (Template.instance() as any)?.tabBar?.close(); } if (message.tmid) { @@ -25,5 +26,15 @@ export const jumpToMessage = (message: IMessage) => { }, ); } - return RoomHistoryManager.getSurroundingMessages(message); + + if (Session.get('openedRoom') === message.rid) { + RoomHistoryManager.getSurroundingMessages(message); + return; + } + + await goToRoomById(message.rid); + + setTimeout(() => { + RoomHistoryManager.getSurroundingMessages(message); + }, 400); }; diff --git a/apps/meteor/client/startup/actionButtons/index.ts b/apps/meteor/client/startup/actionButtons/index.ts index b238cb531ecd..18aede35b215 100644 --- a/apps/meteor/client/startup/actionButtons/index.ts +++ b/apps/meteor/client/startup/actionButtons/index.ts @@ -1,5 +1,6 @@ import './jumpToMessage'; import './jumpToPinMessage'; +import './jumpToSearchMessage'; import './jumpToStarMessage'; import './permalinkPinned'; import './permalinkStar'; diff --git a/apps/meteor/client/startup/actionButtons/jumpToSearchMessage.ts b/apps/meteor/client/startup/actionButtons/jumpToSearchMessage.ts new file mode 100644 index 000000000000..da488907e011 --- /dev/null +++ b/apps/meteor/client/startup/actionButtons/jumpToSearchMessage.ts @@ -0,0 +1,20 @@ +import { Meteor } from 'meteor/meteor'; + +import { MessageAction } from '../../../app/ui-utils/client'; +import { jumpToMessage } from '../../lib/utils/jumpToMessage'; +import { messageArgs } from '../../lib/utils/messageArgs'; + +Meteor.startup(() => { + MessageAction.addButton({ + id: 'jump-to-search-message', + icon: 'jump', + label: 'Jump_to_message', + context: ['search'], + async action(_, props) { + const { message = messageArgs(this).msg } = props; + await jumpToMessage(message); + }, + order: 100, + group: 'menu', + }); +}); diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearch.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearch.tsx new file mode 100644 index 000000000000..4fb6e7f98cfc --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearch.tsx @@ -0,0 +1,130 @@ +import { States, StatesIcon, StatesTitle } from '@rocket.chat/fuselage'; +import { useTranslation } from '@rocket.chat/ui-contexts'; +import type { ReactElement, ChangeEvent, UIEvent } from 'react'; +import React, { useEffect, useRef, useMemo, useState } from 'react'; + +import { createMessageContext } from '../../../../../../app/ui-utils/client/lib/messageContext'; +import { withThrottling } from '../../../../../../lib/utils/highOrderFunctions'; +import BlazeTemplate from '../../../components/BlazeTemplate'; +import LoadingMessagesIndicator from '../../../components/body/LoadingMessagesIndicator'; +import { useRoom } from '../../../contexts/RoomContext'; +import { useMessageSearchQuery } from '../hooks/useMessageSearchQuery'; + +type MessageSearchProps = { + settings: { + GlobalSearchEnabled: boolean; + PageSize: number; + }; + searchText: string; +}; + +const MessageSearch = ({ settings, searchText }: MessageSearchProps): ReactElement => { + const [payload, setPayload] = useState(() => ({ + limit: settings.PageSize, + searchAll: false, + })); + const messageSearchQuery = useMessageSearchQuery({ searchText, ...payload }); + + const hasMore = !!messageSearchQuery.data && !(messageSearchQuery.data?.message?.docs.length < payload.limit); + + const handleToggleGlobalSearch = (event: ChangeEvent) => { + setPayload({ + limit: settings.PageSize, + searchAll: event.target.checked, + }); + }; + + const scrollHandler = useMemo(() => { + if (!hasMore) { + return undefined; + } + + const throttledTestAndSet = withThrottling({ wait: 200 })((element: HTMLElement) => { + if (element.scrollTop >= element.scrollHeight - element.clientHeight) { + setPayload(({ limit, ...rest }) => ({ ...rest, limit: limit + settings.PageSize })); + } + }); + + return (event: UIEvent) => { + throttledTestAndSet(event.currentTarget); + }; + }, [hasMore, settings.PageSize]); + + const scrollListRef = useRef(null); + + useEffect(() => { + const element = scrollListRef.current; + if (!element) { + return; + } + + if (element.scrollTop >= element.scrollHeight - element.clientHeight) { + setPayload(({ limit, ...rest }) => ({ ...rest, limit: limit + settings.PageSize })); + } + }, [settings.PageSize]); + + const room = useRoom(); + const messageContext = useMemo(() => { + const context = createMessageContext({ rid: room._id }); + return { + ...context, + settings: { + ...context.settings, + showReplyButton: false, + showreply: false, + }, + }; + }, [room._id]); + + const t = useTranslation(); + + return ( +
+
+
+ {settings.GlobalSearchEnabled && ( + + )} +
+
+
+ {messageSearchQuery.data && + (messageSearchQuery.data?.message?.docs.length ? ( +
+
+ {messageSearchQuery.data?.message?.docs.map((message) => ( + + ))} +
+
+ ) : ( + + + {t('No_results_found')} + + ))} +
{searchText && messageSearchQuery.isLoading && }
+
+
+ ); +}; + +export default MessageSearch; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx index 7c58e670ba3d..4129929a1b74 100644 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx @@ -15,11 +15,10 @@ import MessageSearchSuggestion from './MessageSearchSuggestion'; type MessageSearchFormWithSuggestionsProps = { provider: ISearchProvider; - getPayload: () => Record; onSearch: (searchText: string) => void; }; -const MessageSearchFormWithSuggestions = ({ provider, getPayload, onSearch }: MessageSearchFormWithSuggestionsProps) => { +const MessageSearchFormWithSuggestions = ({ provider, onSearch }: MessageSearchFormWithSuggestionsProps) => { const { handleSubmit, register, setFocus, setValue } = useForm({ defaultValues: { 'message-search': '', @@ -41,7 +40,7 @@ const MessageSearchFormWithSuggestions = ({ provider, getPayload, onSearch }: Me const suggestionsMutation = useMutation( ['rooms', room._id, 'message-search', 'suggestions', { uid, rid: room._id }] as const, async ({ searchText }: { searchText: string }) => { - const suggestions = await getSearchSuggestions(searchText, { rid: room._id, uid }, getPayload()); + const suggestions = await getSearchSuggestions(searchText, { rid: room._id, uid }, {}); if (!suggestions || suggestions.length === 0) { return [{ text: 'Test' }]; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchPanel.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchPanel.tsx index 3b29bf3ac6a3..f3d2d46e5f19 100644 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchPanel.tsx +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchPanel.tsx @@ -1,14 +1,11 @@ -import type { ISearchProvider, ISetting } from '@rocket.chat/core-typings'; +import type { ISearchProvider } from '@rocket.chat/core-typings'; import { Box } from '@rocket.chat/fuselage'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import { useUserId, useToastMessageDispatch, useMethod, useTranslation } from '@rocket.chat/ui-contexts'; -import { useMutation } from '@tanstack/react-query'; +import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; -import React, { useCallback, useMemo, useRef, useState } from 'react'; +import React, { useState, useCallback } from 'react'; -import BlazeTemplate from '../../../components/BlazeTemplate'; -import { useRoom } from '../../../contexts/RoomContext'; -import { useStateAsReactiveVar } from '../hooks/useStateAsReactiveVar'; +import MessageSearch from './MessageSearch'; import MessageSearchFormWithSuggestions from './MessageSearchFormWithSuggestions'; import MessageSearchFormWithoutSuggestions from './MessageSearchFormWithoutSuggestions'; @@ -17,90 +14,13 @@ type MessageSearchPanelProps = { }; const MessageSearchPanel = ({ provider }: MessageSearchPanelProps): ReactElement => { - const uid = useUserId() ?? undefined; - const room = useRoom(); - - const t = useTranslation(); - const dispatchToastMessage = useToastMessageDispatch(); - - const parentPayloadRef = useRef>({}); - const payloadRef = useRef>({}); - - const getPayload = () => ({ ...parentPayloadRef.current, ...payloadRef.current }); - - const searchMessages = useMethod('rocketchatSearch.search'); - const searchMessagesMutation = useMutation( - ['rooms', room._id, 'message-search', 'result', { uid, rid: room._id }] as const, - async ({ searchText }: { searchText: string }) => { - if (!searchText) { - return null; - } - - return searchMessages(searchText, { uid, rid: room._id }, getPayload()); - }, - { - onError: () => { - dispatchToastMessage({ - type: 'error', - message: t('Search_message_search_failed'), - }); - }, - }, - ); - - const settingsRef = useRef>({}); - const [searchText, setSearchText] = useState(''); - const search = useCallback( - (searchText: string) => { - payloadRef.current = {}; - setSearchText(searchText); - searchMessagesMutation.mutate({ searchText }); - }, - [searchMessagesMutation], - ); - - const { current: scope } = useRef({ - searching: useStateAsReactiveVar( - useMemo( - () => [searchMessagesMutation.isLoading, () => searchMessagesMutation.mutate({ searchText })], - [searchMessagesMutation, searchText], - ), - ), - result: useStateAsReactiveVar( - useMemo( - () => [searchMessagesMutation.data ?? undefined, () => searchMessagesMutation.mutate({ searchText })], - [searchMessagesMutation, searchText], - ), - ), - text: useStateAsReactiveVar([searchText, setSearchText]), - get settings() { - return settingsRef.current; - }, - set settings(value) { - settingsRef.current = value; - }, - get parentPayload() { - return parentPayloadRef.current; - }, - set parentPayload(value) { - parentPayloadRef.current = value; - }, - get payload() { - return payloadRef.current; - }, - search: () => searchMessagesMutation.mutate({ searchText }), - }); - - scope.search = () => searchMessagesMutation.mutate({ searchText }); + const handleSearch = useCallback((searchText: string) => { + setSearchText(searchText); + }, []); - const handleSearch = useCallback( - (searchText: string) => { - searchMessagesMutation.mutate({ searchText }); - }, - [searchMessagesMutation], - ); + const t = useTranslation(); return ( <> @@ -112,17 +32,15 @@ const MessageSearchPanel = ({ provider }: MessageSearchPanelProps): ReactElement {provider.supportsSuggestions ? ( - + ) : ( )} - + {provider.resultTemplate === 'DefaultSearchResultTemplate' && ( + + )} ); }; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx index a33c881166b5..52491bcb4f10 100644 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx @@ -1,9 +1,7 @@ import type { ISearchProvider } from '@rocket.chat/core-typings'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; -import BlazeTemplate from '../../../components/BlazeTemplate'; import type { MessageSearchSuggestion as MessageSearchSuggestionType } from '../lib/MessageSearchSuggestion'; import { getSuggestionText } from '../lib/getSuggestionText'; @@ -24,23 +22,12 @@ const MessageSearchSuggestion = ({ provider, suggestion, active, onClick, onHove onHover(suggestion); }); - const t = useTranslation(); - return (
- {provider.suggestionItemTemplate === 'ChatpalSuggestionItemTemplate' && ( -
- {getSuggestionText(suggestion)} - - {t('Chatpal_run_search')} - - -
- )} {provider.suggestionItemTemplate === 'DefaultSuggestionItemTemplate' && (
{getSuggestionText(suggestion)}
)} diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useMessageSearchQuery.ts b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useMessageSearchQuery.ts new file mode 100644 index 000000000000..4db3a2556d25 --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useMessageSearchQuery.ts @@ -0,0 +1,27 @@ +import { useMethod, useToastMessageDispatch, useTranslation, useUserId } from '@rocket.chat/ui-contexts'; +import { useQuery } from '@tanstack/react-query'; + +import { useRoom } from '../../../contexts/RoomContext'; + +export const useMessageSearchQuery = ({ searchText, limit, searchAll }: { searchText: string; limit: number; searchAll: boolean }) => { + const uid = useUserId() ?? undefined; + const room = useRoom(); + + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const searchMessages = useMethod('rocketchatSearch.search'); + return useQuery( + ['rooms', room._id, 'message-search', { uid, rid: room._id, searchText, limit }] as const, + () => searchMessages(searchText, { uid, rid: room._id }, { limit, searchAll }), + { + enabled: !!searchText, + onError: () => { + dispatchToastMessage({ + type: 'error', + message: t('Search_message_search_failed'), + }); + }, + }, + ); +}; diff --git a/apps/meteor/definition/externals/meteor/templating.d.ts b/apps/meteor/definition/externals/meteor/templating.d.ts index 4c2ef251e4fd..ba371c96a412 100644 --- a/apps/meteor/definition/externals/meteor/templating.d.ts +++ b/apps/meteor/definition/externals/meteor/templating.d.ts @@ -1,7 +1,7 @@ import 'meteor/templating'; import type { Blaze } from 'meteor/blaze'; import type { ReactiveVar } from 'meteor/reactive-var'; -import type { IRoom, ISetting } from '@rocket.chat/core-typings'; +import type { IMessage, IRoom, ISetting, ISubscription, IUser } from '@rocket.chat/core-typings'; declare module 'meteor/blaze' { namespace Blaze { @@ -65,16 +65,6 @@ declare module 'meteor/templating' { oembedUrlWidget: BlazeTemplate; oembedVideoWidget: BlazeTemplate; oembedYoutubeWidget: BlazeTemplate; - DefaultSearchResultTemplate: BlazeTemplate<{ - searching: ReactiveVar; - result: ReactiveVar; - text: ReactiveVar; - settings: Record; - parentPayload: Record; - payload: Record; - search(): void; - }>; - DefaultSuggestionItemTemplate: BlazeTemplate; icon: BlazeTemplate<{ block?: string; icon: string; @@ -117,7 +107,31 @@ declare module 'meteor/templating' { >; error: BlazeTemplate; loading: BlazeTemplate; - message: BlazeTemplate; + message: BlazeTemplate<{ + msg: Omit & { searchedText?: string; customClass?: string; actionContext?: string; groupable?: boolean }; + room?: Omit; + subscription?: Pick; + settings: { + translateLanguage?: unknown; + autoImageLoad?: unknown; + saveMobileBandwidth?: unknown; + collapseMediaByDefault?: unknown; + showreply?: unknown; + showReplyButton?: unknown; + hasPermissionDeleteMessage?: unknown; + hasPermissionDeleteOwnMessage?: unknown; + hideRoles?: unknown; + UI_Use_Real_Name?: unknown; + Chatops_Username?: unknown; + AutoTranslate_Enabled?: unknown; + Message_AllowEditing?: unknown; + Message_AllowEditing_BlockEditInMinutes?: unknown; + API_Embed?: unknown; + Message_GroupingPeriod?: unknown; + }; + u?: Partial; + [key: string]: any; + }>; messageThread: BlazeTemplate; messagePopup: BlazeTemplate; messagePopupChannel: BlazeTemplate; From 825312f33c91e28b4994c7745928789748868e5f Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Mon, 13 Feb 2023 18:38:26 -0300 Subject: [PATCH 05/10] Fix conflicting types --- .../MessageSearchFormWithSuggestions.tsx | 20 ++++++++----------- .../MessageSearchFormWithoutSuggestions.tsx | 4 ++-- .../components/MessageSearchPanel.tsx | 4 ++-- .../components/MessageSearchSuggestion.tsx | 17 ++++++---------- .../lib/MessageSearchSuggestion.ts | 3 --- .../MessageSearchTab/lib/getSuggestionText.ts | 5 ----- .../externals/meteor/templating.d.ts | 4 ++-- ...hProvider.ts => IMessageSearchProvider.ts} | 2 +- .../src/search/IMessageSearchSuggestion.ts | 3 +++ packages/core-typings/src/search/index.ts | 3 ++- .../ui-contexts/src/ServerContext/methods.ts | 7 ++++--- 11 files changed, 30 insertions(+), 42 deletions(-) delete mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/MessageSearchSuggestion.ts delete mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/getSuggestionText.ts rename packages/core-typings/src/search/{ISearchProvider.ts => IMessageSearchProvider.ts} (85%) create mode 100644 packages/core-typings/src/search/IMessageSearchSuggestion.ts diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx index 4129929a1b74..bd90a14f3771 100644 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx @@ -1,4 +1,4 @@ -import type { ISearchProvider } from '@rocket.chat/core-typings'; +import type { IMessageSearchProvider, IMessageSearchSuggestion } from '@rocket.chat/core-typings'; import { Box } from '@rocket.chat/fuselage'; import { useDebouncedCallback, useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { useMethod, useTranslation, useUserId } from '@rocket.chat/ui-contexts'; @@ -9,12 +9,10 @@ import { useForm } from 'react-hook-form'; import BlazeTemplate from '../../../components/BlazeTemplate'; import { useRoom } from '../../../contexts/RoomContext'; -import type { MessageSearchSuggestion as MessageSearchSuggestionType } from '../lib/MessageSearchSuggestion'; -import { getSuggestionText } from '../lib/getSuggestionText'; import MessageSearchSuggestion from './MessageSearchSuggestion'; type MessageSearchFormWithSuggestionsProps = { - provider: ISearchProvider; + provider: IMessageSearchProvider; onSearch: (searchText: string) => void; }; @@ -71,8 +69,7 @@ const MessageSearchFormWithSuggestions = ({ provider, onSearch }: MessageSearchF const suggestions = suggestionsMutation.data; if (event.code === 'Enter') { - const suggestion = suggestionIndex >= 0 ? suggestions?.[suggestionIndex] : undefined; - const suggestionText = getSuggestionText(suggestion); + const suggestionText = suggestionIndex >= 0 ? suggestions?.[suggestionIndex]?.text : undefined; if (!suggestionText) { return; } @@ -99,18 +96,17 @@ const MessageSearchFormWithSuggestions = ({ provider, onSearch }: MessageSearchF } }); - const handleSuggestionClick = useMutableCallback((suggestion: MessageSearchSuggestionType) => { - const suggestionText = getSuggestionText(suggestion); - if (!suggestionText) { + const handleSuggestionClick = useMutableCallback((suggestion: IMessageSearchSuggestion) => { + if (!suggestion.text) { return; } - setValue('message-search', suggestionText); - onSearch(suggestionText); + setValue('message-search', suggestion.text); + onSearch(suggestion.text); suggestionsMutation.reset(); }); - const handleSuggestionHover = useMutableCallback((suggestion: MessageSearchSuggestionType) => { + const handleSuggestionHover = useMutableCallback((suggestion: IMessageSearchSuggestion) => { setSuggestionIndex(suggestionsMutation.data?.indexOf(suggestion) ?? 0); }); diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithoutSuggestions.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithoutSuggestions.tsx index 27afb4d59276..fd532d69fec4 100644 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithoutSuggestions.tsx +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithoutSuggestions.tsx @@ -1,4 +1,4 @@ -import type { ISearchProvider } from '@rocket.chat/core-typings'; +import type { IMessageSearchProvider } from '@rocket.chat/core-typings'; import { Box } from '@rocket.chat/fuselage'; import { useDebouncedCallback, useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { useTranslation } from '@rocket.chat/ui-contexts'; @@ -9,7 +9,7 @@ import { useForm } from 'react-hook-form'; import BlazeTemplate from '../../../components/BlazeTemplate'; type MessageSearchFormWithoutSuggestionsProps = { - provider: ISearchProvider; + provider: IMessageSearchProvider; onSearch: (searchText: string) => void; }; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchPanel.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchPanel.tsx index f3d2d46e5f19..4c43b9030320 100644 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchPanel.tsx +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchPanel.tsx @@ -1,4 +1,4 @@ -import type { ISearchProvider } from '@rocket.chat/core-typings'; +import type { IMessageSearchProvider } from '@rocket.chat/core-typings'; import { Box } from '@rocket.chat/fuselage'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useTranslation } from '@rocket.chat/ui-contexts'; @@ -10,7 +10,7 @@ import MessageSearchFormWithSuggestions from './MessageSearchFormWithSuggestions import MessageSearchFormWithoutSuggestions from './MessageSearchFormWithoutSuggestions'; type MessageSearchPanelProps = { - provider: ISearchProvider; + provider: IMessageSearchProvider; }; const MessageSearchPanel = ({ provider }: MessageSearchPanelProps): ReactElement => { diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx index 52491bcb4f10..f4df3053de88 100644 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx @@ -1,16 +1,13 @@ -import type { ISearchProvider } from '@rocket.chat/core-typings'; +import type { IMessageSearchProvider, IMessageSearchSuggestion } from '@rocket.chat/core-typings'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import React from 'react'; -import type { MessageSearchSuggestion as MessageSearchSuggestionType } from '../lib/MessageSearchSuggestion'; -import { getSuggestionText } from '../lib/getSuggestionText'; - type MessageSearchSuggestionProps = { - provider: ISearchProvider; - suggestion: MessageSearchSuggestionType; + provider: IMessageSearchProvider; + suggestion: IMessageSearchSuggestion; active: boolean; - onClick: (suggestion: MessageSearchSuggestionType) => void; - onHover: (suggestion: MessageSearchSuggestionType) => void; + onClick: (suggestion: IMessageSearchSuggestion) => void; + onHover: (suggestion: IMessageSearchSuggestion) => void; }; const MessageSearchSuggestion = ({ provider, suggestion, active, onClick, onHover }: MessageSearchSuggestionProps) => { @@ -28,9 +25,7 @@ const MessageSearchSuggestion = ({ provider, suggestion, active, onClick, onHove onClick={handleClick} onMouseEnter={handleMouseEnter} > - {provider.suggestionItemTemplate === 'DefaultSuggestionItemTemplate' && ( -
{getSuggestionText(suggestion)}
- )} + {provider.suggestionItemTemplate === 'DefaultSuggestionItemTemplate' &&
{suggestion.text}
}
); }; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/MessageSearchSuggestion.ts b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/MessageSearchSuggestion.ts deleted file mode 100644 index 7392d911165c..000000000000 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/MessageSearchSuggestion.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type MessageSearchSuggestion = { - text: string; -}; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/getSuggestionText.ts b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/getSuggestionText.ts deleted file mode 100644 index b84ebcb74b4b..000000000000 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/lib/getSuggestionText.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { MessageSearchSuggestion } from './MessageSearchSuggestion'; - -export const getSuggestionText = (suggestion?: MessageSearchSuggestion): string | undefined => { - return suggestion?.text; -}; diff --git a/apps/meteor/definition/externals/meteor/templating.d.ts b/apps/meteor/definition/externals/meteor/templating.d.ts index 04c64b91c26a..c757d6eb9c43 100644 --- a/apps/meteor/definition/externals/meteor/templating.d.ts +++ b/apps/meteor/definition/externals/meteor/templating.d.ts @@ -122,14 +122,14 @@ declare module 'meteor/templating' { messagePopup: BlazeTemplate; messagePopupChannel: BlazeTemplate; messagePopupConfig: BlazeTemplate<{ - tmid: IMessage['_id']; rid: IRoom['_id']; + tmid?: IMessage['_id']; getInput: () => HTMLTextAreaElement | null; }>; messagePopupEmoji: BlazeTemplate; messagePopupSlashCommand: BlazeTemplate; messagePopupSlashCommandPreview: BlazeTemplate<{ - tmid: IMessage['_id']; + tmid?: IMessage['_id']; rid: IRoom['_id']; getInput: () => HTMLTextAreaElement | null; }>; diff --git a/packages/core-typings/src/search/ISearchProvider.ts b/packages/core-typings/src/search/IMessageSearchProvider.ts similarity index 85% rename from packages/core-typings/src/search/ISearchProvider.ts rename to packages/core-typings/src/search/IMessageSearchProvider.ts index 864192a95e73..c71c5614ba71 100644 --- a/packages/core-typings/src/search/ISearchProvider.ts +++ b/packages/core-typings/src/search/IMessageSearchProvider.ts @@ -1,6 +1,6 @@ import type { ISetting } from '../ISetting'; -export interface ISearchProvider { +export interface IMessageSearchProvider { key: string; description: string; icon: string; diff --git a/packages/core-typings/src/search/IMessageSearchSuggestion.ts b/packages/core-typings/src/search/IMessageSearchSuggestion.ts new file mode 100644 index 000000000000..14264618df37 --- /dev/null +++ b/packages/core-typings/src/search/IMessageSearchSuggestion.ts @@ -0,0 +1,3 @@ +export interface IMessageSearchSuggestion { + text: string; +} diff --git a/packages/core-typings/src/search/index.ts b/packages/core-typings/src/search/index.ts index 51b4e5008e47..39f26ffb72ee 100644 --- a/packages/core-typings/src/search/index.ts +++ b/packages/core-typings/src/search/index.ts @@ -1 +1,2 @@ -export * from './ISearchProvider'; +export * from './IMessageSearchSuggestion'; +export * from './IMessageSearchProvider'; diff --git a/packages/ui-contexts/src/ServerContext/methods.ts b/packages/ui-contexts/src/ServerContext/methods.ts index 5a99544fc61f..4f9c42fda761 100644 --- a/packages/ui-contexts/src/ServerContext/methods.ts +++ b/packages/ui-contexts/src/ServerContext/methods.ts @@ -5,7 +5,8 @@ import type { IMessage, IPermission, IRoom, - ISearchProvider, + IMessageSearchProvider, + IMessageSearchSuggestion, ISetting, ISubscription, ISupportedLanguage, @@ -268,7 +269,7 @@ export interface ServerMethods { 'private-settings/get': (updatedSince?: Date) => ISetting[] | { update: ISetting[]; remove: ISetting[] }; 'pinMessage': (message: IMessage) => void; 'unpinMessage': (message: IMessage) => void; - 'rocketchatSearch.getProvider': () => ISearchProvider | undefined; + 'rocketchatSearch.getProvider': () => IMessageSearchProvider | undefined; 'rocketchatSearch.search': ( text: string, context: { uid?: IUser['_id']; rid: IRoom['_id'] }, @@ -282,7 +283,7 @@ export interface ServerMethods { text: string, context: { uid?: IUser['_id']; rid: IRoom['_id'] }, payload: unknown, - ) => ({ type: string; action(): string } | { text: string })[]; + ) => IMessageSearchSuggestion[]; } export type ServerMethodName = keyof ServerMethods; From 5ad65373c79efe030435afd64dcdf5c4452779dc Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Mon, 13 Feb 2023 19:44:22 -0300 Subject: [PATCH 06/10] Remove dangling module --- apps/meteor/app/chatpal-search/client/index.ts | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 apps/meteor/app/chatpal-search/client/index.ts diff --git a/apps/meteor/app/chatpal-search/client/index.ts b/apps/meteor/app/chatpal-search/client/index.ts deleted file mode 100644 index 1317676eab11..000000000000 --- a/apps/meteor/app/chatpal-search/client/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './template/admin.html'; -import './template/result.html'; -import './template/admin.js'; -import './template/result.js'; -import './style.css'; From 93915765728885173942062dc9e581920f73650c Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Mon, 13 Feb 2023 21:52:17 -0300 Subject: [PATCH 07/10] Cut more fat --- apps/meteor/app/search/client/index.ts | 1 - .../theme/client/imports/general/base_old.css | 4 - .../app/theme/client/imports/general/rtl.css | 10 -- apps/meteor/client/importPackages.ts | 1 - .../MessageSearchTab/MessageSearchTab.tsx | 6 +- .../components/MessageSearch.tsx | 25 ++- .../components/MessageSearchForm.tsx | 59 +++++++ .../MessageSearchFormWithSuggestions.tsx | 153 ------------------ .../MessageSearchFormWithoutSuggestions.tsx | 67 -------- .../components/MessageSearchInput.tsx | 35 ++++ .../components/MessageSearchPanel.tsx | 33 +--- .../components/MessageSearchSuggestion.tsx | 33 ---- ...ry.ts => useMessageSearchProviderQuery.ts} | 2 +- .../hooks/useStateAsReactiveVar.ts | 31 ---- .../contextualBar/MessageSearchTab/index.ts | 2 + .../contextualBar/MessageSearchTab}/style.css | 2 - 16 files changed, 116 insertions(+), 348 deletions(-) delete mode 100644 apps/meteor/app/search/client/index.ts create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchForm.tsx delete mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithSuggestions.tsx delete mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchFormWithoutSuggestions.tsx create mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchInput.tsx delete mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchSuggestion.tsx rename apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/{useSearchProviderQuery.ts => useMessageSearchProviderQuery.ts} (88%) delete mode 100644 apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useStateAsReactiveVar.ts rename apps/meteor/{app/search/client/style => client/views/room/contextualBar/MessageSearchTab}/style.css (98%) diff --git a/apps/meteor/app/search/client/index.ts b/apps/meteor/app/search/client/index.ts deleted file mode 100644 index ac8fac5e940a..000000000000 --- a/apps/meteor/app/search/client/index.ts +++ /dev/null @@ -1 +0,0 @@ -import './style/style.css'; diff --git a/apps/meteor/app/theme/client/imports/general/base_old.css b/apps/meteor/app/theme/client/imports/general/base_old.css index eb56c7a36a9b..17d360bf307e 100644 --- a/apps/meteor/app/theme/client/imports/general/base_old.css +++ b/apps/meteor/app/theme/client/imports/general/base_old.css @@ -293,10 +293,6 @@ } } -.rc-old .search-form { - position: relative; -} - .rc-old .-autocomplete-container { top: auto; diff --git a/apps/meteor/app/theme/client/imports/general/rtl.css b/apps/meteor/app/theme/client/imports/general/rtl.css index 6ac1a37e26ab..2838b4acdf68 100644 --- a/apps/meteor/app/theme/client/imports/general/rtl.css +++ b/apps/meteor/app/theme/client/imports/general/rtl.css @@ -102,16 +102,6 @@ transform: translateX(27px); } - & .search-form { - width: 100%; - padding: 0 0 0 4px; - - & .icon-plus { - right: 4px; - left: auto; - } - } - & .info-tabs { right: auto; left: 20px; diff --git a/apps/meteor/client/importPackages.ts b/apps/meteor/client/importPackages.ts index 317e7138fa15..a9c631a44366 100644 --- a/apps/meteor/client/importPackages.ts +++ b/apps/meteor/client/importPackages.ts @@ -61,7 +61,6 @@ import '../app/wordpress/client'; import '../app/meteor-accounts-saml/client'; import '../app/e2e/client'; import '../app/version-check/client'; -import '../app/search/client'; import '../app/lazy-load/client'; import '../app/discussion/client'; import '../app/threads/client'; diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx index 3be0c905c2d1..f3b0ced47f22 100644 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx @@ -9,10 +9,10 @@ import VerticalBarIcon from '../../../../components/VerticalBar/VerticalBarIcon' import VerticalBarText from '../../../../components/VerticalBar/VerticalBarText'; import { useTabBarClose } from '../../contexts/ToolboxContext'; import MessageSearchPanel from './components/MessageSearchPanel'; -import { useSearchProviderQuery } from './hooks/useSearchProviderQuery'; +import { useMessageSearchProviderQuery } from './hooks/useMessageSearchProviderQuery'; const MessageSearchTab = () => { - const providerQuery = useSearchProviderQuery(); + const providerQuery = useMessageSearchProviderQuery(); const tabBarClose = useTabBarClose(); const handleCloseButtonClick = useCallback(() => { @@ -28,7 +28,7 @@ const MessageSearchTab = () => { {t('Search_Messages')} - + {providerQuery.isSuccess && } {providerQuery.isError && ( diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearch.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearch.tsx index 4fb6e7f98cfc..4ef8b725241e 100644 --- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearch.tsx +++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearch.tsx @@ -1,5 +1,5 @@ import { States, StatesIcon, StatesTitle } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; +import { useSetting, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement, ChangeEvent, UIEvent } from 'react'; import React, { useEffect, useRef, useMemo, useState } from 'react'; @@ -11,16 +11,15 @@ import { useRoom } from '../../../contexts/RoomContext'; import { useMessageSearchQuery } from '../hooks/useMessageSearchQuery'; type MessageSearchProps = { - settings: { - GlobalSearchEnabled: boolean; - PageSize: number; - }; searchText: string; }; -const MessageSearch = ({ settings, searchText }: MessageSearchProps): ReactElement => { +const MessageSearch = ({ searchText }: MessageSearchProps): ReactElement => { + const pageSize = useSetting('PageSize') ?? 10; + const globalSearchEnabled = useSetting('GlobalSearchEnabled') ?? false; + const [payload, setPayload] = useState(() => ({ - limit: settings.PageSize, + limit: pageSize, searchAll: false, })); const messageSearchQuery = useMessageSearchQuery({ searchText, ...payload }); @@ -29,7 +28,7 @@ const MessageSearch = ({ settings, searchText }: MessageSearchProps): ReactEleme const handleToggleGlobalSearch = (event: ChangeEvent) => { setPayload({ - limit: settings.PageSize, + limit: pageSize, searchAll: event.target.checked, }); }; @@ -41,14 +40,14 @@ const MessageSearch = ({ settings, searchText }: MessageSearchProps): ReactEleme const throttledTestAndSet = withThrottling({ wait: 200 })((element: HTMLElement) => { if (element.scrollTop >= element.scrollHeight - element.clientHeight) { - setPayload(({ limit, ...rest }) => ({ ...rest, limit: limit + settings.PageSize })); + setPayload(({ limit, ...rest }) => ({ ...rest, limit: limit + pageSize })); } }); return (event: UIEvent) => { throttledTestAndSet(event.currentTarget); }; - }, [hasMore, settings.PageSize]); + }, [hasMore, pageSize]); const scrollListRef = useRef(null); @@ -59,9 +58,9 @@ const MessageSearch = ({ settings, searchText }: MessageSearchProps): ReactEleme } if (element.scrollTop >= element.scrollHeight - element.clientHeight) { - setPayload(({ limit, ...rest }) => ({ ...rest, limit: limit + settings.PageSize })); + setPayload(({ limit, ...rest }) => ({ ...rest, limit: limit + pageSize })); } - }, [settings.PageSize]); + }, [pageSize]); const room = useRoom(); const messageContext = useMemo(() => { @@ -82,7 +81,7 @@ const MessageSearch = ({ settings, searchText }: MessageSearchProps): ReactEleme
- {settings.GlobalSearchEnabled && ( + {globalSearchEnabled && (