Skip to content

Commit 0027fbf

Browse files
committed
Clean implementation of heap used for recent reports list
1 parent d1ac93e commit 0027fbf

3 files changed

Lines changed: 31 additions & 24 deletions

File tree

src/components/Search/SearchAutocompleteList.tsx

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
1818
import {getCardFeedKey, getCardFeedNamesWithType} from '@libs/CardFeedUtils';
1919
import {getCardDescription, isCard, isCardHiddenFromSearch, mergeCardListWithWorkspaceFeeds} from '@libs/CardUtils';
2020
import memoize from '@libs/memoize';
21-
import {getMostRecentOptions, Options, SearchOption} from '@libs/OptionsListUtils';
21+
import {getMostRecentOptions, Options, recentReportComparator, SearchOption} from '@libs/OptionsListUtils';
2222
import {combineOrderingOfReportsAndPersonalDetails, getSearchOptions, getValidPersonalDetailOptions, orderReportOptions} from '@libs/OptionsListUtils';
2323
import Performance from '@libs/Performance';
2424
import {getAllTaxRates, getCleanedTagName, shouldShowPolicy} from '@libs/PolicyUtils';
@@ -353,14 +353,10 @@ function SearchAutocompleteList(
353353
}));
354354
}
355355
case CONST.SEARCH.SYNTAX_FILTER_KEYS.IN: {
356-
Timing.start(CONST.TIMING.SEARCH_MOST_RECENT_OPTIONS)
357-
358356
// const orderedReportOptions = orderReportOptions(searchOptions.recentReports);
359-
const orderedReportOptions = getMostRecentOptions(searchOptions.recentReports, 10)
360-
const filteredChats = orderedReportOptions
361-
.filter((chat) => chat.text?.toLowerCase()?.includes(autocompleteValue.toLowerCase()) && !alreadyAutocompletedKeys.includes(chat.text.toLowerCase()))
362-
.slice(0, 10);
363-
Timing.end(CONST.TIMING.SEARCH_MOST_RECENT_OPTIONS)
357+
const filterChats = (chat: OptionData) => chat.text?.toLowerCase()?.includes(autocompleteValue.toLowerCase()) && !alreadyAutocompletedKeys.includes(chat.text.toLowerCase());
358+
const filteredChats = getMostRecentOptions(searchOptions.recentReports, 10, recentReportComparator, filterChats);
359+
364360
return filteredChats.map((chat) => ({
365361
filterKey: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.IN,
366362
text: chat.text ?? '',
@@ -501,12 +497,13 @@ function SearchAutocompleteList(
501497
const {search: filterOptions, isInitialized: isFastSearchInitialized} = useFastSearchFromOptions(searchOptions, {includeUserToInvite: true});
502498

503499
const recentReportsOptions = useMemo(() => {
500+
Timing.start(CONST.TIMING.SEARCH_FILTER_OPTIONS);
504501
if (autocompleteQueryValue.trim() === '' || !isFastSearchInitialized) {
505-
const orderedReportOptions = orderReportOptions(searchOptions.recentReports);
506-
return orderedReportOptions.slice(0, 20);
502+
const orderedReportOptions = getMostRecentOptions(searchOptions.recentReports, 20, recentReportComparator);
503+
Timing.end(CONST.TIMING.SEARCH_FILTER_OPTIONS);
504+
return orderedReportOptions;
507505
}
508506

509-
Timing.start(CONST.TIMING.SEARCH_FILTER_OPTIONS);
510507
const filteredOptions = filterOptions(autocompleteQueryValue);
511508
const orderedOptions = combineOrderingOfReportsAndPersonalDetails(filteredOptions, autocompleteQueryValue, {
512509
sortByReportTypeInSearch: true,

src/libs/OptionsListUtils.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable @typescript-eslint/prefer-for-of */
22

33
/* eslint-disable no-continue */
4+
import {MaxHeap} from '@datastructures-js/heap';
45
import {Str} from 'expensify-common';
56
import keyBy from 'lodash/keyBy';
67
import lodashOrderBy from 'lodash/orderBy';
@@ -144,7 +145,6 @@ import type {OptionData} from './ReportUtils';
144145
import StringUtils from './StringUtils';
145146
import {getTaskCreatedMessage, getTaskReportActionMessage} from './TaskUtils';
146147
import {generateAccountID} from './UserUtils';
147-
import {MaxHeap} from '@datastructures-js/heap';
148148

149149
type SearchOption<T> = OptionData & {
150150
item: T;
@@ -1253,18 +1253,28 @@ function orderReportOptions(options: OptionData[]) {
12531253
return lodashOrderBy(options, [sortComparatorReportOptionByArchivedStatus, sortComparatorReportOptionByDate], ['asc', 'desc']);
12541254
}
12551255

1256-
function getMostRecentOptions(options: OptionData[], limit: number): OptionData[] {
1257-
const heap = new MaxHeap<OptionData>((option) => {
1258-
return `${option.private_isArchived ? 0 : 1}_${option.lastVisibleActionCreated ?? ''}`;
1259-
});
1256+
const recentReportComparator = (option: OptionData) => {
1257+
return `${option.private_isArchived ? 0 : 1}_${option.lastVisibleActionCreated ?? ''}`;
1258+
};
1259+
1260+
function getMostRecentOptions(options: OptionData[], limit: number, comparator: (option: OptionData) => number | string, filter?: (option: OptionData) => boolean | undefined): OptionData[] {
1261+
Timing.start(CONST.TIMING.SEARCH_MOST_RECENT_OPTIONS);
1262+
const heap = new MaxHeap<OptionData>(comparator);
12601263
options.forEach((option) => {
1264+
if (filter && !filter(option)) {
1265+
return;
1266+
}
12611267
heap.push(option);
12621268
});
1263-
const result = [];
1264-
while (heap.size() > 0 && result.length < limit) {
1265-
result.push(heap.pop());
1269+
const result: OptionData[] = [];
1270+
while (!heap.isEmpty() && result.length < limit) {
1271+
/**
1272+
* Disable the no-non-null assertion rule here because we are checking if the heap is empty before popping an element.
1273+
*/
1274+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
1275+
result.push(heap.pop()!);
12661276
}
1267-
1277+
Timing.end(CONST.TIMING.SEARCH_MOST_RECENT_OPTIONS);
12681278
return result;
12691279
}
12701280

@@ -2483,7 +2493,8 @@ export {
24832493
isMakingLastRequiredTagListOptional,
24842494
processReport,
24852495
shallowOptionsListCompare,
2486-
getMostRecentOptions
2496+
getMostRecentOptions,
2497+
recentReportComparator,
24872498
};
24882499

24892500
export type {Section, SectionBase, MemberForList, Options, OptionList, SearchOption, Option, OptionTree, ReportAndPersonalDetailOptions};

src/pages/Share/ShareTab.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
1212
import {getOptimisticChatReport, saveReportDraft, searchInServer} from '@libs/actions/Report';
1313
import {saveUnknownUserDetails} from '@libs/actions/Share';
1414
import Navigation from '@libs/Navigation/Navigation';
15-
import {combineOrderingOfReportsAndPersonalDetails, getHeaderMessage, getSearchOptions, orderReportOptions} from '@libs/OptionsListUtils';
15+
import {combineOrderingOfReportsAndPersonalDetails, getHeaderMessage, getMostRecentOptions, getSearchOptions, recentReportComparator} from '@libs/OptionsListUtils';
1616
import type {OptionData} from '@libs/ReportUtils';
1717
import StringUtils from '@libs/StringUtils';
1818
import CONST from '@src/CONST';
@@ -52,8 +52,7 @@ function ShareTab() {
5252

5353
const recentReportsOptions = useMemo(() => {
5454
if (textInputValue.trim() === '') {
55-
const orderedReportOptions = orderReportOptions(searchOptions.recentReports);
56-
return orderedReportOptions.slice(0, 20);
55+
return getMostRecentOptions(searchOptions.recentReports, 20, recentReportComparator);
5756
}
5857
const filteredOptions = filterOptions(textInputValue);
5958
const orderedOptions = combineOrderingOfReportsAndPersonalDetails(filteredOptions, textInputValue, {

0 commit comments

Comments
 (0)