From 40d0258ddd0baf6f9dd9e1324a30c8f936bd9479 Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Thu, 17 Apr 2025 14:20:53 +0200 Subject: [PATCH 1/8] update autocomplete parser --- src/libs/SearchParser/autocompleteParser.js | 3 +++ src/libs/SearchParser/autocompleteParser.peggy | 1 + 2 files changed, 4 insertions(+) diff --git a/src/libs/SearchParser/autocompleteParser.js b/src/libs/SearchParser/autocompleteParser.js index a80c8d370c478..c613805ec67f2 100644 --- a/src/libs/SearchParser/autocompleteParser.js +++ b/src/libs/SearchParser/autocompleteParser.js @@ -718,6 +718,9 @@ function peg$parse(input, options) { s1 = peg$parsereimbursable(); if (s1 === peg$FAILED) { s1 = peg$parsebillable(); + if (s1 === peg$FAILED) { + s1 = peg$parsepolicyID(); + } } } } diff --git a/src/libs/SearchParser/autocompleteParser.peggy b/src/libs/SearchParser/autocompleteParser.peggy index 3ea24232ce32b..26baa274c697d 100644 --- a/src/libs/SearchParser/autocompleteParser.peggy +++ b/src/libs/SearchParser/autocompleteParser.peggy @@ -72,6 +72,7 @@ autocompleteKey "key" / groupBy / reimbursable / billable + / policyID ) filterKey From b4010cc33a5b80f3f0259f279f84fe5a7a41ae1e Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Thu, 17 Apr 2025 14:25:42 +0200 Subject: [PATCH 2/8] add workspace highlighting --- src/libs/SearchAutocompleteUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/SearchAutocompleteUtils.ts b/src/libs/SearchAutocompleteUtils.ts index 978d6b03bd31b..2f3a1945df83d 100644 --- a/src/libs/SearchAutocompleteUtils.ts +++ b/src/libs/SearchAutocompleteUtils.ts @@ -159,6 +159,7 @@ function filterOutRangesWithCorrectValue( case CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE: case CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED: case CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID: + case CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID: return substitutionMap[`${range.key}:${range.value}`] !== undefined; case CONST.SEARCH.SYNTAX_FILTER_KEYS.TO: From 17453dfe499bd9a7f0fb5a4bce90fedab0e4365b Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Thu, 17 Apr 2025 14:26:39 +0200 Subject: [PATCH 3/8] Add workspace autocomplete list --- .../Search/SearchAutocompleteList.tsx | 30 ++++++- .../SearchPageHeaderInput.tsx | 9 +- .../Search/SearchRouter/SearchRouter.tsx | 8 +- .../SearchRouter/buildSubstitutionsMap.ts | 13 ++- src/libs/SearchQueryUtils.ts | 82 ++++++++++++++++++- 5 files changed, 128 insertions(+), 14 deletions(-) diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index 2ce9c5329a70b..7cd88f66a8367 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -13,6 +13,7 @@ import UserListItem from '@components/SelectionList/UserListItem'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useFastSearchFromOptions from '@hooks/useFastSearchFromOptions'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import usePolicy from '@hooks/usePolicy'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -23,7 +24,7 @@ import memoize from '@libs/memoize'; import {combineOrderingOfReportsAndPersonalDetails, getSearchOptions, getValidPersonalDetailOptions} from '@libs/OptionsListUtils'; import type {Options, SearchOption} from '@libs/OptionsListUtils'; import Performance from '@libs/Performance'; -import {getAllTaxRates, getCleanedTagName} from '@libs/PolicyUtils'; +import {getAllTaxRates, getCleanedTagName, shouldShowPolicy} from '@libs/PolicyUtils'; import type {OptionData} from '@libs/ReportUtils'; import { getAutocompleteCategories, @@ -150,6 +151,7 @@ function SearchAutocompleteList( const personalDetails = usePersonalDetails(); const [reports = {}] = useOnyx(ONYXKEYS.COLLECTION.REPORT); const taxRates = getAllTaxRates(); + const {canUseLeftHandBar} = usePermissions(); const {options, areOptionsInitialized} = useOptionsList(); const searchOptions = useMemo(() => { @@ -219,6 +221,13 @@ function SearchAutocompleteList( return getAutocompleteRecentCategories(allRecentCategories, activeWorkspaceID); }, [activeWorkspaceID, allRecentCategories]); + const [policies = {}] = useOnyx(ONYXKEYS.COLLECTION.POLICY); + const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email}); + + const workspaceList = Object.values(policies) + .filter((singlePolicy) => !!singlePolicy && shouldShowPolicy(singlePolicy, false, currentUserLogin) && !singlePolicy?.isJoinRequestPending) + .map((singlePolicy) => ({id: singlePolicy?.id, name: singlePolicy?.name ?? ''})); + const [currencyList] = useOnyx(ONYXKEYS.CURRENCY_LIST); const currencyAutocompleteList = Object.keys(currencyList ?? {}).filter((currency) => !currencyList?.[currency]?.retired); const [recentCurrencyAutocompleteList] = useOnyx(ONYXKEYS.RECENTLY_USED_CURRENCIES); @@ -403,6 +412,21 @@ function SearchAutocompleteList( text: value, })); } + case CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID: { + const filteredPolicies = workspaceList + .filter((workspace) => workspace.name.toLowerCase().includes(autocompleteValue.toLowerCase()) && !alreadyAutocompletedKeys.includes(workspace.name.toLowerCase())) + .sort() + .slice(0, 10); + + return canUseLeftHandBar + ? filteredPolicies.map((workspace) => ({ + filterKey: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.POLICY_ID, + text: workspace.name, + autocompleteID: workspace.id, + mapKey: CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID, + })) + : []; + } default: { return []; } @@ -419,14 +443,16 @@ function SearchAutocompleteList( getParticipantsAutocompleteList, searchOptions.recentReports, typeAutocompleteList, + groupByAutocompleteList, statusAutocompleteList, expenseTypes, feedAutoCompleteList, workspaceCardFeeds, cardAutocompleteList, allCards, - groupByAutocompleteList, booleanTypes, + workspaceList, + canUseLeftHandBar, ]); const sortedRecentSearches = useMemo(() => { diff --git a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx index 0be5ef0ae02ce..4829bc7cf00b5 100644 --- a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx +++ b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx @@ -36,6 +36,7 @@ import { buildUserReadableQueryString, buildUserReadableQueryStringWithPolicyID, getQueryWithUpdatedValues, + getQueryWithUpdatedValuesWithoutPolicy, isDefaultExpensesQuery, isDefaultExpensesQueryWithPolicyIDCheck, sanitizeSearchValue, @@ -121,9 +122,9 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo }, [isDefaultQuery, queryText]); useEffect(() => { - const substitutionsMap = buildSubstitutionsMap(originalInputQuery, personalDetails, reports, taxRates, allCards, cardFeedNamesWithType); + const substitutionsMap = buildSubstitutionsMap(originalInputQuery, personalDetails, reports, taxRates, allCards, cardFeedNamesWithType, policies, canUseLeftHandBar); setAutocompleteSubstitutions(substitutionsMap); - }, [cardFeedNamesWithType, allCards, originalInputQuery, personalDetails, reports, taxRates]); + }, [cardFeedNamesWithType, allCards, originalInputQuery, personalDetails, reports, taxRates, policies, canUseLeftHandBar]); useEffect(() => { if (searchRouterListVisible) { @@ -167,7 +168,7 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo const submitSearch = useCallback( (queryString: SearchQueryString) => { const queryWithSubstitutions = getQueryWithSubstitutions(queryString, autocompleteSubstitutions); - const updatedQuery = getQueryWithUpdatedValues(queryWithSubstitutions, queryJSON.policyID); + const updatedQuery = canUseLeftHandBar ? getQueryWithUpdatedValuesWithoutPolicy(queryWithSubstitutions) : getQueryWithUpdatedValues(queryWithSubstitutions, queryJSON.policyID); if (!updatedQuery) { return; @@ -182,7 +183,7 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo setAutocompleteQueryValue(''); } }, - [autocompleteSubstitutions, hideSearchRouterList, originalInputQuery, queryJSON.policyID], + [autocompleteSubstitutions, hideSearchRouterList, originalInputQuery, queryJSON.policyID, canUseLeftHandBar], ); const onListItemPress = useCallback( diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index bed0431bce185..2c8eeba6f94f9 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -19,13 +19,14 @@ import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useDebouncedState from '@hooks/useDebouncedState'; import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import {scrollToRight} from '@libs/InputUtils'; import type {SearchOption} from '@libs/OptionsListUtils'; import type {OptionData} from '@libs/ReportUtils'; import {getAutocompleteQueryWithComma, getQueryWithoutAutocompletedPart} from '@libs/SearchAutocompleteUtils'; -import {getQueryWithUpdatedValues, sanitizeSearchValue} from '@libs/SearchQueryUtils'; +import {getQueryWithUpdatedValues, getQueryWithUpdatedValuesWithoutPolicy, sanitizeSearchValue} from '@libs/SearchQueryUtils'; import StringUtils from '@libs/StringUtils'; import Navigation from '@navigation/Navigation'; import type {ReportsSplitNavigatorParamList} from '@navigation/types'; @@ -82,6 +83,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla const [, recentSearchesMetadata] = useOnyx(ONYXKEYS.RECENT_SEARCHES); const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false}); const {activeWorkspaceID} = useActiveWorkspace(); + const {canUseLeftHandBar} = usePermissions(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const listRef = useRef(null); @@ -215,7 +217,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla const submitSearch = useCallback( (queryString: SearchQueryString) => { const queryWithSubstitutions = getQueryWithSubstitutions(queryString, autocompleteSubstitutions); - const updatedQuery = getQueryWithUpdatedValues(queryWithSubstitutions, activeWorkspaceID); + const updatedQuery = canUseLeftHandBar ? getQueryWithUpdatedValuesWithoutPolicy(queryWithSubstitutions) : getQueryWithUpdatedValues(queryWithSubstitutions, activeWorkspaceID); if (!updatedQuery) { return; } @@ -226,7 +228,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla setTextInputValue(''); setAutocompleteQueryValue(''); }, - [autocompleteSubstitutions, onRouterClose, setTextInputValue, activeWorkspaceID], + [autocompleteSubstitutions, onRouterClose, setTextInputValue, activeWorkspaceID, canUseLeftHandBar], ); const setTextAndUpdateSelection = useCallback( diff --git a/src/components/Search/SearchRouter/buildSubstitutionsMap.ts b/src/components/Search/SearchRouter/buildSubstitutionsMap.ts index a085446bf9f21..77a1c37e949b3 100644 --- a/src/components/Search/SearchRouter/buildSubstitutionsMap.ts +++ b/src/components/Search/SearchRouter/buildSubstitutionsMap.ts @@ -2,9 +2,9 @@ import type {OnyxCollection} from 'react-native-onyx'; import type {SearchAutocompleteQueryRange, SearchFilterKey} from '@components/Search/types'; import type {CardFeedNamesWithType} from '@libs/CardFeedUtils'; import {parse} from '@libs/SearchParser/autocompleteParser'; -import {getFilterDisplayValue} from '@libs/SearchQueryUtils'; +import {getFilterDisplayValue, getFilterDisplayValueWithPolicyID} from '@libs/SearchQueryUtils'; import CONST from '@src/CONST'; -import type {CardList, PersonalDetailsList, Report} from '@src/types/onyx'; +import type {CardList, PersonalDetailsList, Policy, Report} from '@src/types/onyx'; import type {SubstitutionMap} from './getQueryWithSubstitutions'; const getSubstitutionsKey = (filterKey: SearchFilterKey, value: string) => `${filterKey}:${value}`; @@ -32,6 +32,8 @@ function buildSubstitutionsMap( allTaxRates: Record, cardList: CardList, cardFeedNamesWithType: CardFeedNamesWithType, + policies: OnyxCollection, + canUseLeftHandBar?: boolean, ): SubstitutionMap { const parsedQuery = parse(query) as {ranges: SearchAutocompleteQueryRange[]}; @@ -63,9 +65,12 @@ function buildSubstitutionsMap( filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG || - filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED + filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED || + filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID ) { - const displayValue = getFilterDisplayValue(filterKey, filterValue, personalDetails, reports, cardList, cardFeedNamesWithType); + const displayValue = canUseLeftHandBar + ? getFilterDisplayValueWithPolicyID(filterKey, filterValue, personalDetails, reports, cardList, cardFeedNamesWithType, policies) + : getFilterDisplayValue(filterKey, filterValue, personalDetails, reports, cardList, cardFeedNamesWithType); // If displayValue === filterValue, then it means there is nothing to substitute, so we don't add any key to map if (displayValue !== filterValue) { diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 6e33591d3d476..e53961f6872f7 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -557,6 +557,65 @@ function getPolicyIDFromSearchQuery(queryJSON: SearchQueryJSON) { return policyID; } +/** + * A copy of `getFilterDisplayValue` handling the policy ID, used if you have access to the leftHandBar beta. + * When this beta is no longer needed, this method will be renamed to `getFilterDisplayValue` and will replace the old method. + * + * Formats a given `SearchQueryJSON` object into the human-readable string version of query. + * This format of query is the one which we want to display to users. + * Returns the human-readable "pretty" string for a specified filter value. + */ +function getFilterDisplayValueWithPolicyID( + filterName: string, + filterValue: string, + personalDetails: OnyxTypes.PersonalDetailsList | undefined, + reports: OnyxCollection, + cardList: OnyxTypes.CardList, + cardFeedNamesWithType: CardFeedNamesWithType, + policies: OnyxCollection, +) { + if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM || filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO) { + // login can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + return personalDetails?.[filterValue]?.displayName || filterValue; + } + if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID) { + const cardID = parseInt(filterValue, 10); + if (Number.isNaN(cardID)) { + return filterValue; + } + return getCardDescription(cardID, cardList) || filterValue; + } + if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN) { + return getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${filterValue}`]) || filterValue; + } + if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.AMOUNT) { + const frontendAmount = convertToFrontendAmountAsInteger(Number(filterValue)); + return Number.isNaN(frontendAmount) ? filterValue : frontendAmount.toString(); + } + if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG) { + return getCleanedTagName(filterValue); + } + if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED) { + const workspaceFeedKey = getWorkspaceCardFeedKey(filterValue); + + const workspaceValue = cardFeedNamesWithType[workspaceFeedKey]; + const domainValue = cardFeedNamesWithType[filterValue]; + + if (workspaceValue && workspaceValue.type === 'workspace') { + return workspaceValue.name; + } + + if (domainValue && domainValue.type === 'domain') { + return domainValue.name; + } + } + if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID) { + return policies?.[`${ONYXKEYS.COLLECTION.POLICY}${filterValue}`]?.name ?? filterValue; + } + return filterValue; +} + /** * Returns the human-readable "pretty" string for a specified filter value. */ @@ -663,7 +722,7 @@ function buildUserReadableQueryStringWithPolicyID( } else { displayQueryFilters = queryFilter.map((filter) => ({ operator: filter.operator, - value: getFilterDisplayValue(key, filter.value.toString(), PersonalDetails, reports, cardList, cardFeedNamesWithType), + value: getFilterDisplayValueWithPolicyID(key, filter.value.toString(), PersonalDetails, reports, cardList, cardFeedNamesWithType, policies), })); } title += buildFilterValuesString(getUserFriendlyKey(key), displayQueryFilters); @@ -832,6 +891,25 @@ function traverseAndUpdatedQuery(queryJSON: SearchQueryJSON, computeNodeValue: ( return standardQuery; } +/** + * A copy of `getQueryWithUpdatedValues` handling the policy ID, used if you have access to the leftHandBar beta. + * When this beta is no longer needed, this method will be renamed to `getQueryWithUpdatedValues` and will replace the old method. + * + * Returns new string query, after parsing it and traversing to update some filter values. + * If there are any personal emails, it will try to substitute them with accountIDs + */ +function getQueryWithUpdatedValuesWithoutPolicy(query: string) { + const queryJSON = buildSearchQueryJSON(query); + + if (!queryJSON) { + Log.alert(`${CONST.ERROR.ENSURE_BUGBOT} user query failed to parse`, {}, false); + return; + } + + const standardizedQuery = traverseAndUpdatedQuery(queryJSON, getUpdatedFilterValue); + return buildSearchQueryString(standardizedQuery); +} + /** * Returns new string query, after parsing it and traversing to update some filter values. * If there are any personal emails, it will try to substitute them with accountIDs @@ -887,6 +965,7 @@ export { buildUserReadableQueryString, buildUserReadableQueryStringWithPolicyID, getFilterDisplayValue, + getFilterDisplayValueWithPolicyID, buildQueryStringFromFilterFormValues, buildFilterFormValuesFromQuery, getPolicyIDFromSearchQuery, @@ -895,6 +974,7 @@ export { isCannedSearchQueryWithPolicyIDCheck, sanitizeSearchValue, getQueryWithUpdatedValues, + getQueryWithUpdatedValuesWithoutPolicy, getUserFriendlyKey, isDefaultExpensesQuery, shouldHighlight, From f18e704a03a74d2dab18554144633c72d987d20a Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Thu, 17 Apr 2025 14:54:36 +0200 Subject: [PATCH 4/8] fix tests typescripts --- tests/unit/Search/buildSubstitutionsMapTest.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/Search/buildSubstitutionsMapTest.ts b/tests/unit/Search/buildSubstitutionsMapTest.ts index 2761d62ca2824..f07a9de00cc6f 100644 --- a/tests/unit/Search/buildSubstitutionsMapTest.ts +++ b/tests/unit/Search/buildSubstitutionsMapTest.ts @@ -69,14 +69,14 @@ describe('buildSubstitutionsMap should return correct substitutions map', () => test('when there were no substitutions', () => { const userQuery = 'foo bar'; - const result = buildSubstitutionsMap(userQuery, personalDetailsMock, reportsMock, taxRatesMock, {}, cardFeedNamesWithTypeMock); + const result = buildSubstitutionsMap(userQuery, personalDetailsMock, reportsMock, taxRatesMock, {}, cardFeedNamesWithTypeMock, {}); expect(result).toStrictEqual({}); }); test('when query has a single substitution', () => { const userQuery = 'foo from:12345'; - const result = buildSubstitutionsMap(userQuery, personalDetailsMock, reportsMock, taxRatesMock, {}, cardFeedNamesWithTypeMock); + const result = buildSubstitutionsMap(userQuery, personalDetailsMock, reportsMock, taxRatesMock, {}, cardFeedNamesWithTypeMock, {}); expect(result).toStrictEqual({ 'from:John Doe': '12345', @@ -86,7 +86,7 @@ describe('buildSubstitutionsMap should return correct substitutions map', () => test('when query has multiple substitutions of different types', () => { const userQuery = 'from:78901,12345 to:nonExistingGuy@mail.com cardID:11223344 in:rep123 taxRate:id_TAX_1 feed:"11111111_Expensify Card"'; - const result = buildSubstitutionsMap(userQuery, personalDetailsMock, reportsMock, taxRatesMock, cardListMock, cardFeedNamesWithTypeMock); + const result = buildSubstitutionsMap(userQuery, personalDetailsMock, reportsMock, taxRatesMock, cardListMock, cardFeedNamesWithTypeMock, {}); expect(result).toStrictEqual({ 'from:Jane Doe': '78901', From dd58318e89dd52b2ae94d984c2ea76cfcded5431 Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Thu, 17 Apr 2025 16:15:16 +0200 Subject: [PATCH 5/8] Add canBeMissing param --- .../Search/SearchAutocompleteList.tsx | 26 +++++++++---------- .../SearchPageHeaderInput.tsx | 8 +++--- .../Search/SearchRouter/SearchRouter.tsx | 4 +-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index 7cd88f66a8367..61f6960f2d715 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -146,10 +146,10 @@ function SearchAutocompleteList( const {activeWorkspaceID} = useActiveWorkspace(); const policy = usePolicy(activeWorkspaceID); - const [betas] = useOnyx(ONYXKEYS.BETAS); - const [recentSearches] = useOnyx(ONYXKEYS.RECENT_SEARCHES); + const [betas] = useOnyx(ONYXKEYS.BETAS, {canBeMissing: true}); + const [recentSearches] = useOnyx(ONYXKEYS.RECENT_SEARCHES, {canBeMissing: true}); const personalDetails = usePersonalDetails(); - const [reports = {}] = useOnyx(ONYXKEYS.COLLECTION.REPORT); + const [reports = {}] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const taxRates = getAllTaxRates(); const {canUseLeftHandBar} = usePermissions(); @@ -169,8 +169,8 @@ function SearchAutocompleteList( const expenseTypes = Object.values(CONST.SEARCH.TRANSACTION_TYPE); const booleanTypes = Object.values(CONST.SEARCH.BOOLEAN); - const [userCardList] = useOnyx(ONYXKEYS.CARD_LIST); - const [workspaceCardFeeds] = useOnyx(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST); + const [userCardList] = useOnyx(ONYXKEYS.CARD_LIST, {canBeMissing: true}); + const [workspaceCardFeeds] = useOnyx(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST, {canBeMissing: true}); const allCards = useMemo(() => mergeCardListWithWorkspaceFeeds(workspaceCardFeeds ?? CONST.EMPTY_OBJECT, userCardList), [userCardList, workspaceCardFeeds]); const cardAutocompleteList = Object.values(allCards); const cardFeedNamesWithType = useMemo(() => { @@ -212,8 +212,8 @@ function SearchAutocompleteList( const taxAutocompleteList = useMemo(() => getAutocompleteTaxList(taxRates, policy), [policy, taxRates]); - const [allPolicyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES); - const [allRecentCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES); + const [allPolicyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES, {canBeMissing: false}); + const [allRecentCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES, {canBeMissing: true}); const categoryAutocompleteList = useMemo(() => { return getAutocompleteCategories(allPolicyCategories, activeWorkspaceID); }, [activeWorkspaceID, allPolicyCategories]); @@ -221,18 +221,18 @@ function SearchAutocompleteList( return getAutocompleteRecentCategories(allRecentCategories, activeWorkspaceID); }, [activeWorkspaceID, allRecentCategories]); - const [policies = {}] = useOnyx(ONYXKEYS.COLLECTION.POLICY); - const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email}); + const [policies = {}] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: false}); + const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email, canBeMissing: false}); const workspaceList = Object.values(policies) .filter((singlePolicy) => !!singlePolicy && shouldShowPolicy(singlePolicy, false, currentUserLogin) && !singlePolicy?.isJoinRequestPending) .map((singlePolicy) => ({id: singlePolicy?.id, name: singlePolicy?.name ?? ''})); - const [currencyList] = useOnyx(ONYXKEYS.CURRENCY_LIST); + const [currencyList] = useOnyx(ONYXKEYS.CURRENCY_LIST, {canBeMissing: false}); const currencyAutocompleteList = Object.keys(currencyList ?? {}).filter((currency) => !currencyList?.[currency]?.retired); - const [recentCurrencyAutocompleteList] = useOnyx(ONYXKEYS.RECENTLY_USED_CURRENCIES); - const [allPoliciesTags] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS); - const [allRecentTags] = useOnyx(ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS); + const [recentCurrencyAutocompleteList] = useOnyx(ONYXKEYS.RECENTLY_USED_CURRENCIES, {canBeMissing: true}); + const [allPoliciesTags] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS, {canBeMissing: false}); + const [allRecentTags] = useOnyx(ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS, {canBeMissing: true}); const tagAutocompleteList = useMemo(() => { return getAutocompleteTags(allPoliciesTags, activeWorkspaceID); }, [activeWorkspaceID, allPoliciesTags]); diff --git a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx index 4829bc7cf00b5..58394955eb1ea 100644 --- a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx +++ b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx @@ -69,11 +69,11 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo const theme = useTheme(); const {shouldUseNarrowLayout: displayNarrowHeader} = useResponsiveLayout(); const personalDetails = usePersonalDetails(); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); - const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: false}); + const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: false}); const taxRates = useMemo(() => getAllTaxRates(), []); - const [userCardList] = useOnyx(ONYXKEYS.CARD_LIST); - const [workspaceCardFeeds] = useOnyx(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST); + const [userCardList] = useOnyx(ONYXKEYS.CARD_LIST, {canBeMissing: false}); + const [workspaceCardFeeds] = useOnyx(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST, {canBeMissing: true}); const allCards = useMemo(() => mergeCardListWithWorkspaceFeeds(workspaceCardFeeds ?? CONST.EMPTY_OBJECT, userCardList), [userCardList, workspaceCardFeeds]); const cardFeedNamesWithType = useMemo(() => { return getCardFeedNamesWithType({workspaceCardFeeds, translate}); diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index 2c8eeba6f94f9..9e1fc8c3074da 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -80,8 +80,8 @@ type SearchRouterProps = { function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDisplayed}: SearchRouterProps, ref: React.Ref) { const {translate} = useLocalize(); const styles = useThemeStyles(); - const [, recentSearchesMetadata] = useOnyx(ONYXKEYS.RECENT_SEARCHES); - const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false}); + const [, recentSearchesMetadata] = useOnyx(ONYXKEYS.RECENT_SEARCHES, {canBeMissing: true}); + const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false, canBeMissing: true}); const {activeWorkspaceID} = useActiveWorkspace(); const {canUseLeftHandBar} = usePermissions(); From 629aafea7ba9414c60225d632335d7e654f6c947 Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Tue, 22 Apr 2025 09:45:18 +0200 Subject: [PATCH 6/8] fix can be missing param for reports --- .../Search/SearchPageHeader/SearchPageHeaderInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx index 58394955eb1ea..b4c58a0712e7f 100644 --- a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx +++ b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx @@ -69,7 +69,7 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo const theme = useTheme(); const {shouldUseNarrowLayout: displayNarrowHeader} = useResponsiveLayout(); const personalDetails = usePersonalDetails(); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: false}); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: false}); const taxRates = useMemo(() => getAllTaxRates(), []); const [userCardList] = useOnyx(ONYXKEYS.CARD_LIST, {canBeMissing: false}); From 047f54305184615acfc0de8b9288e0c479734ff1 Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Tue, 22 Apr 2025 12:57:06 +0200 Subject: [PATCH 7/8] fix comment --- src/libs/SearchQueryUtils.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index bf89bbba998fb..8028b122ede73 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -565,8 +565,6 @@ function getPolicyIDFromSearchQuery(queryJSON: SearchQueryJSON) { * A copy of `getFilterDisplayValue` handling the policy ID, used if you have access to the leftHandBar beta. * When this beta is no longer needed, this method will be renamed to `getFilterDisplayValue` and will replace the old method. * - * Formats a given `SearchQueryJSON` object into the human-readable string version of query. - * This format of query is the one which we want to display to users. * Returns the human-readable "pretty" string for a specified filter value. */ function getFilterDisplayValueWithPolicyID( From 7f259f55a9d786675240fcedabaa1b42a1cd0bbd Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Tue, 22 Apr 2025 18:39:41 +0200 Subject: [PATCH 8/8] review comments --- .../Search/SearchAutocompleteList.tsx | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index 61f6960f2d715..4be2810d9d1a8 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -224,9 +224,13 @@ function SearchAutocompleteList( const [policies = {}] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: false}); const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email, canBeMissing: false}); - const workspaceList = Object.values(policies) - .filter((singlePolicy) => !!singlePolicy && shouldShowPolicy(singlePolicy, false, currentUserLogin) && !singlePolicy?.isJoinRequestPending) - .map((singlePolicy) => ({id: singlePolicy?.id, name: singlePolicy?.name ?? ''})); + const workspaceList = useMemo( + () => + Object.values(policies) + .filter((singlePolicy) => !!singlePolicy && shouldShowPolicy(singlePolicy, false, currentUserLogin) && !singlePolicy?.isJoinRequestPending) + .map((singlePolicy) => ({id: singlePolicy?.id, name: singlePolicy?.name ?? ''})), + [policies, currentUserLogin], + ); const [currencyList] = useOnyx(ONYXKEYS.CURRENCY_LIST, {canBeMissing: false}); const currencyAutocompleteList = Object.keys(currencyList ?? {}).filter((currency) => !currencyList?.[currency]?.retired); @@ -413,19 +417,20 @@ function SearchAutocompleteList( })); } case CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID: { + if (!canUseLeftHandBar) { + return []; + } const filteredPolicies = workspaceList .filter((workspace) => workspace.name.toLowerCase().includes(autocompleteValue.toLowerCase()) && !alreadyAutocompletedKeys.includes(workspace.name.toLowerCase())) .sort() .slice(0, 10); - return canUseLeftHandBar - ? filteredPolicies.map((workspace) => ({ - filterKey: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.POLICY_ID, - text: workspace.name, - autocompleteID: workspace.id, - mapKey: CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID, - })) - : []; + return filteredPolicies.map((workspace) => ({ + filterKey: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.POLICY_ID, + text: workspace.name, + autocompleteID: workspace.id, + mapKey: CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID, + })); } default: { return [];