Fix keyboard search when left pane is narrow

This PR fixes Cmd+f/Ctrl+f functionality in the left pane.
Using a keyboard to search across all
conversations should now automatically change the left pane width
to accommodate the search input component.

Resolves: #6281
This commit is contained in:
veekas ashoka 2023-02-22 14:21:59 -05:00
parent 3d735acdec
commit 0100866d0a
7 changed files with 99 additions and 23 deletions

View file

@ -104,7 +104,7 @@ const defaultModeSpecificProps = {
pinnedConversations,
conversations: defaultConversations,
archivedConversations: defaultArchivedConversations,
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
};
const emptySearchResultsGroup = { isLoading: false, results: [] };
@ -278,7 +278,7 @@ export function InboxNoConversations(): JSX.Element {
pinnedConversations: [],
conversations: [],
archivedConversations: [],
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
},
})}
/>
@ -299,7 +299,7 @@ export function InboxOnlyPinnedConversations(): JSX.Element {
pinnedConversations,
conversations: [],
archivedConversations: [],
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
},
})}
/>
@ -320,7 +320,7 @@ export function InboxOnlyNonPinnedConversations(): JSX.Element {
pinnedConversations: [],
conversations: defaultConversations,
archivedConversations: [],
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
},
})}
/>
@ -341,7 +341,7 @@ export function InboxOnlyArchivedConversations(): JSX.Element {
pinnedConversations: [],
conversations: [],
archivedConversations: defaultArchivedConversations,
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
},
})}
/>
@ -362,7 +362,7 @@ export function InboxPinnedAndArchivedConversations(): JSX.Element {
pinnedConversations,
conversations: [],
archivedConversations: defaultArchivedConversations,
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
},
})}
/>
@ -383,7 +383,7 @@ export function InboxNonPinnedAndArchivedConversations(): JSX.Element {
pinnedConversations: [],
conversations: defaultConversations,
archivedConversations: defaultArchivedConversations,
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
},
})}
/>
@ -404,7 +404,7 @@ export function InboxPinnedAndNonPinnedConversations(): JSX.Element {
pinnedConversations,
conversations: defaultConversations,
archivedConversations: [],
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
},
})}
/>
@ -946,7 +946,7 @@ export function CaptchaDialogRequired(): JSX.Element {
pinnedConversations,
conversations: defaultConversations,
archivedConversations: [],
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
searchTerm: '',
},
challengeStatus: 'required',
@ -969,7 +969,7 @@ export function CaptchaDialogPending(): JSX.Element {
pinnedConversations,
conversations: defaultConversations,
archivedConversations: [],
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
searchTerm: '',
},
challengeStatus: 'pending',
@ -991,7 +991,7 @@ export const _CrashReportDialog = (): JSX.Element => (
pinnedConversations,
conversations: defaultConversations,
archivedConversations: [],
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
searchTerm: '',
},
crashReportCount: 42,
@ -1163,7 +1163,7 @@ export function SearchingConversation(): JSX.Element {
pinnedConversations: [],
conversations: defaultConversations,
archivedConversations: [],
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
searchConversation: getDefaultConversation(),
searchTerm: '',
},

View file

@ -24,7 +24,7 @@ export type LeftPaneInboxPropsType = {
conversations: ReadonlyArray<ConversationListItemPropsType>;
archivedConversations: ReadonlyArray<ConversationListItemPropsType>;
pinnedConversations: ReadonlyArray<ConversationListItemPropsType>;
isAboutToSearchInAConversation: boolean;
isAboutToSearch: boolean;
startSearchCounter: number;
searchDisabled: boolean;
searchTerm: string;
@ -38,7 +38,7 @@ export class LeftPaneInboxHelper extends LeftPaneHelper<LeftPaneInboxPropsType>
private readonly pinnedConversations: ReadonlyArray<ConversationListItemPropsType>;
private readonly isAboutToSearchInAConversation: boolean;
private readonly isAboutToSearch: boolean;
private readonly startSearchCounter: number;
@ -52,7 +52,7 @@ export class LeftPaneInboxHelper extends LeftPaneHelper<LeftPaneInboxPropsType>
conversations,
archivedConversations,
pinnedConversations,
isAboutToSearchInAConversation,
isAboutToSearch,
startSearchCounter,
searchDisabled,
searchTerm,
@ -63,7 +63,7 @@ export class LeftPaneInboxHelper extends LeftPaneHelper<LeftPaneInboxPropsType>
this.conversations = conversations;
this.archivedConversations = archivedConversations;
this.pinnedConversations = pinnedConversations;
this.isAboutToSearchInAConversation = isAboutToSearchInAConversation;
this.isAboutToSearch = isAboutToSearch;
this.startSearchCounter = startSearchCounter;
this.searchDisabled = searchDisabled;
this.searchTerm = searchTerm;
@ -245,7 +245,7 @@ export class LeftPaneInboxHelper extends LeftPaneHelper<LeftPaneInboxPropsType>
!this.conversations.length &&
!this.pinnedConversations.length &&
!this.archivedConversations.length;
return hasNoConversations || this.isAboutToSearchInAConversation;
return hasNoConversations || this.isAboutToSearch;
}
shouldRecomputeRowHeights(old: Readonly<LeftPaneInboxPropsType>): boolean {

View file

@ -57,6 +57,7 @@ export type MessageSearchResultLookupType = ReadonlyDeep<{
export type SearchStateType = ReadonlyDeep<{
startSearchCounter: number;
searchConversationId?: string;
globalSearch?: boolean;
contactIds: Array<string>;
conversationIds: Array<string>;
query: string;
@ -94,7 +95,7 @@ type UpdateSearchTermActionType = ReadonlyDeep<{
}>;
type StartSearchActionType = ReadonlyDeep<{
type: 'SEARCH_START';
payload: null;
payload: { globalSearch: boolean };
}>;
type ClearSearchActionType = ReadonlyDeep<{
type: 'SEARCH_CLEAR';
@ -137,7 +138,7 @@ export const actions = {
function startSearch(): StartSearchActionType {
return {
type: 'SEARCH_START',
payload: null,
payload: { globalSearch: true },
};
}
function clearSearch(): ClearSearchActionType {
@ -341,6 +342,7 @@ export function reducer(
return {
...state,
searchConversationId: undefined,
globalSearch: true,
startSearchCounter: state.startSearchCounter + 1,
};
}

View file

@ -54,6 +54,23 @@ export const getIsSearchingInAConversation = createSelector(
Boolean
);
export const getGlobalSearchValue = createSelector(
getSearch,
(state: SearchStateType): boolean | undefined => state.globalSearch
);
export const getIsSearchingGlobally = createSelector(
getGlobalSearchValue,
Boolean
);
export const getIsSearching = createSelector(
getIsSearchingInAConversation,
getIsSearchingGlobally,
(isSearchingInAConversation, isSearchingGlobally): boolean =>
isSearchingInAConversation || isSearchingGlobally
);
export const getSearchConversation = createSelector(
getSearchConversationId,
getConversationLookup,

View file

@ -16,7 +16,7 @@ import { isDone as isRegistrationDone } from '../../util/registration';
import { ComposerStep, OneTimeModalState } from '../ducks/conversationsEnums';
import {
getIsSearchingInAConversation,
getIsSearching,
getQuery,
getSearchConversation,
getSearchResults,
@ -152,7 +152,7 @@ const getModeSpecificProps = (
}
return {
mode: LeftPaneMode.Inbox,
isAboutToSearchInAConversation: getIsSearchingInAConversation(state),
isAboutToSearch: getIsSearching(state),
searchConversation: getSearchConversation(state),
searchDisabled: state.network.challengeStatus !== 'idle',
searchTerm: getQuery(state),

View file

@ -14,6 +14,8 @@ import type { MessageSearchResultType } from '../../../state/ducks/search';
import { getEmptyState as getEmptySearchState } from '../../../state/ducks/search';
import { getEmptyState as getEmptyUserState } from '../../../state/ducks/user';
import {
getIsSearching,
getIsSearchingGlobally,
getIsSearchingInAConversation,
getMessageSearchResultSelector,
getSearchResults,
@ -93,6 +95,61 @@ describe('both/state/selectors/search', () => {
});
});
describe('#getIsSearchingGlobally', () => {
it('returns false if not searching', () => {
const state = getEmptyRootState();
assert.isFalse(getIsSearchingGlobally(state));
});
it('returns true if searching globally', () => {
const state = {
...getEmptyRootState(),
search: {
...getEmptySearchState(),
globalSearch: true,
},
};
assert.isTrue(getIsSearchingGlobally(state));
});
});
describe('#getIsSearching', () => {
it('returns false if not searching in any manner', () => {
const state = getEmptyRootState();
assert.isFalse(getIsSearching(state));
});
it('returns true if searching in a conversation', () => {
const state = {
...getEmptyRootState(),
search: {
...getEmptySearchState(),
searchConversationId: 'abc123',
searchConversationName: 'Test Conversation',
globalSearch: false,
},
};
assert.isTrue(getIsSearching(state));
});
it('returns true if searching globally', () => {
const state = {
...getEmptyRootState(),
search: {
...getEmptySearchState(),
searchConversationId: undefined,
globalSearch: true,
},
};
assert.isTrue(getIsSearchingGlobally(state));
});
});
describe('#getMessageSearchResultSelector', () => {
it('returns undefined if message not found in lookup', () => {
const state = getEmptyRootState();

View file

@ -14,7 +14,7 @@ describe('LeftPaneInboxHelper', () => {
const defaultProps: LeftPaneInboxPropsType = {
archivedConversations: [],
conversations: [],
isAboutToSearchInAConversation: false,
isAboutToSearch: false,
pinnedConversations: [],
searchConversation: undefined,
searchDisabled: false,
@ -616,7 +616,7 @@ describe('LeftPaneInboxHelper', () => {
it("returns true if we're about to search in a conversation", () => {
const helper = new LeftPaneInboxHelper({
...defaultProps,
isAboutToSearchInAConversation: true,
isAboutToSearch: true,
});
assert.isTrue(helper.requiresFullWidth());