fix: search now works correctly and we include groups again

heading for unamed contacts is #, groups go above note to self, trust in the sql query
pull/3083/head
William Grant 10 months ago
parent 301af68eee
commit 5cd7262fa2

@ -85,7 +85,7 @@ const ContactListItemSection = () => {
directContactsByNameWithBreaks.push(currentChar.toUpperCase());
} else if (!m.displayName && currentChar !== unknownSection) {
currentChar = unknownSection;
directContactsByNameWithBreaks.push(window.i18n('unknown'));
directContactsByNameWithBreaks.push('#');
}
directContactsByNameWithBreaks.push(m);
});

@ -30,10 +30,6 @@ export function useHotkey(
const lowerKey = key.toLowerCase();
const eventKey = event.key.toLowerCase();
window.log.debug(
`WIP: [useHotkey] key: ${key} lowerKey: ${lowerKey} eventKey: ${eventKey} event.target: ${JSON.stringify(event)}`
);
switch (lowerKey) {
case 'esc':
case 'escape':
@ -45,20 +41,15 @@ export function useHotkey(
const handler: Handler = event => {
if (disabled) {
window.log.debug(`WIP: [useHotkey] '${key}' is disabled. Triggered by ${event.key}`);
return;
}
const specialKeys = specialKeyPressed(event);
if (specialKeys) {
window.log.debug(
`WIP: [useHotkey] '${key}' was ignored because it was pressed with ${specialKeys}. Triggered by ${event.key} + ${specialKeys}`
);
return;
}
window.log.debug(`WIP: [useHotkey] '${key}' onPress event. Triggered by ${event.key}`);
void onPress(event);
};

@ -711,13 +711,13 @@ function searchConversations(query: string) {
.prepare(
`SELECT * FROM ${CONVERSATIONS_TABLE} WHERE
(
displayNameInProfile LIKE $displayNameInProfile OR
nickname LIKE $nickname OR
displayNameInProfile LIKE $displayNameInProfile COLLATE NOCASE OR
nickname LIKE $nickname COLLATE NOCASE OR
(id LIKE $id AND
(displayNameInProfile IS NULL OR displayNameInProfile = '') AND (nickname IS NULL OR nickname = '')
)
) AND active_at > 0
ORDER BY active_at DESC
ORDER BY (COALESCE(NULLIF(nickname, ''), displayNameInProfile) COLLATE NOCASE)
LIMIT $limit`
)
.all({

@ -4,7 +4,6 @@ import { Data } from '../../data/data';
import { AdvancedSearchOptions, SearchOptions } from '../../types/Search';
import { cleanSearchTerm } from '../../util/cleanSearchTerm';
import { ConversationTypeEnum } from '../../models/conversationAttributes';
import { PubKey } from '../../session/types';
import { UserUtils } from '../../session/utils';
import { MessageResultProps } from '../../types/message';
@ -16,7 +15,7 @@ export type SearchStateType = {
query: string;
normalizedPhoneNumber?: string;
// For conversations we store just the id, and pull conversation props in the selector
contactsAndConversations: Array<string>;
contactsAndGroups: Array<string>;
messages?: Array<MessageResultProps>;
};
@ -24,7 +23,7 @@ export type SearchStateType = {
type SearchResultsPayloadType = {
query: string;
normalizedPhoneNumber?: string;
contactsAndConversations: Array<string>;
contactsAndGroups: Array<string>;
messages?: Array<MessageResultProps>;
};
@ -72,24 +71,21 @@ async function doSearch(query: string): Promise<SearchResultsPayloadType> {
noteToSelf: window.i18n('noteToSelf').toLowerCase(),
savedMessages: window.i18n('savedMessages').toLowerCase(),
ourNumber: UserUtils.getOurPubKeyStrFromCache(),
filter: 'contacts',
};
const advancedSearchOptions = getAdvancedSearchOptionsFromQuery(query);
const processedQuery = advancedSearchOptions.query;
// const isAdvancedQuery = query !== processedQuery;
const [discussions, messages] = await Promise.all([
queryConversationsAndContacts(processedQuery, options),
const [contactsAndGroups, messages] = await Promise.all([
queryContactsAndGroups(processedQuery, options),
queryMessages(processedQuery),
]);
const { conversations, contacts } = discussions;
const contactsAndConversations = _.uniq([...conversations, ...contacts]);
const filteredMessages = _.compact(messages);
return {
query,
normalizedPhoneNumber: PubKey.normalize(query),
contactsAndConversations,
contactsAndGroups,
messages: filteredMessages,
};
}
@ -202,45 +198,13 @@ async function queryMessages(query: string): Promise<Array<MessageResultProps>>
}
}
async function queryConversationsAndContacts(providedQuery: string, options: SearchOptions) {
const { ourNumber, noteToSelf, savedMessages, filter } = options;
async function queryContactsAndGroups(providedQuery: string, options: SearchOptions) {
const { ourNumber, noteToSelf, savedMessages } = options;
// we don't need to use cleanSearchTerm here because the query is wrapped as a wild card and is not referenced in the SQL query directly
const query = providedQuery.replace(/[+-.()]*/g, '');
const contactsOnly = filter === 'contacts';
const conversationsOnly = filter === 'conversations';
const searchResults: Array<ReduxConversationType> = await Data.searchConversations(query);
// Split into two groups - active conversations and items just from address book
let conversations: Array<string> = [];
let contacts: Array<string> = [];
const max = searchResults.length;
for (let i = 0; i < max; i += 1) {
const conversation = searchResults[i];
if (!contactsOnly) {
if (conversation.id && conversation.activeAt) {
if (conversation.id === ourNumber) {
conversations.push(ourNumber);
} else {
conversations.push(conversation.id);
}
}
if (conversation.id && conversation.type !== ConversationTypeEnum.PRIVATE) {
conversations.push(conversation.id);
}
}
if (
!conversationsOnly &&
conversation.id &&
conversation.type === ConversationTypeEnum.PRIVATE
) {
contacts.push(conversation.id);
}
}
let contactsAndGroups: Array<string> = searchResults.map(conversation => conversation.id);
const queryLowered = query.toLowerCase();
// Inject synthetic Note to Self entry if query matches localized 'Note to Self'
@ -251,20 +215,18 @@ async function queryConversationsAndContacts(providedQuery: string, options: Sea
savedMessages.includes(queryLowered)
) {
// Ensure that we don't have duplicates in our results
contacts = contacts.filter(id => id !== ourNumber);
conversations = conversations.filter(id => id !== ourNumber);
contacts.unshift(ourNumber);
contactsAndGroups = contactsAndGroups.filter(id => id !== ourNumber);
contactsAndGroups.unshift(ourNumber);
}
return { conversations, contacts };
return contactsAndGroups;
}
// Reducer
export const initialSearchState: SearchStateType = {
query: '',
contactsAndConversations: [],
contactsAndGroups: [],
messages: [],
};
@ -293,7 +255,7 @@ export function reducer(state: SearchStateType | undefined, action: SEARCH_TYPES
if (action.type === 'SEARCH_RESULTS_FULFILLED') {
const { payload } = action;
const { query, normalizedPhoneNumber, contactsAndConversations, messages } = payload;
const { query, normalizedPhoneNumber, contactsAndGroups, messages } = payload;
// Reject if the associated query is not the most recent user-provided query
if (state.query !== query) {
return state;
@ -303,7 +265,7 @@ export function reducer(state: SearchStateType | undefined, action: SEARCH_TYPES
...state,
query,
normalizedPhoneNumber,
contactsAndConversations,
contactsAndGroups,
messages,
};
}

@ -1,8 +1,9 @@
import { createSelector } from '@reduxjs/toolkit';
import { compact, isEmpty, sortBy } from 'lodash';
import { compact, isEmpty, remove, sortBy } from 'lodash';
import { StateType } from '../reducer';
import { ConversationTypeEnum } from '../../models/conversationAttributes';
import { UserUtils } from '../../session/utils';
import { MessageResultProps } from '../../types/message';
import { ConversationLookupType } from '../ducks/conversations';
@ -21,8 +22,8 @@ const getSearchResults = createSelector(
[getSearch, getConversationLookup],
(searchState: SearchStateType, lookup: ConversationLookupType) => {
return {
contactsAndConversations: compact(
searchState.contactsAndConversations
contactsAndGroups: compact(
searchState.contactsAndGroups
.filter(id => {
const value = lookup[id];
@ -50,16 +51,16 @@ export const getSearchTerm = createSelector([getSearchResults], searchResult =>
export const getSearchResultsIdsOnly = createSelector([getSearchResults], searchState => {
return {
...searchState,
contactsAndConversationIds: searchState.contactsAndConversations.map(m => m.id),
contactsAndGroupsIds: searchState.contactsAndGroups.map(m => m.id),
};
});
export const getHasSearchResults = createSelector([getSearchResults], searchState => {
return !isEmpty(searchState.contactsAndConversations) || !isEmpty(searchState.messages);
return !isEmpty(searchState.contactsAndGroups) || !isEmpty(searchState.messages);
});
export const getSearchResultsContactOnly = createSelector([getSearchResults], searchState => {
return searchState.contactsAndConversations.filter(m => m.isPrivate).map(m => m.id);
return searchState.contactsAndGroups.filter(m => m.isPrivate).map(m => m.id);
});
/**
@ -74,33 +75,39 @@ export type SearchResultsMergedListItem =
| MessageResultProps;
export const getSearchResultsList = createSelector([getSearchResults], searchState => {
const { contactsAndConversations, messages } = searchState;
const { contactsAndGroups, messages } = searchState;
const builtList: Array<SearchResultsMergedListItem> = [];
if (contactsAndConversations.length) {
if (contactsAndGroups.length) {
const us = UserUtils.getOurPubKeyStrFromCache();
let usIndex: number = -1;
const idsAndDisplayNames = contactsAndConversations.map(m => ({
const idsWithNameAndType = contactsAndGroups.map(m => ({
contactConvoId: m.id,
displayName: m.nickname || m.displayNameInProfile,
type: m.type,
}));
const idsWithDisplayNames = sortBy(
idsAndDisplayNames.filter(m => Boolean(m.displayName)),
const groupsAndCommunities = sortBy(
remove(idsWithNameAndType, m => m.type === ConversationTypeEnum.GROUP),
m => m.displayName?.toLowerCase()
);
const idsWithNoDisplayNames = sortBy(
remove(idsWithNameAndType, m => !m.displayName),
m => m.contactConvoId
);
// add a break wherever needed
let currentChar = '';
for (let i = 0; i < idsWithDisplayNames.length; i++) {
const m = idsWithDisplayNames[i];
for (let i = 0; i < idsWithNameAndType.length; i++) {
const m = idsWithNameAndType[i];
if (m.contactConvoId === us) {
usIndex = i;
continue;
}
if (
idsWithDisplayNames.length > 1 &&
idsWithNameAndType.length > 1 &&
m.displayName &&
m.displayName[0].toLowerCase() !== currentChar
) {
@ -110,18 +117,15 @@ export const getSearchResultsList = createSelector([getSearchResults], searchSta
builtList.push(m);
}
if (usIndex !== -1) {
builtList.unshift({ contactConvoId: us, displayName: window.i18n('noteToSelf') });
}
builtList.unshift(...groupsAndCommunities);
const idsWithNoDisplayNames = sortBy(
idsAndDisplayNames.filter(m => !m.displayName),
'id'
);
if (idsWithNoDisplayNames.length) {
builtList.push(window.i18n('unknown'), ...idsWithNoDisplayNames);
builtList.push('#', ...idsWithNoDisplayNames);
}
if (usIndex !== -1) {
builtList.unshift({ contactConvoId: us, displayName: window.i18n('noteToSelf') });
}
builtList.unshift(window.i18n('sessionConversations'));
}

@ -2,7 +2,6 @@ export type SearchOptions = {
ourNumber: string;
noteToSelf: string;
savedMessages: string;
filter?: 'contacts' | 'conversations';
};
export type AdvancedSearchOptions = {

Loading…
Cancel
Save