Page MenuHomePhabricator

D8910.id30549.diff
No OneTemporary

D8910.id30549.diff

diff --git a/lib/shared/mention-utils.js b/lib/shared/mention-utils.js
--- a/lib/shared/mention-utils.js
+++ b/lib/shared/mention-utils.js
@@ -8,10 +8,11 @@
} from './thread-utils.js';
import { stringForUserExplicit } from './user-utils.js';
import { threadTypes } from '../types/thread-types-enum.js';
-import {
- type ThreadInfo,
- type RelativeMemberInfo,
- type ResolvedThreadInfo,
+import type {
+ ThreadInfo,
+ RelativeMemberInfo,
+ ResolvedThreadInfo,
+ ChatMentionCandidates,
} from '../types/thread-types.js';
export type TypeaheadMatchedStrings = {
@@ -31,7 +32,7 @@
type MentionTypeaheadChatSuggestionItem = {
type: 'chat',
- chat: ResolvedThreadInfo,
+ threadInfo: ResolvedThreadInfo,
};
export type MentionTypeaheadSuggestionItem =
@@ -106,6 +107,31 @@
.map(userInfo => ({ type: 'user', userInfo }));
}
+function getMentionTypeaheadChatSuggestions(
+ chatSearchIndex: SentencePrefixSearchIndex,
+ chatMentionCandidates: ChatMentionCandidates,
+ chatPrefix: string,
+): $ReadOnlyArray<MentionTypeaheadChatSuggestionItem> {
+ if (chatPrefix.length === 0) {
+ return Object.keys(chatMentionCandidates).map(threadID => ({
+ type: 'chat',
+ threadInfo: chatMentionCandidates[threadID],
+ }));
+ }
+ const threadIDs = chatSearchIndex.getSearchResults(chatPrefix);
+ const result = [];
+ for (const threadID of threadIDs) {
+ if (!chatMentionCandidates[threadID]) {
+ continue;
+ }
+ result.push({
+ type: 'chat',
+ threadInfo: chatMentionCandidates[threadID],
+ });
+ }
+ return result;
+}
+
function getNewTextAndSelection(
textBeforeAtSymbol: string,
entireText: string,
@@ -148,6 +174,7 @@
isUserMentioned,
extractUserMentionsFromText,
getMentionTypeaheadUserSuggestions,
+ getMentionTypeaheadChatSuggestions,
getNewTextAndSelection,
getTypeaheadRegexMatches,
getUserMentionsCandidates,
diff --git a/native/avatars/thread-avatar.react.js b/native/avatars/thread-avatar.react.js
--- a/native/avatars/thread-avatar.react.js
+++ b/native/avatars/thread-avatar.react.js
@@ -8,13 +8,17 @@
} from 'lib/shared/avatar-utils.js';
import { getSingleOtherUser } from 'lib/shared/thread-utils.js';
import { threadTypes } from 'lib/types/thread-types-enum.js';
-import { type RawThreadInfo, type ThreadInfo } from 'lib/types/thread-types.js';
+import type {
+ RawThreadInfo,
+ ThreadInfo,
+ ResolvedThreadInfo,
+} from 'lib/types/thread-types.js';
import Avatar, { type AvatarSize } from './avatar.react.js';
import { useSelector } from '../redux/redux-utils.js';
type Props = {
- +threadInfo: RawThreadInfo | ThreadInfo,
+ +threadInfo: RawThreadInfo | ThreadInfo | ResolvedThreadInfo,
+size: AvatarSize,
};
diff --git a/native/chat/chat-input-bar.react.js b/native/chat/chat-input-bar.react.js
--- a/native/chat/chat-input-bar.react.js
+++ b/native/chat/chat-input-bar.react.js
@@ -38,6 +38,7 @@
import { useEditMessage } from 'lib/shared/edit-messages-utils.js';
import {
getMentionTypeaheadUserSuggestions,
+ getMentionTypeaheadChatSuggestions,
getTypeaheadRegexMatches,
type Selection,
getUserMentionsCandidates,
@@ -58,6 +59,7 @@
checkIfDefaultMembersAreVoiced,
draftKeyFromThreadID,
useThreadChatMentionCandidates,
+ useThreadChatMentionSearchIndex,
} from 'lib/shared/thread-utils.js';
import type { CalendarQuery } from 'lib/types/entry-types.js';
import type { LoadingStatus } from 'lib/types/loading-types.js';
@@ -74,6 +76,7 @@
ClientThreadJoinRequest,
ThreadJoinPayload,
RelativeMemberInfo,
+ ChatMentionCandidates,
} from 'lib/types/thread-types.js';
import { type UserInfos } from 'lib/types/user-types.js';
import {
@@ -173,6 +176,8 @@
+inputState: ?InputState,
+userSearchIndex: SentencePrefixSearchIndex,
+userMentionsCandidates: $ReadOnlyArray<RelativeMemberInfo>,
+ +chatMentionSearchIndex: SentencePrefixSearchIndex,
+ +chatMentionCandidates: ChatMentionCandidates,
+parentThreadInfo: ?ThreadInfo,
+editedMessagePreview: ?MessagePreviewResult,
+editedMessageInfo: ?MessageInfo,
@@ -565,13 +570,19 @@
this.props.viewerID,
typeaheadMatchedStrings.textPrefix,
);
+ const suggestedChats = getMentionTypeaheadChatSuggestions(
+ this.props.chatMentionSearchIndex,
+ this.props.chatMentionCandidates,
+ typeaheadMatchedStrings.textPrefix,
+ );
+ const suggestions = [...suggestedUsers, ...suggestedChats];
- if (suggestedUsers.length > 0) {
+ if (suggestions.length > 0) {
typeaheadTooltip = (
<TypeaheadTooltip
text={this.state.text}
matchedStrings={typeaheadMatchedStrings}
- suggestions={suggestedUsers}
+ suggestions={suggestions}
focusAndUpdateTextAndSelection={this.focusAndUpdateTextAndSelection}
typeaheadButtonRenderer={mentionTypeaheadTooltipButtonRenderer}
typeaheadTooltipActionsGetter={mentionTypeaheadTooltipActions}
@@ -1255,6 +1266,10 @@
const userSearchIndex = useSelector(userStoreMentionSearchIndex);
+ const chatMentionSearchIndex = useThreadChatMentionSearchIndex(
+ props.threadInfo,
+ );
+
const { parentThreadID } = props.threadInfo;
const parentThreadInfo = useSelector(state =>
parentThreadID ? threadInfoSelector(state)[parentThreadID] : null,
@@ -1299,6 +1314,8 @@
inputState={inputState}
userSearchIndex={userSearchIndex}
userMentionsCandidates={userMentionsCandidates}
+ chatMentionSearchIndex={chatMentionSearchIndex}
+ chatMentionCandidates={chatMentionCandidates}
parentThreadInfo={parentThreadInfo}
editedMessagePreview={editedMessagePreview}
editedMessageInfo={editedMessageInfo}
diff --git a/native/utils/typeahead-utils.js b/native/utils/typeahead-utils.js
--- a/native/utils/typeahead-utils.js
+++ b/native/utils/typeahead-utils.js
@@ -11,15 +11,17 @@
type TypeaheadTooltipActionItem,
type MentionTypeaheadSuggestionItem,
} from 'lib/shared/mention-utils.js';
+import { validChatNameRegexString } from 'lib/shared/thread-utils.js';
import { stringForUserExplicit } from 'lib/shared/user-utils.js';
+import ThreadAvatar from '../avatars/thread-avatar.react.js';
import UserAvatar from '../avatars/user-avatar.react.js';
import type { TypeaheadTooltipStyles } from '../chat/typeahead-tooltip.react.js';
// Native regex is a little bit different than web one as
// there are no named capturing groups yet on native.
const nativeMentionTypeaheadRegex: RegExp = new RegExp(
- `((^(.|\n)*\\s+)|^)@(${oldValidUsernameRegexString})?$`,
+ `((^(.|\n)*\\s+)|^)@(${oldValidUsernameRegexString}|${validChatNameRegexString})?$`,
);
export type TypeaheadTooltipActionsParams<SuggestionType> = {
@@ -67,12 +69,12 @@
},
});
} else if (suggestion.type === 'chat') {
- const { chat } = suggestion;
- const mentionText = `@[[${chat.id}:${encodeChatMentionText(
- chat.uiName,
+ const { threadInfo } = suggestion;
+ const mentionText = `@[[${threadInfo.id}:${encodeChatMentionText(
+ threadInfo.uiName,
)}]]`;
actions.push({
- key: chat.id,
+ key: threadInfo.id,
execute: () => {
const { newText, newSelectionStart } = getNewTextAndSelection(
textBeforeAtSymbol,
@@ -87,7 +89,7 @@
},
actionButtonContent: {
type: 'chat',
- chat,
+ threadInfo,
},
});
}
@@ -110,6 +112,14 @@
<UserAvatar size="small" userID={item.actionButtonContent.userInfo.id} />
);
typeaheadTooltipButtonText = item.actionButtonContent.userInfo.username;
+ } else if (item.actionButtonContent.type === 'chat') {
+ typeaheadTooltipButtonText = item.actionButtonContent.threadInfo.uiName;
+ avatarComponent = (
+ <ThreadAvatar
+ size="small"
+ threadInfo={item.actionButtonContent.threadInfo}
+ />
+ );
}
return (
<>

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 24, 7:25 AM (21 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2574532
Default Alt Text
D8910.id30549.diff (7 KB)

Event Timeline