From a1cfbc53208aefd9003231799b7ebb693d07cda9 Mon Sep 17 00:00:00 2001 From: Situ Chandra Shil <108292595+situchan@users.noreply.github.com> Date: Tue, 21 Oct 2025 00:23:03 +1100 Subject: [PATCH] Revert "Add type expense report" --- src/CONST/index.ts | 11 +- .../Search/SearchAutocompleteList.tsx | 3 - src/components/Search/SearchList/index.tsx | 9 +- .../SearchPageHeader/SearchFiltersBar.tsx | 6 +- src/components/Search/index.tsx | 39 ++- src/components/Search/types.ts | 3 +- .../Search/TransactionGroupListExpanded.tsx | 34 +- .../Search/TransactionGroupListItem.tsx | 50 ++- .../SelectionListWithSections/types.ts | 6 +- src/hooks/useAdvancedSearchFilters.ts | 24 +- src/languages/de.ts | 2 +- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- src/languages/fr.ts | 2 +- src/languages/it.ts | 2 +- src/languages/ja.ts | 2 +- src/languages/nl.ts | 2 +- src/languages/pl.ts | 2 +- src/languages/pt-BR.ts | 2 +- src/languages/zh-hans.ts | 2 +- src/libs/SearchParser/autocompleteParser.js | 307 ++++++++++-------- src/libs/SearchParser/baseRules.peggy | 2 + src/libs/SearchParser/searchParser.js | 307 ++++++++++-------- src/libs/SearchUIUtils.ts | 49 ++- src/libs/actions/IOU.ts | 11 +- src/pages/Search/AdvancedSearchFilters.tsx | 17 +- src/pages/Search/EmptySearchView.tsx | 9 +- .../SearchFiltersStatusPage.tsx | 3 +- src/pages/Search/SearchPage.tsx | 4 +- src/types/form/SearchAdvancedFiltersForm.ts | 55 +--- tests/actions/IOUTest.ts | 17 +- tests/ui/components/EmptySearchViewTest.tsx | 8 +- tests/unit/Search/SearchUIUtilsTest.ts | 74 +++-- .../Search/handleActionButtonPressTest.ts | 2 +- tests/unit/TransactionGroupListItemTest.tsx | 4 +- 35 files changed, 532 insertions(+), 542 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 92dc8405d2fa..3a83e61b564c 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -6478,7 +6478,6 @@ const CONST = { ME: 'me', DATA_TYPES: { EXPENSE: 'expense', - EXPENSE_REPORT: 'expense-report', INVOICE: 'invoice', TASK: 'task', TRIP: 'trip', @@ -6536,6 +6535,7 @@ const CONST = { DESC: 'desc', }, GROUP_BY: { + REPORTS: 'reports', FROM: 'from', CARD: 'card', WITHDRAWAL_ID: 'withdrawal-id', @@ -6558,14 +6558,6 @@ const CONST = { DONE: 'done', PAID: 'paid', }, - EXPENSE_REPORT: { - ALL: '', - DRAFTS: 'drafts', - OUTSTANDING: 'outstanding', - APPROVED: 'approved', - DONE: 'done', - PAID: 'paid', - }, INVOICE: { ALL: '', OUTSTANDING: 'outstanding', @@ -6719,6 +6711,7 @@ const CONST = { get SEARCH_USER_FRIENDLY_VALUES_MAP() { return { [this.TRANSACTION_TYPE.PER_DIEM]: 'per-diem', + [this.GROUP_BY.REPORTS]: 'report', [this.STATUS.EXPENSE.DRAFTS]: 'draft', }; }, diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index 9fd75977cbf7..067002dab2c6 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -227,9 +227,6 @@ function SearchAutocompleteList({ case CONST.SEARCH.DATA_TYPES.EXPENSE: suggestedStatuses = Object.values(CONST.SEARCH.STATUS.EXPENSE); break; - case CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT: - suggestedStatuses = Object.values(CONST.SEARCH.STATUS.EXPENSE_REPORT); - break; case CONST.SEARCH.DATA_TYPES.INVOICE: suggestedStatuses = Object.values(CONST.SEARCH.STATUS.INVOICE); break; diff --git a/src/components/Search/SearchList/index.tsx b/src/components/Search/SearchList/index.tsx index ac737a88db4b..00158be78da9 100644 --- a/src/components/Search/SearchList/index.tsx +++ b/src/components/Search/SearchList/index.tsx @@ -169,7 +169,7 @@ function SearchList({ }: SearchListProps) { const styles = useThemeStyles(); - const {hash, groupBy, type} = queryJSON; + const {hash, groupBy} = queryJSON; const flattenedItems = useMemo(() => { if (groupBy) { if (!isTransactionGroupListItemArray(data)) { @@ -223,6 +223,7 @@ function SearchList({ const handleLongPressRow = useCallback( (item: SearchListItem) => { const currentRoute = navigationRef.current?.getCurrentRoute(); + const isReadonlyGroupBy = groupBy && groupBy !== CONST.SEARCH.GROUP_BY.REPORTS; if (currentRoute && route.key !== currentRoute.key) { return; } @@ -232,7 +233,7 @@ function SearchList({ return; } // disable long press for empty expense reports - if ('transactions' in item && item.transactions.length === 0 && !groupBy) { + if ('transactions' in item && item.transactions.length === 0 && !isReadonlyGroupBy) { return; } if (isMobileSelectionModeEnabled) { @@ -318,7 +319,6 @@ function SearchList({ isDisabled={isDisabled} allReports={allReports} groupBy={groupBy} - searchType={type} userWalletTierName={userWalletTierName} isUserValidated={isUserValidated} personalDetails={personalDetails} @@ -333,7 +333,6 @@ function SearchList({ ); }, [ - type, groupBy, newTransactions, shouldAnimate, @@ -362,7 +361,7 @@ function SearchList({ ], ); - const tableHeaderVisible = (canSelectMultiple || !!SearchTableHeader) && (!groupBy || type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT); + const tableHeaderVisible = (canSelectMultiple || !!SearchTableHeader) && (!groupBy || groupBy === CONST.SEARCH.GROUP_BY.REPORTS); const selectAllButtonVisible = canSelectMultiple && !SearchTableHeader; const isSelectAllChecked = selectedItemsLength > 0 && selectedItemsLength === flattenedItemsWithoutPendingDelete.length; diff --git a/src/components/Search/SearchPageHeader/SearchFiltersBar.tsx b/src/components/Search/SearchPageHeader/SearchFiltersBar.tsx index bc184f53feb7..02a99a0bcc80 100644 --- a/src/components/Search/SearchPageHeader/SearchFiltersBar.tsx +++ b/src/components/Search/SearchPageHeader/SearchFiltersBar.tsx @@ -152,12 +152,12 @@ function SearchFiltersBar({ }, [flatFilters, allFeeds, allCards]); const [statusOptions, status] = useMemo(() => { - const options = type ? getStatusOptions(type.value) : []; + const options = type ? getStatusOptions(type.value, groupBy?.value) : []; const value = [ Array.isArray(unsafeStatus) ? options.filter((option) => unsafeStatus.includes(option.value)) : (options.find((option) => option.value === unsafeStatus) ?? []), ].flat(); return [options, value]; - }, [unsafeStatus, type]); + }, [unsafeStatus, type, groupBy]); const [hasOptions, has] = useMemo(() => { const hasFilterValues = flatFilters.find((filter) => filter.key === CONST.SEARCH.SYNTAX_FILTER_KEYS.HAS)?.filters?.map((filter) => filter.value); @@ -456,7 +456,7 @@ function SearchFiltersBar({ const filters = useMemo(() => { const fromValue = filterFormValues.from?.map((currentAccountID) => personalDetails?.[currentAccountID]?.displayName ?? currentAccountID) ?? []; - const shouldDisplayGroupByFilter = !!groupBy?.value; + const shouldDisplayGroupByFilter = !!groupBy?.value && groupBy?.value !== CONST.SEARCH.GROUP_BY.REPORTS; const shouldDisplayGroupCurrencyFilter = shouldDisplayGroupByFilter && hasMultipleOutputCurrency; const shouldDisplayFeedFilter = feedOptions.length > 1 && !!filterFormValues.feed; const shouldDisplayPostedFilter = !!filterFormValues.feed && (!!filterFormValues.postedOn || !!filterFormValues.postedAfter || !!filterFormValues.postedBefore); diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 9079f8fa0cd4..1966a453b9f8 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -316,8 +316,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); - const validGroupBy = groupBy && Object.values(CONST.SEARCH.GROUP_BY).includes(groupBy) ? groupBy : undefined; - const isSearchResultsEmpty = !searchResults?.data || isSearchResultsEmptyUtil(searchResults, validGroupBy); + const isSearchResultsEmpty = !searchResults?.data || isSearchResultsEmptyUtil(searchResults, groupBy); useEffect(() => { if (!isFocused) { @@ -385,13 +384,13 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS // Group-by option cannot be used for chats or tasks const isChat = type === CONST.SEARCH.DATA_TYPES.CHAT; const isTask = type === CONST.SEARCH.DATA_TYPES.TASK; - if (validGroupBy && (isChat || isTask)) { + if (groupBy && (isChat || isTask)) { return [[], 0]; } - const data1 = getSections(type, searchResults.data, accountID, formatPhoneNumber, validGroupBy, exportReportActions, searchKey, archivedReportsIdSet, queryJSON); + const data1 = getSections(type, searchResults.data, accountID, formatPhoneNumber, groupBy, exportReportActions, searchKey, archivedReportsIdSet, queryJSON); return [data1, data1.length]; - }, [searchKey, exportReportActions, validGroupBy, isDataLoaded, searchResults, type, archivedReportsIdSet, formatPhoneNumber, accountID, queryJSON]); + }, [searchKey, exportReportActions, groupBy, isDataLoaded, searchResults, type, archivedReportsIdSet, formatPhoneNumber, accountID, queryJSON]); useEffect(() => { /** We only want to display the skeleton for the status filters the first time we load them for a specific data type */ @@ -425,7 +424,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS return; } const newTransactionList: SelectedTransactions = {}; - if (validGroupBy) { + if (groupBy) { data.forEach((transactionGroup) => { if (!Object.hasOwn(transactionGroup, 'transactions') || !('transactions' in transactionGroup)) { return; @@ -533,7 +532,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS if (!data.length || isRefreshingSelection.current) { return; } - const areItemsGrouped = !!validGroupBy; + const areItemsGrouped = !!groupBy; const flattenedItems = areItemsGrouped ? (data as TransactionGroupListItemType[]).flatMap((item) => item.transactions) : data; const areAllItemsSelected = flattenedItems.length === Object.keys(selectedTransactions).length; @@ -543,7 +542,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS if (!areAllItemsSelected) { selectAllMatchingItems(false); } - }, [isFocused, data, searchResults?.search?.hasMoreResults, selectedTransactions, selectAllMatchingItems, shouldShowSelectAllMatchingItems, validGroupBy]); + }, [isFocused, data, searchResults?.search?.hasMoreResults, selectedTransactions, selectAllMatchingItems, shouldShowSelectAllMatchingItems, groupBy]); const toggleTransaction = useCallback( (item: SearchListItem, itemTransactions?: TransactionListItemType[]) => { @@ -727,13 +726,12 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS const isChat = type === CONST.SEARCH.DATA_TYPES.CHAT; const isTask = type === CONST.SEARCH.DATA_TYPES.TASK; - const isExpenseReportType = type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT; - const canSelectMultiple = !isChat && !isTask && (!isSmallScreenWidth || isMobileSelectionModeEnabled) && validGroupBy !== CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID; - const ListItem = getListItem(type, status, validGroupBy); + const canSelectMultiple = !isChat && !isTask && (!isSmallScreenWidth || isMobileSelectionModeEnabled) && groupBy !== CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID; + const ListItem = getListItem(type, status, groupBy); const sortedSelectedData = useMemo( () => - getSortedSections(type, status, data, localeCompare, sortBy, sortOrder, validGroupBy).map((item) => { + getSortedSections(type, status, data, localeCompare, sortBy, sortOrder, groupBy).map((item) => { const baseKey = isChat ? `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${(item as ReportActionListItemType).reportActionID}` : `${ONYXKEYS.COLLECTION.TRANSACTION}${(item as TransactionListItemType).transactionID}`; @@ -754,7 +752,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS return mapToItemWithAdditionalInfo(item, selectedTransactions, canSelectMultiple, shouldAnimateInHighlight, hash); }), - [type, status, data, sortBy, sortOrder, validGroupBy, isChat, newSearchResultKey, selectedTransactions, canSelectMultiple, localeCompare, hash], + [type, status, data, sortBy, sortOrder, groupBy, isChat, newSearchResultKey, selectedTransactions, canSelectMultiple, localeCompare, hash], ); const hasErrors = Object.keys(searchResults?.errors ?? {}).length > 0 && !isOffline; @@ -782,7 +780,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS }, [isFocused, searchResults?.search?.hasMoreResults, shouldShowLoadingMoreItems, shouldShowLoadingState, offset, data.length]); const toggleAllTransactions = useCallback(() => { - const areItemsGrouped = !!validGroupBy || isExpenseReportType; + const areItemsGrouped = !!groupBy; const totalSelected = Object.keys(selectedTransactions).length; if (totalSelected > 0) { @@ -813,7 +811,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS ), data, ); - }, [clearSelectedTransactions, data, validGroupBy, reportActionsArray, selectedTransactions, setSelectedTransactions, outstandingReportsByPolicyID, isExpenseReportType]); + }, [clearSelectedTransactions, data, groupBy, reportActionsArray, selectedTransactions, setSelectedTransactions, outstandingReportsByPolicyID]); const onLayout = useCallback(() => handleSelectionListScroll(sortedSelectedData, searchListRef.current), [handleSelectionListScroll, sortedSelectedData]); @@ -862,6 +860,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS @@ -876,9 +875,9 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS const shouldShowYear = shouldShowYearUtil(searchResults?.data); const {shouldShowAmountInWideColumn, shouldShowTaxAmountInWideColumn} = getWideAmountIndicators(searchResults?.data); - const shouldShowSorting = !validGroupBy; - const shouldShowTableHeader = isLargeScreenWidth && !isChat && !validGroupBy && !isExpenseReportType; - const tableHeaderVisible = (canSelectMultiple || shouldShowTableHeader) && (!validGroupBy || isExpenseReportType); + const shouldShowSorting = !groupBy; + const shouldShowTableHeader = isLargeScreenWidth && !isChat && !groupBy; + const tableHeaderVisible = (canSelectMultiple || shouldShowTableHeader) && (!groupBy || groupBy === CONST.SEARCH.GROUP_BY.REPORTS); return ( @@ -898,7 +897,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS ) } diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index d8560da954e2..7a204efefd6e 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -86,11 +86,10 @@ type PaymentData = { type SortOrder = ValueOf; type SearchColumnType = ValueOf; type ExpenseSearchStatus = ValueOf; -type ExpenseReportSearchStatus = ValueOf; type InvoiceSearchStatus = ValueOf; type TripSearchStatus = ValueOf; type TaskSearchStatus = ValueOf; -type SingularSearchStatus = ExpenseSearchStatus | ExpenseReportSearchStatus | InvoiceSearchStatus | TripSearchStatus | TaskSearchStatus; +type SingularSearchStatus = ExpenseSearchStatus | InvoiceSearchStatus | TripSearchStatus | TaskSearchStatus; type SearchStatus = SingularSearchStatus | SingularSearchStatus[]; type SearchGroupBy = ValueOf; type TableColumnSize = ValueOf; diff --git a/src/components/SelectionListWithSections/Search/TransactionGroupListExpanded.tsx b/src/components/SelectionListWithSections/Search/TransactionGroupListExpanded.tsx index 9307a33c0bb8..328fb3fb2fc7 100644 --- a/src/components/SelectionListWithSections/Search/TransactionGroupListExpanded.tsx +++ b/src/components/SelectionListWithSections/Search/TransactionGroupListExpanded.tsx @@ -38,7 +38,7 @@ function TransactionGroupListExpanded({ transactionsVisibleLimit, setTransactionsVisibleLimit, isEmpty, - isExpenseReportType, + isGroupByReports, transactionsSnapshot, shouldDisplayEmptyView, searchTransactions, @@ -53,14 +53,14 @@ function TransactionGroupListExpanded({ }, [transactionsSnapshot]); const visibleTransactions = useMemo(() => { - if (isExpenseReportType) { + if (isGroupByReports) { return transactions.slice(0, transactionsVisibleLimit); } return transactions; - }, [transactions, transactionsVisibleLimit, isExpenseReportType]); + }, [transactions, transactionsVisibleLimit, isGroupByReports]); const currentColumns = useMemo(() => { - if (isExpenseReportType) { + if (isGroupByReports) { return columns ?? []; } if (!transactionsSnapshot?.data) { @@ -69,23 +69,23 @@ function TransactionGroupListExpanded({ const columnsToShow = getColumnsToShow(accountID, transactionsSnapshot?.data, false, transactionsSnapshot?.search.type === CONST.SEARCH.DATA_TYPES.TASK); return (Object.keys(columnsToShow) as SearchColumnType[]).filter((col) => columnsToShow[col]); - }, [accountID, columns, isExpenseReportType, transactionsSnapshot?.data, transactionsSnapshot?.search.type]); + }, [accountID, columns, isGroupByReports, transactionsSnapshot?.data, transactionsSnapshot?.search.type]); const areAllOptionalColumnsHidden = useMemo(() => { - if (isExpenseReportType) { + if (isGroupByReports) { return areAllOptionalColumnsHiddenProp ?? false; } const canBeMissingColumns = getExpenseHeaders(groupBy) .filter((header) => header.canBeMissing) .map((header) => header.columnName); return canBeMissingColumns.every((column) => !currentColumns.includes(column)); - }, [areAllOptionalColumnsHiddenProp, currentColumns, groupBy, isExpenseReportType]); + }, [areAllOptionalColumnsHiddenProp, currentColumns, groupBy, isGroupByReports]); // Currently only the transaction report groups have transactions where the empty view makes sense - const shouldDisplayShowMoreButton = isExpenseReportType ? transactions.length > transactionsVisibleLimit : !!transactionsSnapshotMetadata?.hasMoreResults && !isOffline; + const shouldDisplayShowMoreButton = isGroupByReports ? transactions.length > transactionsVisibleLimit : !!transactionsSnapshotMetadata?.hasMoreResults && !isOffline; const currentOffset = transactionsSnapshotMetadata?.offset ?? 0; const shouldShowLoadingOnSearch = !!(!transactions?.length && transactionsSnapshotMetadata?.isLoading) || currentOffset > 0; - const shouldDisplayLoadingIndicator = !isExpenseReportType && !!transactionsSnapshotMetadata?.isLoading && shouldShowLoadingOnSearch; + const shouldDisplayLoadingIndicator = !isGroupByReports && !!transactionsSnapshotMetadata?.isLoading && shouldShowLoadingOnSearch; const {isLargeScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout(); const {amountColumnSize, dateColumnSize, taxAmountColumnSize} = useMemo(() => { @@ -115,7 +115,7 @@ function TransactionGroupListExpanded({ }; // The arrow navigation in RHP is only allowed for group-by:reports - if (!isExpenseReportType) { + if (!isGroupByReports) { navigateToTransactionThread(); return; } @@ -131,12 +131,12 @@ function TransactionGroupListExpanded({ }; const onShowMoreButtonPress = useCallback(() => { - if (isExpenseReportType) { + if (isGroupByReports) { setTransactionsVisibleLimit((currentPageSize) => currentPageSize + CONST.TRANSACTION.RESULTS_PAGE_SIZE); } else if (!isOffline && transactionsQueryJSON) { searchTransactions(CONST.SEARCH.RESULTS_PAGE_SIZE); } - }, [isExpenseReportType, isOffline, transactionsQueryJSON, setTransactionsVisibleLimit, searchTransactions]); + }, [isGroupByReports, isOffline, transactionsQueryJSON, setTransactionsVisibleLimit, searchTransactions]); if (shouldDisplayEmptyView) { return ( @@ -155,13 +155,7 @@ function TransactionGroupListExpanded({ <> {isLargeScreenWidth && ( ({ onButtonPress={() => { openReportInRHP(transaction); }} - style={[styles.noBorderRadius, shouldUseNarrowLayout ? [styles.p3, styles.pt2] : [styles.ph3, styles.pv1Half], isExpenseReportType && styles.pr10]} + style={[styles.noBorderRadius, shouldUseNarrowLayout ? [styles.p3, styles.pt2] : [styles.ph3, styles.pv1Half], isGroupByReports && styles.pr10]} isReportItemChild isInSingleTransactionReport={isInSingleTransactionReport} areAllOptionalColumnsHidden={areAllOptionalColumnsHidden} diff --git a/src/components/SelectionListWithSections/Search/TransactionGroupListItem.tsx b/src/components/SelectionListWithSections/Search/TransactionGroupListItem.tsx index 1b45ff2282e5..874dae112efa 100644 --- a/src/components/SelectionListWithSections/Search/TransactionGroupListItem.tsx +++ b/src/components/SelectionListWithSections/Search/TransactionGroupListItem.tsx @@ -53,7 +53,6 @@ function TransactionGroupListItem({ shouldSyncFocus, columns, groupBy, - searchType, accountID, isOffline, areAllOptionalColumnsHidden, @@ -86,12 +85,12 @@ function TransactionGroupListItem({ const selectedTransactionIDsSet = useMemo(() => new Set(selectedTransactionIDs), [selectedTransactionIDs]); const [transactionsSnapshot] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${groupItem.transactionsQueryJSON?.hash}`, {canBeMissing: true}); - const isExpenseReportType = searchType === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT; + const isGroupByReports = groupBy === CONST.SEARCH.GROUP_BY.REPORTS; const [transactionsVisibleLimit, setTransactionsVisibleLimit] = useState(CONST.TRANSACTION.RESULTS_PAGE_SIZE as number); const [isExpanded, setIsExpanded] = useState(false); const transactions = useMemo(() => { - if (isExpenseReportType) { + if (isGroupByReports) { return groupItem.transactions; } if (!transactionsSnapshot?.data) { @@ -102,7 +101,7 @@ function TransactionGroupListItem({ ...transactionItem, isSelected: selectedTransactionIDsSet.has(transactionItem.transactionID), })); - }, [isExpenseReportType, transactionsSnapshot?.data, accountID, formatPhoneNumber, groupItem.transactions, selectedTransactionIDsSet]); + }, [isGroupByReports, transactionsSnapshot?.data, accountID, formatPhoneNumber, groupItem.transactions, selectedTransactionIDsSet]); const selectedItemsLength = useMemo(() => { return transactions.reduce((acc, transaction) => { @@ -119,7 +118,7 @@ function TransactionGroupListItem({ const isEmpty = transactions.length === 0; // Currently only the transaction report groups have transactions where the empty view makes sense - const shouldDisplayEmptyView = isEmpty && isExpenseReportType; + const shouldDisplayEmptyView = isEmpty && isGroupByReports; const isDisabledOrEmpty = isEmpty || isDisabled; const searchTransactions = useCallback( @@ -167,13 +166,13 @@ function TransactionGroupListItem({ }, [isExpanded]); const onPress = useCallback(() => { - if (isExpenseReportType || transactions.length === 0) { + if (isGroupByReports || transactions.length === 0) { onSelectRow(item, transactionPreviewData); } - if (!isExpenseReportType) { + if (!isGroupByReports) { handleToggle(); } - }, [isExpenseReportType, transactions.length, onSelectRow, transactionPreviewData, item, handleToggle]); + }, [isGroupByReports, transactions.length, onSelectRow, transactionPreviewData, item, handleToggle]); const onLongPress = useCallback(() => { if (isEmpty) { @@ -184,9 +183,9 @@ function TransactionGroupListItem({ const onCheckboxPress = useCallback( (val: TItem) => { - onCheckboxPressRow?.(val, isExpenseReportType ? undefined : transactions); + onCheckboxPressRow?.(val, isGroupByReports ? undefined : transactions); }, - [onCheckboxPressRow, transactions, isExpenseReportType], + [onCheckboxPressRow, transactions, isGroupByReports], ); const onExpandIconPress = useCallback(() => { @@ -200,6 +199,18 @@ function TransactionGroupListItem({ const getHeader = useMemo(() => { const headers: Record = { + [CONST.SEARCH.GROUP_BY.REPORTS]: ( + onSelectRow(listItem, transactionPreviewData)} + onCheckboxPress={onCheckboxPress} + isDisabled={isDisabledOrEmpty} + isFocused={isFocused} + canSelectMultiple={canSelectMultiple} + isSelectAllChecked={isSelectAllChecked} + isIndeterminate={isIndeterminate} + /> + ), [CONST.SEARCH.GROUP_BY.FROM]: ( ({ ), }; - if (searchType === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT) { - return ( - onSelectRow(listItem, transactionPreviewData)} - onCheckboxPress={onCheckboxPress} - isDisabled={isDisabledOrEmpty} - isFocused={isFocused} - canSelectMultiple={canSelectMultiple} - isSelectAllChecked={isSelectAllChecked} - isIndeterminate={isIndeterminate} - /> - ); - } - if (!groupBy) { return null; } return headers[groupBy]; - }, [groupItem, onSelectRow, transactionPreviewData, onCheckboxPress, isDisabledOrEmpty, isFocused, canSelectMultiple, isSelectAllChecked, isIndeterminate, groupBy, searchType]); + }, [groupItem, onSelectRow, transactionPreviewData, onCheckboxPress, isDisabledOrEmpty, isFocused, canSelectMultiple, isSelectAllChecked, isIndeterminate, groupBy]); useSyncFocus(pressableRef, !!isFocused, shouldSyncFocus); @@ -305,7 +301,7 @@ function TransactionGroupListItem({ setTransactionsVisibleLimit={setTransactionsVisibleLimit} isEmpty={isEmpty} shouldDisplayEmptyView={shouldDisplayEmptyView} - isExpenseReportType={isExpenseReportType} + isGroupByReports={isGroupByReports} transactionsSnapshot={transactionsSnapshot} transactionsQueryJSON={groupItem.transactionsQueryJSON} searchTransactions={searchTransactions} diff --git a/src/components/SelectionListWithSections/types.ts b/src/components/SelectionListWithSections/types.ts index bd3db6f76349..7f39a2e56e8d 100644 --- a/src/components/SelectionListWithSections/types.ts +++ b/src/components/SelectionListWithSections/types.ts @@ -31,7 +31,6 @@ import type {Attendee, SplitExpense} from '@src/types/onyx/IOU'; import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; import type { SearchCardGroup, - SearchDataTypes, SearchMemberGroup, SearchPersonalDetails, SearchReport, @@ -356,7 +355,7 @@ type TransactionGroupListItemType = ListItem & { transactionsQueryJSON?: SearchQueryJSON; }; -type TransactionReportGroupListItemType = TransactionGroupListItemType & {groupedBy: typeof CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT} & SearchReport & { +type TransactionReportGroupListItemType = TransactionGroupListItemType & {groupedBy: typeof CONST.SEARCH.GROUP_BY.REPORTS} & SearchReport & { /** The personal details of the user requesting money */ from: SearchPersonalDetails; @@ -522,7 +521,6 @@ type TaskListItemProps = ListItemProps & { type TransactionGroupListItemProps = ListItemProps & { groupBy?: SearchGroupBy; - searchType?: SearchDataTypes; policies?: OnyxCollection; accountID?: number; columns?: SearchColumnType[]; @@ -539,7 +537,7 @@ type TransactionGroupListExpandedProps = Pick< transactionsVisibleLimit: number; setTransactionsVisibleLimit: React.Dispatch>; isEmpty: boolean; - isExpenseReportType: boolean; + isGroupByReports: boolean; transactionsSnapshot?: SearchResults; shouldDisplayEmptyView: boolean; transactionsQueryJSON?: SearchQueryJSON; diff --git a/src/hooks/useAdvancedSearchFilters.ts b/src/hooks/useAdvancedSearchFilters.ts index d4bcd759768d..fd970f5e55af 100644 --- a/src/hooks/useAdvancedSearchFilters.ts +++ b/src/hooks/useAdvancedSearchFilters.ts @@ -48,30 +48,8 @@ const typeFiltersKeys = { CONST.SEARCH.SYNTAX_FILTER_KEYS.REIMBURSABLE, CONST.SEARCH.SYNTAX_FILTER_KEYS.BILLABLE, CONST.SEARCH.SYNTAX_FILTER_KEYS.ATTENDEE, - CONST.SEARCH.SYNTAX_FILTER_KEYS.ACTION, - CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_ID, - CONST.SEARCH.SYNTAX_FILTER_KEYS.SUBMITTED, - CONST.SEARCH.SYNTAX_FILTER_KEYS.APPROVED, - CONST.SEARCH.SYNTAX_FILTER_KEYS.PAID, - CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTED, - CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWAL_TYPE, - CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWAL_ID, - CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWN, ], - ], - [CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT]: [ [ - CONST.SEARCH.SYNTAX_FILTER_KEYS.TYPE, - CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM, - CONST.SEARCH.SYNTAX_FILTER_KEYS.TO, - CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD, - CONST.SEARCH.SYNTAX_FILTER_KEYS.STATUS, - CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID, - CONST.SEARCH.SYNTAX_FILTER_KEYS.GROUP_CURRENCY, - ], - [ - CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE, - CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY, CONST.SEARCH.SYNTAX_FILTER_KEYS.ACTION, CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_ID, CONST.SEARCH.SYNTAX_FILTER_KEYS.TOTAL, @@ -256,7 +234,7 @@ function useAdvancedSearchFilters() { const shouldDisplayCardFilter = shouldDisplayFilter(Object.keys(allCards).length, areCardsEnabled); const shouldDisplayTaxFilter = shouldDisplayFilter(Object.keys(taxRates).length, areTaxEnabled); const shouldDisplayWorkspaceFilter = workspaces.some((section) => section.data.length !== 0); - const shouldDisplayGroupByFilter = !!groupBy; + const shouldDisplayGroupByFilter = !!groupBy && groupBy !== CONST.SEARCH.GROUP_BY.REPORTS; const shouldDisplayGroupCurrencyFilter = shouldDisplayGroupByFilter; let currentType = searchAdvancedFilters?.type ?? CONST.SEARCH.DATA_TYPES.EXPENSE; diff --git a/src/languages/de.ts b/src/languages/de.ts index a5b410076fec..7cfce746d163 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -637,7 +637,6 @@ const translations = { downloadAsPDF: 'Als PDF herunterladen', downloadAsCSV: 'Als CSV herunterladen', help: 'Hilfe', - expenseReport: 'Spesenabrechnung', expenseReports: 'Spesenabrechnungen', rateOutOfPolicy: 'Satz außerhalb der Richtlinien', reimbursable: 'Erstattungsfähig', @@ -6262,6 +6261,7 @@ ${amount} für ${merchant} - ${date}`, reimbursable: 'Erstattungsfähig', purchaseCurrency: 'Kaufwährung', groupBy: { + [CONST.SEARCH.GROUP_BY.REPORTS]: 'Bericht', [CONST.SEARCH.GROUP_BY.FROM]: 'Von', [CONST.SEARCH.GROUP_BY.CARD]: 'Karte', [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'Auszahlungs-ID', diff --git a/src/languages/en.ts b/src/languages/en.ts index bb17536f13e5..ca6e421337b9 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -631,7 +631,6 @@ const translations = { downloadAsPDF: 'Download as PDF', downloadAsCSV: 'Download as CSV', help: 'Help', - expenseReport: 'Expense Report', expenseReports: 'Expense Reports', // @context Rate as a noun, not a verb rateOutOfPolicy: 'Rate out of policy', @@ -6216,6 +6215,7 @@ const translations = { reimbursable: 'Reimbursable', purchaseCurrency: 'Purchase currency', groupBy: { + [CONST.SEARCH.GROUP_BY.REPORTS]: 'Report', [CONST.SEARCH.GROUP_BY.FROM]: 'From', [CONST.SEARCH.GROUP_BY.CARD]: 'Card', [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'Withdrawal ID', diff --git a/src/languages/es.ts b/src/languages/es.ts index 7a1d3962acab..803c504e2c7e 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -618,7 +618,6 @@ const translations = { downloadAsPDF: 'Descargar como PDF', downloadAsCSV: 'Descargar como CSV', help: 'Ayuda', - expenseReport: 'Informe de Gastos', expenseReports: 'Informes de Gastos', rateOutOfPolicy: 'Tasa fuera de póliza', reimbursable: 'Reembolsable', @@ -6245,6 +6244,7 @@ ${amount} para ${merchant} - ${date}`, reimbursable: 'Reembolsable', purchaseCurrency: 'Moneda de compra', groupBy: { + [CONST.SEARCH.GROUP_BY.REPORTS]: 'Informe', [CONST.SEARCH.GROUP_BY.FROM]: 'De', [CONST.SEARCH.GROUP_BY.CARD]: 'Tarjeta', [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'ID de retiro', diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 1cecdc28f751..cc03cd22784a 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -637,7 +637,6 @@ const translations = { downloadAsPDF: 'Télécharger en PDF', downloadAsCSV: 'Télécharger en CSV', help: 'Aide', - expenseReport: 'Rapport de dépenses', expenseReports: 'Rapports de dépenses', rateOutOfPolicy: 'Taux hors politique', reimbursable: 'Remboursable', @@ -6269,6 +6268,7 @@ ${amount} pour ${merchant} - ${date}`, reimbursable: 'Remboursable', purchaseCurrency: "Devise d'achat", groupBy: { + [CONST.SEARCH.GROUP_BY.REPORTS]: 'Rapport', [CONST.SEARCH.GROUP_BY.FROM]: 'De', [CONST.SEARCH.GROUP_BY.CARD]: 'Carte', [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'ID de retrait', diff --git a/src/languages/it.ts b/src/languages/it.ts index ba6e2402fcd0..39f3dec00a59 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -637,7 +637,6 @@ const translations = { downloadAsPDF: 'Scarica come PDF', downloadAsCSV: 'Scarica come CSV', help: 'Aiuto', - expenseReport: 'Report di spesa', expenseReports: 'Report di spesa', rateOutOfPolicy: 'Tariffa fuori politica', reimbursable: 'Rimborsabile', @@ -6274,6 +6273,7 @@ ${amount} per ${merchant} - ${date}`, reimbursable: 'Rimborsabile', purchaseCurrency: 'Valuta di acquisto', groupBy: { + [CONST.SEARCH.GROUP_BY.REPORTS]: 'Rapporto', [CONST.SEARCH.GROUP_BY.FROM]: 'Da', [CONST.SEARCH.GROUP_BY.CARD]: 'Carta', [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'ID di prelievo', diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 7ac21cd0f917..d9c2f2e59007 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -637,7 +637,6 @@ const translations = { downloadAsPDF: 'PDFとしてダウンロード', downloadAsCSV: 'CSVとしてダウンロード', help: '助けて', - expenseReport: '経費報告書', expenseReports: '経費報告書', rateOutOfPolicy: 'ポリシー外のレート', reimbursable: '払い戻し可能', @@ -6209,6 +6208,7 @@ ${date} - ${merchant}に${amount}`, reimbursable: '払い戻し可能', purchaseCurrency: '購入通貨', groupBy: { + [CONST.SEARCH.GROUP_BY.REPORTS]: '報告', [CONST.SEARCH.GROUP_BY.FROM]: 'から', [CONST.SEARCH.GROUP_BY.CARD]: 'カード', [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: '出金ID', diff --git a/src/languages/nl.ts b/src/languages/nl.ts index fbe5768cea01..b63cf25cc23b 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -636,7 +636,6 @@ const translations = { downloadAsPDF: 'Downloaden als PDF', downloadAsCSV: 'Downloaden als CSV', help: 'Help', - expenseReport: 'Onkostennota', expenseReports: "Onkostennota's", rateOutOfPolicy: 'Tarief buiten beleid', reimbursable: 'Vergoedbaar', @@ -6258,6 +6257,7 @@ ${amount} voor ${merchant} - ${date}`, reimbursable: 'Vergoedbaar', purchaseCurrency: 'Aankoopvaluta', groupBy: { + [CONST.SEARCH.GROUP_BY.REPORTS]: 'Verslag', [CONST.SEARCH.GROUP_BY.FROM]: 'Van', [CONST.SEARCH.GROUP_BY.CARD]: 'Kaart', [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'Opname-ID', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index 7be518d81c30..113656f4dfab 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -637,7 +637,6 @@ const translations = { downloadAsPDF: 'Pobierz jako PDF', downloadAsCSV: 'Pobierz jako CSV', help: 'Pomoc', - expenseReport: 'Raport wydatków', expenseReports: 'Raporty wydatków', rateOutOfPolicy: 'Stawka poza polityką', reimbursable: 'Podlegające zwrotowi', @@ -6244,6 +6243,7 @@ ${amount} dla ${merchant} - ${date}`, reimbursable: 'Podlegające zwrotowi', purchaseCurrency: 'Waluta zakupu', groupBy: { + [CONST.SEARCH.GROUP_BY.REPORTS]: 'Raport', [CONST.SEARCH.GROUP_BY.FROM]: 'Od', [CONST.SEARCH.GROUP_BY.CARD]: 'Karta', [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'Identyfikator wypłaty', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index 32d38f7600b5..d9ee8f9619ec 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -637,7 +637,6 @@ const translations = { downloadAsPDF: 'Baixar como PDF', downloadAsCSV: 'Baixar como CSV', help: 'Ajuda', - expenseReport: 'Relatório de Despesas', expenseReports: 'Relatórios de Despesas', rateOutOfPolicy: 'Taxa fora da política', reimbursable: 'Reembolsável', @@ -6253,6 +6252,7 @@ ${amount} para ${merchant} - ${date}`, reimbursable: 'Reembolsável', purchaseCurrency: 'Moeda da compra', groupBy: { + [CONST.SEARCH.GROUP_BY.REPORTS]: 'Relatório', [CONST.SEARCH.GROUP_BY.FROM]: 'De', [CONST.SEARCH.GROUP_BY.CARD]: 'Cartão', [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'ID de retirada', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 2df5e8ba6f4e..e402932947e1 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -636,7 +636,6 @@ const translations = { downloadAsPDF: '下载为PDF', downloadAsCSV: '下载为CSV', help: '帮助', - expenseReport: '费用报告', expenseReports: '费用报告', rateOutOfPolicy: '超出政策的费率', reimbursable: '可报销的', @@ -6131,6 +6130,7 @@ ${merchant}的${amount} - ${date}`, reimbursable: '可报销的', purchaseCurrency: '购买货币', groupBy: { + [CONST.SEARCH.GROUP_BY.REPORTS]: '报告', [CONST.SEARCH.GROUP_BY.FROM]: '从', [CONST.SEARCH.GROUP_BY.CARD]: '卡片', [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: '提现ID', diff --git a/src/libs/SearchParser/autocompleteParser.js b/src/libs/SearchParser/autocompleteParser.js index bc22450b3ad4..e289a136c89e 100644 --- a/src/libs/SearchParser/autocompleteParser.js +++ b/src/libs/SearchParser/autocompleteParser.js @@ -246,16 +246,18 @@ function peg$parse(input, options) { var peg$c60 = "purchase-currency"; var peg$c61 = "perdiem"; var peg$c62 = "per-diem"; - var peg$c63 = "drafts"; - var peg$c64 = "draft"; - var peg$c65 = "!="; - var peg$c66 = ">="; - var peg$c67 = ">"; - var peg$c68 = "<="; - var peg$c69 = "<"; - var peg$c70 = "\u201C"; - var peg$c71 = "\u201D"; - var peg$c72 = "\""; + var peg$c63 = "reports"; + var peg$c64 = "report"; + var peg$c65 = "drafts"; + var peg$c66 = "draft"; + var peg$c67 = "!="; + var peg$c68 = ">="; + var peg$c69 = ">"; + var peg$c70 = "<="; + var peg$c71 = "<"; + var peg$c72 = "\u201C"; + var peg$c73 = "\u201D"; + var peg$c74 = "\""; var peg$r0 = /^[:=]/; var peg$r1 = /^[^ ,\t\n\r\xA0]/; @@ -333,32 +335,34 @@ function peg$parse(input, options) { var peg$e61 = peg$literalExpectation("purchase-currency", true); var peg$e62 = peg$literalExpectation("perDiem", true); var peg$e63 = peg$literalExpectation("per-diem", true); - var peg$e64 = peg$literalExpectation("drafts", true); - var peg$e65 = peg$literalExpectation("draft", true); - var peg$e66 = peg$otherExpectation("operator"); - var peg$e67 = peg$classExpectation([":", "="], false, false); - var peg$e68 = peg$literalExpectation("!=", false); - var peg$e69 = peg$literalExpectation(">=", false); - var peg$e70 = peg$literalExpectation(">", false); - var peg$e71 = peg$literalExpectation("<=", false); - var peg$e72 = peg$literalExpectation("<", false); - var peg$e73 = peg$otherExpectation("word"); - var peg$e74 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false); - var peg$e75 = peg$otherExpectation("whitespace"); - var peg$e76 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false); - var peg$e77 = peg$otherExpectation("quote"); - var peg$e78 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false); - var peg$e79 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false); - var peg$e80 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false); - var peg$e81 = peg$literalExpectation("\u201C", false); - var peg$e82 = peg$literalExpectation("\u201D", false); - var peg$e83 = peg$literalExpectation("\"", false); - var peg$e84 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"], ["0", "9"]], false, false); - var peg$e85 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false); - var peg$e86 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0"], false, false); - var peg$e87 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"]], false, false); - var peg$e88 = peg$anyExpectation(); - var peg$e89 = peg$classExpectation([","], false, false); + var peg$e64 = peg$literalExpectation("reports", true); + var peg$e65 = peg$literalExpectation("report", true); + var peg$e66 = peg$literalExpectation("drafts", true); + var peg$e67 = peg$literalExpectation("draft", true); + var peg$e68 = peg$otherExpectation("operator"); + var peg$e69 = peg$classExpectation([":", "="], false, false); + var peg$e70 = peg$literalExpectation("!=", false); + var peg$e71 = peg$literalExpectation(">=", false); + var peg$e72 = peg$literalExpectation(">", false); + var peg$e73 = peg$literalExpectation("<=", false); + var peg$e74 = peg$literalExpectation("<", false); + var peg$e75 = peg$otherExpectation("word"); + var peg$e76 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false); + var peg$e77 = peg$otherExpectation("whitespace"); + var peg$e78 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false); + var peg$e79 = peg$otherExpectation("quote"); + var peg$e80 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false); + var peg$e81 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false); + var peg$e82 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false); + var peg$e83 = peg$literalExpectation("\u201C", false); + var peg$e84 = peg$literalExpectation("\u201D", false); + var peg$e85 = peg$literalExpectation("\"", false); + var peg$e86 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"], ["0", "9"]], false, false); + var peg$e87 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false); + var peg$e88 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0"], false, false); + var peg$e89 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"]], false, false); + var peg$e90 = peg$anyExpectation(); + var peg$e91 = peg$classExpectation([","], false, false); var peg$f0 = function(ranges) { return { autocomplete, ranges }; }; var peg$f1 = function(filters) { return filters.filter(Boolean).flat(); }; @@ -464,29 +468,30 @@ function peg$parse(input, options) { var peg$f49 = function() {return "purchaseAmount"}; var peg$f50 = function() {return "purchaseCurrency"}; var peg$f51 = function() { return "perDiem"; }; - var peg$f52 = function() {return "drafts"; }; - var peg$f53 = function() { return "eq"; }; - var peg$f54 = function() { return "neq"; }; - var peg$f55 = function() { return "gte"; }; - var peg$f56 = function() { return "gt"; }; - var peg$f57 = function() { return "lte"; }; - var peg$f58 = function() { return "lt"; }; - var peg$f59 = function(o) { + var peg$f52 = function() {return "reports"; }; + var peg$f53 = function() {return "drafts"; }; + var peg$f54 = function() { return "eq"; }; + var peg$f55 = function() { return "neq"; }; + var peg$f56 = function() { return "gte"; }; + var peg$f57 = function() { return "gt"; }; + var peg$f58 = function() { return "lte"; }; + var peg$f59 = function() { return "lt"; }; + var peg$f60 = function(o) { if (nameOperator) { expectingNestedQuote = (o === "eq"); // Use simple parser if no valid operator is found } return o; }; - var peg$f60 = function(chars) { return chars.join("").trim(); }; - var peg$f61 = function() { return "and"; }; - var peg$f62 = function() { return expectingNestedQuote; }; - var peg$f63 = function(start, inner, end) { //handle no-breaking space + var peg$f61 = function(chars) { return chars.join("").trim(); }; + var peg$f62 = function() { return "and"; }; + var peg$f63 = function() { return expectingNestedQuote; }; + var peg$f64 = function(start, inner, end) { //handle no-breaking space return [...start, '"', ...inner, '"', ...end].join(""); }; - var peg$f64 = function(start) {return "“"}; - var peg$f65 = function(start) {return "”"}; - var peg$f66 = function(start) {return "\""}; - var peg$f67 = function(start, inner, end) { + var peg$f65 = function(start) {return "“"}; + var peg$f66 = function(start) {return "”"}; + var peg$f67 = function(start) {return "\""}; + var peg$f68 = function(start, inner, end) { return [...start, '"', ...inner, '"'].join(""); }; var peg$currPos = options.peg$currPos | 0; @@ -2024,7 +2029,10 @@ function peg$parse(input, options) { s0 = peg$parseperDiem(); if (s0 === peg$FAILED) { - s0 = peg$parsedraft(); + s0 = peg$parsereport(); + if (s0 === peg$FAILED) { + s0 = peg$parsedraft(); + } } return s0; @@ -2059,21 +2067,21 @@ function peg$parse(input, options) { return s0; } - function peg$parsedraft() { + function peg$parsereport() { var s0, s1; - s0 = input.substr(peg$currPos, 6); + s0 = input.substr(peg$currPos, 7); if (s0.toLowerCase() === peg$c63) { - peg$currPos += 6; + peg$currPos += 7; } else { s0 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e64); } } if (s0 === peg$FAILED) { s0 = peg$currPos; - s1 = input.substr(peg$currPos, 5); + s1 = input.substr(peg$currPos, 6); if (s1.toLowerCase() === peg$c64) { - peg$currPos += 5; + peg$currPos += 6; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e65); } @@ -2088,6 +2096,35 @@ function peg$parse(input, options) { return s0; } + function peg$parsedraft() { + var s0, s1; + + s0 = input.substr(peg$currPos, 6); + if (s0.toLowerCase() === peg$c65) { + peg$currPos += 6; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e66); } + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = input.substr(peg$currPos, 5); + if (s1.toLowerCase() === peg$c66) { + peg$currPos += 5; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e67); } + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f53(); + } + s0 = s1; + } + + return s0; + } + function peg$parseoperator() { var s0, s1; @@ -2098,81 +2135,81 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e67); } + if (peg$silentFails === 0) { peg$fail(peg$e69); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f53(); + s1 = peg$f54(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c65) { - s1 = peg$c65; + if (input.substr(peg$currPos, 2) === peg$c67) { + s1 = peg$c67; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e68); } + if (peg$silentFails === 0) { peg$fail(peg$e70); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f54(); + s1 = peg$f55(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c66) { - s1 = peg$c66; + if (input.substr(peg$currPos, 2) === peg$c68) { + s1 = peg$c68; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e69); } + if (peg$silentFails === 0) { peg$fail(peg$e71); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f55(); + s1 = peg$f56(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 62) { - s1 = peg$c67; + s1 = peg$c69; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e70); } + if (peg$silentFails === 0) { peg$fail(peg$e72); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f56(); + s1 = peg$f57(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c68) { - s1 = peg$c68; + if (input.substr(peg$currPos, 2) === peg$c70) { + s1 = peg$c70; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e71); } + if (peg$silentFails === 0) { peg$fail(peg$e73); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f57(); + s1 = peg$f58(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 60) { - s1 = peg$c69; + s1 = peg$c71; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e72); } + if (peg$silentFails === 0) { peg$fail(peg$e74); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f58(); + s1 = peg$f59(); } s0 = s1; } @@ -2183,7 +2220,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e66); } + if (peg$silentFails === 0) { peg$fail(peg$e68); } } return s0; @@ -2196,7 +2233,7 @@ function peg$parse(input, options) { s1 = peg$parseoperator(); if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f59(s1); + s1 = peg$f60(s1); } s0 = s1; @@ -2214,7 +2251,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e74); } + if (peg$silentFails === 0) { peg$fail(peg$e76); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { @@ -2224,7 +2261,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e74); } + if (peg$silentFails === 0) { peg$fail(peg$e76); } } } } else { @@ -2232,13 +2269,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f60(s1); + s1 = peg$f61(s1); } s0 = s1; peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e73); } + if (peg$silentFails === 0) { peg$fail(peg$e75); } } return s0; @@ -2250,7 +2287,7 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = peg$parse_(); peg$savedPos = s0; - s1 = peg$f61(); + s1 = peg$f62(); s0 = s1; return s0; @@ -2266,7 +2303,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e76); } + if (peg$silentFails === 0) { peg$fail(peg$e78); } } while (s1 !== peg$FAILED) { s0.push(s1); @@ -2275,12 +2312,12 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e76); } + if (peg$silentFails === 0) { peg$fail(peg$e78); } } } peg$silentFails--; s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e75); } + if (peg$silentFails === 0) { peg$fail(peg$e77); } return s0; } @@ -2290,7 +2327,7 @@ function peg$parse(input, options) { s0 = peg$currPos; peg$savedPos = peg$currPos; - s1 = peg$f62(); + s1 = peg$f63(); if (s1) { s1 = undefined; } else { @@ -2327,7 +2364,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e78); } + if (peg$silentFails === 0) { peg$fail(peg$e80); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2336,7 +2373,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e78); } + if (peg$silentFails === 0) { peg$fail(peg$e80); } } } s2 = input.charAt(peg$currPos); @@ -2344,7 +2381,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e79); } + if (peg$silentFails === 0) { peg$fail(peg$e81); } } if (s2 !== peg$FAILED) { s3 = []; @@ -2353,7 +2390,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e80); } + if (peg$silentFails === 0) { peg$fail(peg$e82); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -2362,7 +2399,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e80); } + if (peg$silentFails === 0) { peg$fail(peg$e82); } } } s4 = input.charAt(peg$currPos); @@ -2370,7 +2407,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e79); } + if (peg$silentFails === 0) { peg$fail(peg$e81); } } if (s4 !== peg$FAILED) { s5 = []; @@ -2379,7 +2416,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e74); } + if (peg$silentFails === 0) { peg$fail(peg$e76); } } while (s6 !== peg$FAILED) { s5.push(s6); @@ -2388,11 +2425,11 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e74); } + if (peg$silentFails === 0) { peg$fail(peg$e76); } } } peg$savedPos = s0; - s0 = peg$f63(s1, s3, s5); + s0 = peg$f64(s1, s3, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2404,7 +2441,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e77); } + if (peg$silentFails === 0) { peg$fail(peg$e79); } } return s0; @@ -2421,7 +2458,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e78); } + if (peg$silentFails === 0) { peg$fail(peg$e80); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2430,7 +2467,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e78); } + if (peg$silentFails === 0) { peg$fail(peg$e80); } } } s2 = input.charAt(peg$currPos); @@ -2438,7 +2475,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e79); } + if (peg$silentFails === 0) { peg$fail(peg$e81); } } if (s2 !== peg$FAILED) { s3 = []; @@ -2447,7 +2484,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e80); } + if (peg$silentFails === 0) { peg$fail(peg$e82); } } if (s4 === peg$FAILED) { s4 = peg$currPos; @@ -2463,15 +2500,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8220) { - s6 = peg$c70; + s6 = peg$c72; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e81); } + if (peg$silentFails === 0) { peg$fail(peg$e83); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f64(s1); + s4 = peg$f65(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2494,15 +2531,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8221) { - s6 = peg$c71; + s6 = peg$c73; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e82); } + if (peg$silentFails === 0) { peg$fail(peg$e84); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f65(s1); + s4 = peg$f66(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2525,15 +2562,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s6 = peg$c72; + s6 = peg$c74; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e83); } + if (peg$silentFails === 0) { peg$fail(peg$e85); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f66(s1); + s4 = peg$f67(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2552,7 +2589,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e80); } + if (peg$silentFails === 0) { peg$fail(peg$e82); } } if (s4 === peg$FAILED) { s4 = peg$currPos; @@ -2568,15 +2605,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8220) { - s6 = peg$c70; + s6 = peg$c72; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e81); } + if (peg$silentFails === 0) { peg$fail(peg$e83); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f64(s1); + s4 = peg$f65(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2599,15 +2636,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8221) { - s6 = peg$c71; + s6 = peg$c73; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e82); } + if (peg$silentFails === 0) { peg$fail(peg$e84); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f65(s1); + s4 = peg$f66(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2630,15 +2667,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s6 = peg$c72; + s6 = peg$c74; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e83); } + if (peg$silentFails === 0) { peg$fail(peg$e85); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f66(s1); + s4 = peg$f67(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2654,7 +2691,7 @@ function peg$parse(input, options) { s4 = peg$parseclosingQuote(); if (s4 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f67(s1, s3, s4); + s0 = peg$f68(s1, s3, s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2666,7 +2703,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e77); } + if (peg$silentFails === 0) { peg$fail(peg$e79); } } return s0; @@ -2681,7 +2718,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e79); } + if (peg$silentFails === 0) { peg$fail(peg$e81); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2719,7 +2756,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e84); } + if (peg$silentFails === 0) { peg$fail(peg$e86); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2728,7 +2765,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e84); } + if (peg$silentFails === 0) { peg$fail(peg$e86); } } } s2 = []; @@ -2737,7 +2774,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e85); } + if (peg$silentFails === 0) { peg$fail(peg$e87); } } while (s3 !== peg$FAILED) { s2.push(s3); @@ -2746,7 +2783,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e85); } + if (peg$silentFails === 0) { peg$fail(peg$e87); } } } s3 = []; @@ -2755,7 +2792,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e86); } + if (peg$silentFails === 0) { peg$fail(peg$e88); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -2764,7 +2801,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e86); } + if (peg$silentFails === 0) { peg$fail(peg$e88); } } } s4 = peg$parseoperator(); @@ -2783,7 +2820,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e87); } + if (peg$silentFails === 0) { peg$fail(peg$e89); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2792,7 +2829,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e87); } + if (peg$silentFails === 0) { peg$fail(peg$e89); } } } s2 = peg$currPos; @@ -2813,7 +2850,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e88); } + if (peg$silentFails === 0) { peg$fail(peg$e90); } } peg$silentFails--; if (s4 === peg$FAILED) { @@ -2839,7 +2876,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e89); } + if (peg$silentFails === 0) { peg$fail(peg$e91); } } } } diff --git a/src/libs/SearchParser/baseRules.peggy b/src/libs/SearchParser/baseRules.peggy index 60fbc69ec304..1569ad0bce6b 100644 --- a/src/libs/SearchParser/baseRules.peggy +++ b/src/libs/SearchParser/baseRules.peggy @@ -82,9 +82,11 @@ purchaseCurrency = "purchaseCurrency"i / "purchase-currency"i {return "purchaseC // Value transformation rules values = perDiem + / report / draft perDiem = "perDiem"i / "per-diem"i { return "perDiem"; } +report = "reports"i / "report"i {return "reports"; } draft = "drafts"i / "draft"i {return "drafts"; } operator "operator" diff --git a/src/libs/SearchParser/searchParser.js b/src/libs/SearchParser/searchParser.js index ed6c7cd60ba6..3203356e4330 100644 --- a/src/libs/SearchParser/searchParser.js +++ b/src/libs/SearchParser/searchParser.js @@ -247,16 +247,18 @@ function peg$parse(input, options) { var peg$c60 = "purchase-currency"; var peg$c61 = "perdiem"; var peg$c62 = "per-diem"; - var peg$c63 = "drafts"; - var peg$c64 = "draft"; - var peg$c65 = "!="; - var peg$c66 = ">="; - var peg$c67 = ">"; - var peg$c68 = "<="; - var peg$c69 = "<"; - var peg$c70 = "\u201C"; - var peg$c71 = "\u201D"; - var peg$c72 = "\""; + var peg$c63 = "reports"; + var peg$c64 = "report"; + var peg$c65 = "drafts"; + var peg$c66 = "draft"; + var peg$c67 = "!="; + var peg$c68 = ">="; + var peg$c69 = ">"; + var peg$c70 = "<="; + var peg$c71 = "<"; + var peg$c72 = "\u201C"; + var peg$c73 = "\u201D"; + var peg$c74 = "\""; var peg$r0 = /^[^ \t\r\n\xA0]/; var peg$r1 = /^[:=]/; @@ -337,32 +339,34 @@ function peg$parse(input, options) { var peg$e63 = peg$literalExpectation("purchase-currency", true); var peg$e64 = peg$literalExpectation("perDiem", true); var peg$e65 = peg$literalExpectation("per-diem", true); - var peg$e66 = peg$literalExpectation("drafts", true); - var peg$e67 = peg$literalExpectation("draft", true); - var peg$e68 = peg$otherExpectation("operator"); - var peg$e69 = peg$classExpectation([":", "="], false, false); - var peg$e70 = peg$literalExpectation("!=", false); - var peg$e71 = peg$literalExpectation(">=", false); - var peg$e72 = peg$literalExpectation(">", false); - var peg$e73 = peg$literalExpectation("<=", false); - var peg$e74 = peg$literalExpectation("<", false); - var peg$e75 = peg$otherExpectation("word"); - var peg$e76 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false); - var peg$e77 = peg$otherExpectation("whitespace"); - var peg$e78 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false); - var peg$e79 = peg$otherExpectation("quote"); - var peg$e80 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false); - var peg$e81 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false); - var peg$e82 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false); - var peg$e83 = peg$literalExpectation("\u201C", false); - var peg$e84 = peg$literalExpectation("\u201D", false); - var peg$e85 = peg$literalExpectation("\"", false); - var peg$e86 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"], ["0", "9"]], false, false); - var peg$e87 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false); - var peg$e88 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0"], false, false); - var peg$e89 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"]], false, false); - var peg$e90 = peg$anyExpectation(); - var peg$e91 = peg$classExpectation([","], false, false); + var peg$e66 = peg$literalExpectation("reports", true); + var peg$e67 = peg$literalExpectation("report", true); + var peg$e68 = peg$literalExpectation("drafts", true); + var peg$e69 = peg$literalExpectation("draft", true); + var peg$e70 = peg$otherExpectation("operator"); + var peg$e71 = peg$classExpectation([":", "="], false, false); + var peg$e72 = peg$literalExpectation("!=", false); + var peg$e73 = peg$literalExpectation(">=", false); + var peg$e74 = peg$literalExpectation(">", false); + var peg$e75 = peg$literalExpectation("<=", false); + var peg$e76 = peg$literalExpectation("<", false); + var peg$e77 = peg$otherExpectation("word"); + var peg$e78 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false); + var peg$e79 = peg$otherExpectation("whitespace"); + var peg$e80 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false); + var peg$e81 = peg$otherExpectation("quote"); + var peg$e82 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false); + var peg$e83 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false); + var peg$e84 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false); + var peg$e85 = peg$literalExpectation("\u201C", false); + var peg$e86 = peg$literalExpectation("\u201D", false); + var peg$e87 = peg$literalExpectation("\"", false); + var peg$e88 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"], ["0", "9"]], false, false); + var peg$e89 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false); + var peg$e90 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0"], false, false); + var peg$e91 = peg$classExpectation([" ", "\t", "\n", "\r", "\xA0", ["a", "z"], ["A", "Z"]], false, false); + var peg$e92 = peg$anyExpectation(); + var peg$e93 = peg$classExpectation([","], false, false); var peg$f0 = function(filters) { return applyDefaults(filters); }; var peg$f1 = function(head, tail) { @@ -486,29 +490,30 @@ function peg$parse(input, options) { var peg$f50 = function() {return "purchaseAmount"}; var peg$f51 = function() {return "purchaseCurrency"}; var peg$f52 = function() { return "perDiem"; }; - var peg$f53 = function() {return "drafts"; }; - var peg$f54 = function() { return "eq"; }; - var peg$f55 = function() { return "neq"; }; - var peg$f56 = function() { return "gte"; }; - var peg$f57 = function() { return "gt"; }; - var peg$f58 = function() { return "lte"; }; - var peg$f59 = function() { return "lt"; }; - var peg$f60 = function(o) { + var peg$f53 = function() {return "reports"; }; + var peg$f54 = function() {return "drafts"; }; + var peg$f55 = function() { return "eq"; }; + var peg$f56 = function() { return "neq"; }; + var peg$f57 = function() { return "gte"; }; + var peg$f58 = function() { return "gt"; }; + var peg$f59 = function() { return "lte"; }; + var peg$f60 = function() { return "lt"; }; + var peg$f61 = function(o) { if (nameOperator) { expectingNestedQuote = (o === "eq"); // Use simple parser if no valid operator is found } return o; }; - var peg$f61 = function(chars) { return chars.join("").trim(); }; - var peg$f62 = function() { return "and"; }; - var peg$f63 = function() { return expectingNestedQuote; }; - var peg$f64 = function(start, inner, end) { //handle no-breaking space + var peg$f62 = function(chars) { return chars.join("").trim(); }; + var peg$f63 = function() { return "and"; }; + var peg$f64 = function() { return expectingNestedQuote; }; + var peg$f65 = function(start, inner, end) { //handle no-breaking space return [...start, '"', ...inner, '"', ...end].join(""); }; - var peg$f65 = function(start) {return "“"}; - var peg$f66 = function(start) {return "”"}; - var peg$f67 = function(start) {return "\""}; - var peg$f68 = function(start, inner, end) { + var peg$f66 = function(start) {return "“"}; + var peg$f67 = function(start) {return "”"}; + var peg$f68 = function(start) {return "\""}; + var peg$f69 = function(start, inner, end) { return [...start, '"', ...inner, '"'].join(""); }; var peg$currPos = options.peg$currPos | 0; @@ -2203,7 +2208,10 @@ function peg$parse(input, options) { s0 = peg$parseperDiem(); if (s0 === peg$FAILED) { - s0 = peg$parsedraft(); + s0 = peg$parsereport(); + if (s0 === peg$FAILED) { + s0 = peg$parsedraft(); + } } return s0; @@ -2238,21 +2246,21 @@ function peg$parse(input, options) { return s0; } - function peg$parsedraft() { + function peg$parsereport() { var s0, s1; - s0 = input.substr(peg$currPos, 6); + s0 = input.substr(peg$currPos, 7); if (s0.toLowerCase() === peg$c63) { - peg$currPos += 6; + peg$currPos += 7; } else { s0 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e66); } } if (s0 === peg$FAILED) { s0 = peg$currPos; - s1 = input.substr(peg$currPos, 5); + s1 = input.substr(peg$currPos, 6); if (s1.toLowerCase() === peg$c64) { - peg$currPos += 5; + peg$currPos += 6; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e67); } @@ -2267,6 +2275,35 @@ function peg$parse(input, options) { return s0; } + function peg$parsedraft() { + var s0, s1; + + s0 = input.substr(peg$currPos, 6); + if (s0.toLowerCase() === peg$c65) { + peg$currPos += 6; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e68); } + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = input.substr(peg$currPos, 5); + if (s1.toLowerCase() === peg$c66) { + peg$currPos += 5; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e69); } + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f54(); + } + s0 = s1; + } + + return s0; + } + function peg$parseoperator() { var s0, s1; @@ -2277,81 +2314,81 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e69); } + if (peg$silentFails === 0) { peg$fail(peg$e71); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f54(); + s1 = peg$f55(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c65) { - s1 = peg$c65; + if (input.substr(peg$currPos, 2) === peg$c67) { + s1 = peg$c67; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e70); } + if (peg$silentFails === 0) { peg$fail(peg$e72); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f55(); + s1 = peg$f56(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c66) { - s1 = peg$c66; + if (input.substr(peg$currPos, 2) === peg$c68) { + s1 = peg$c68; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e71); } + if (peg$silentFails === 0) { peg$fail(peg$e73); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f56(); + s1 = peg$f57(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 62) { - s1 = peg$c67; + s1 = peg$c69; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e72); } + if (peg$silentFails === 0) { peg$fail(peg$e74); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f57(); + s1 = peg$f58(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c68) { - s1 = peg$c68; + if (input.substr(peg$currPos, 2) === peg$c70) { + s1 = peg$c70; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e73); } + if (peg$silentFails === 0) { peg$fail(peg$e75); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f58(); + s1 = peg$f59(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 60) { - s1 = peg$c69; + s1 = peg$c71; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e74); } + if (peg$silentFails === 0) { peg$fail(peg$e76); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f59(); + s1 = peg$f60(); } s0 = s1; } @@ -2362,7 +2399,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e68); } + if (peg$silentFails === 0) { peg$fail(peg$e70); } } return s0; @@ -2375,7 +2412,7 @@ function peg$parse(input, options) { s1 = peg$parseoperator(); if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f60(s1); + s1 = peg$f61(s1); } s0 = s1; @@ -2393,7 +2430,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e76); } + if (peg$silentFails === 0) { peg$fail(peg$e78); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { @@ -2403,7 +2440,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e76); } + if (peg$silentFails === 0) { peg$fail(peg$e78); } } } } else { @@ -2411,13 +2448,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f61(s1); + s1 = peg$f62(s1); } s0 = s1; peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e75); } + if (peg$silentFails === 0) { peg$fail(peg$e77); } } return s0; @@ -2429,7 +2466,7 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = peg$parse_(); peg$savedPos = s0; - s1 = peg$f62(); + s1 = peg$f63(); s0 = s1; return s0; @@ -2445,7 +2482,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e78); } + if (peg$silentFails === 0) { peg$fail(peg$e80); } } while (s1 !== peg$FAILED) { s0.push(s1); @@ -2454,12 +2491,12 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e78); } + if (peg$silentFails === 0) { peg$fail(peg$e80); } } } peg$silentFails--; s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e77); } + if (peg$silentFails === 0) { peg$fail(peg$e79); } return s0; } @@ -2469,7 +2506,7 @@ function peg$parse(input, options) { s0 = peg$currPos; peg$savedPos = peg$currPos; - s1 = peg$f63(); + s1 = peg$f64(); if (s1) { s1 = undefined; } else { @@ -2506,7 +2543,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e80); } + if (peg$silentFails === 0) { peg$fail(peg$e82); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2515,7 +2552,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e80); } + if (peg$silentFails === 0) { peg$fail(peg$e82); } } } s2 = input.charAt(peg$currPos); @@ -2523,7 +2560,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e81); } + if (peg$silentFails === 0) { peg$fail(peg$e83); } } if (s2 !== peg$FAILED) { s3 = []; @@ -2532,7 +2569,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e82); } + if (peg$silentFails === 0) { peg$fail(peg$e84); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -2541,7 +2578,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e82); } + if (peg$silentFails === 0) { peg$fail(peg$e84); } } } s4 = input.charAt(peg$currPos); @@ -2549,7 +2586,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e81); } + if (peg$silentFails === 0) { peg$fail(peg$e83); } } if (s4 !== peg$FAILED) { s5 = []; @@ -2558,7 +2595,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e76); } + if (peg$silentFails === 0) { peg$fail(peg$e78); } } while (s6 !== peg$FAILED) { s5.push(s6); @@ -2567,11 +2604,11 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e76); } + if (peg$silentFails === 0) { peg$fail(peg$e78); } } } peg$savedPos = s0; - s0 = peg$f64(s1, s3, s5); + s0 = peg$f65(s1, s3, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2583,7 +2620,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e79); } + if (peg$silentFails === 0) { peg$fail(peg$e81); } } return s0; @@ -2600,7 +2637,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e80); } + if (peg$silentFails === 0) { peg$fail(peg$e82); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2609,7 +2646,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e80); } + if (peg$silentFails === 0) { peg$fail(peg$e82); } } } s2 = input.charAt(peg$currPos); @@ -2617,7 +2654,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e81); } + if (peg$silentFails === 0) { peg$fail(peg$e83); } } if (s2 !== peg$FAILED) { s3 = []; @@ -2626,7 +2663,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e82); } + if (peg$silentFails === 0) { peg$fail(peg$e84); } } if (s4 === peg$FAILED) { s4 = peg$currPos; @@ -2642,15 +2679,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8220) { - s6 = peg$c70; + s6 = peg$c72; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e83); } + if (peg$silentFails === 0) { peg$fail(peg$e85); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f65(s1); + s4 = peg$f66(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2673,15 +2710,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8221) { - s6 = peg$c71; + s6 = peg$c73; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e84); } + if (peg$silentFails === 0) { peg$fail(peg$e86); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f66(s1); + s4 = peg$f67(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2704,15 +2741,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s6 = peg$c72; + s6 = peg$c74; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e85); } + if (peg$silentFails === 0) { peg$fail(peg$e87); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f67(s1); + s4 = peg$f68(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2731,7 +2768,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e82); } + if (peg$silentFails === 0) { peg$fail(peg$e84); } } if (s4 === peg$FAILED) { s4 = peg$currPos; @@ -2747,15 +2784,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8220) { - s6 = peg$c70; + s6 = peg$c72; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e83); } + if (peg$silentFails === 0) { peg$fail(peg$e85); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f65(s1); + s4 = peg$f66(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2778,15 +2815,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 8221) { - s6 = peg$c71; + s6 = peg$c73; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e84); } + if (peg$silentFails === 0) { peg$fail(peg$e86); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f66(s1); + s4 = peg$f67(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2809,15 +2846,15 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s6 = peg$c72; + s6 = peg$c74; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e85); } + if (peg$silentFails === 0) { peg$fail(peg$e87); } } if (s6 !== peg$FAILED) { peg$savedPos = s4; - s4 = peg$f67(s1); + s4 = peg$f68(s1); } else { peg$currPos = s4; s4 = peg$FAILED; @@ -2833,7 +2870,7 @@ function peg$parse(input, options) { s4 = peg$parseclosingQuote(); if (s4 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f68(s1, s3, s4); + s0 = peg$f69(s1, s3, s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2845,7 +2882,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e79); } + if (peg$silentFails === 0) { peg$fail(peg$e81); } } return s0; @@ -2860,7 +2897,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e81); } + if (peg$silentFails === 0) { peg$fail(peg$e83); } } if (s1 !== peg$FAILED) { s2 = peg$currPos; @@ -2898,7 +2935,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e86); } + if (peg$silentFails === 0) { peg$fail(peg$e88); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2907,7 +2944,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e86); } + if (peg$silentFails === 0) { peg$fail(peg$e88); } } } s2 = []; @@ -2916,7 +2953,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e87); } + if (peg$silentFails === 0) { peg$fail(peg$e89); } } while (s3 !== peg$FAILED) { s2.push(s3); @@ -2925,7 +2962,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e87); } + if (peg$silentFails === 0) { peg$fail(peg$e89); } } } s3 = []; @@ -2934,7 +2971,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e88); } + if (peg$silentFails === 0) { peg$fail(peg$e90); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -2943,7 +2980,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e88); } + if (peg$silentFails === 0) { peg$fail(peg$e90); } } } s4 = peg$parseoperator(); @@ -2962,7 +2999,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e89); } + if (peg$silentFails === 0) { peg$fail(peg$e91); } } while (s2 !== peg$FAILED) { s1.push(s2); @@ -2971,7 +3008,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e89); } + if (peg$silentFails === 0) { peg$fail(peg$e91); } } } s2 = peg$currPos; @@ -2992,7 +3029,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e90); } + if (peg$silentFails === 0) { peg$fail(peg$e92); } } peg$silentFails--; if (s4 === peg$FAILED) { @@ -3018,7 +3055,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e91); } + if (peg$silentFails === 0) { peg$fail(peg$e93); } } } } diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index caf76bbc50e7..8da246818dc9 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -306,9 +306,9 @@ function getSuggestedSearches(accountID: number = CONST.DEFAULT_NUMBER_ID, defau [CONST.SEARCH.SEARCH_KEYS.REPORTS]: { key: CONST.SEARCH.SEARCH_KEYS.REPORTS, translationPath: 'common.reports', - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, icon: Expensicons.Document, - searchQuery: buildCannedSearchQuery({type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT}), + searchQuery: buildCannedSearchQuery({groupBy: CONST.SEARCH.GROUP_BY.REPORTS}), get searchQueryJSON() { return buildSearchQueryJSON(this.searchQuery); }, @@ -338,10 +338,11 @@ function getSuggestedSearches(accountID: number = CONST.DEFAULT_NUMBER_ID, defau [CONST.SEARCH.SEARCH_KEYS.SUBMIT]: { key: CONST.SEARCH.SEARCH_KEYS.SUBMIT, translationPath: 'common.submit', - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, icon: Expensicons.Pencil, searchQuery: buildQueryStringFromFilterFormValues({ - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, + groupBy: CONST.SEARCH.GROUP_BY.REPORTS, action: CONST.SEARCH.ACTION_FILTERS.SUBMIT, from: [`${accountID}`], }), @@ -358,10 +359,11 @@ function getSuggestedSearches(accountID: number = CONST.DEFAULT_NUMBER_ID, defau [CONST.SEARCH.SEARCH_KEYS.APPROVE]: { key: CONST.SEARCH.SEARCH_KEYS.APPROVE, translationPath: 'search.bulkActions.approve', - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, icon: Expensicons.ThumbsUp, searchQuery: buildQueryStringFromFilterFormValues({ - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, + groupBy: CONST.SEARCH.GROUP_BY.REPORTS, action: CONST.SEARCH.ACTION_FILTERS.APPROVE, to: [`${accountID}`], }), @@ -378,10 +380,11 @@ function getSuggestedSearches(accountID: number = CONST.DEFAULT_NUMBER_ID, defau [CONST.SEARCH.SEARCH_KEYS.PAY]: { key: CONST.SEARCH.SEARCH_KEYS.PAY, translationPath: 'search.bulkActions.pay', - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, icon: Expensicons.MoneyBag, searchQuery: buildQueryStringFromFilterFormValues({ - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, + groupBy: CONST.SEARCH.GROUP_BY.REPORTS, action: CONST.SEARCH.ACTION_FILTERS.PAY, reimbursable: CONST.SEARCH.BOOLEAN.YES, payer: accountID?.toString(), @@ -399,10 +402,10 @@ function getSuggestedSearches(accountID: number = CONST.DEFAULT_NUMBER_ID, defau [CONST.SEARCH.SEARCH_KEYS.EXPORT]: { key: CONST.SEARCH.SEARCH_KEYS.EXPORT, translationPath: 'common.export', - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, icon: Expensicons.CheckCircle, searchQuery: buildQueryStringFromFilterFormValues({ - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + groupBy: CONST.SEARCH.GROUP_BY.REPORTS, action: CONST.SEARCH.ACTION_FILTERS.EXPORT, exporter: [`${accountID}`], exportedOn: CONST.SEARCH.DATE_PRESETS.NEVER, @@ -724,7 +727,7 @@ function isTransactionGroupListItemType(item: ListItem): item is TransactionGrou * Type guard that checks if something is a TransactionReportGroupListItemType */ function isTransactionReportGroupListItemType(item: ListItem): item is TransactionReportGroupListItemType { - return isTransactionGroupListItemType(item) && 'groupedBy' in item && item.groupedBy === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT; + return isTransactionGroupListItemType(item) && 'groupedBy' in item && item.groupedBy === CONST.SEARCH.GROUP_BY.REPORTS; } /** @@ -1423,8 +1426,8 @@ function getReportSections( ...reportItem, action: allActions.at(0) ?? CONST.SEARCH.ACTION_TYPES.VIEW, allActions, + groupedBy: CONST.SEARCH.GROUP_BY.REPORTS, keyForList: String(reportItem.reportID), - groupedBy: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, from: transactions.length > 0 ? data.personalDetailsList[data?.[reportKey as ReportKey]?.accountID ?? CONST.DEFAULT_NUMBER_ID] : emptyPersonalDetails, to: !shouldShowBlankTo && reportItem.managerID ? data.personalDetailsList?.[reportItem.managerID] : emptyPersonalDetails, transactions, @@ -1596,7 +1599,7 @@ function getListItem(type: SearchDataTypes, status: SearchStatus, groupBy?: Sear if (type === CONST.SEARCH.DATA_TYPES.TASK) { return TaskListItem; } - if (type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT || groupBy) { + if (groupBy) { return TransactionGroupListItem; } return TransactionListItem; @@ -1623,14 +1626,12 @@ function getSections( return getTaskSections(data, formatPhoneNumber, archivedReportsIDList); } - if (type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT) { - return getReportSections(data, currentSearch, currentAccountID, formatPhoneNumber, reportActions); - } - if (groupBy) { // Disabling the default-case lint rule here is actually safer as this forces us to make the switch cases exhaustive // eslint-disable-next-line default-case switch (groupBy) { + case CONST.SEARCH.GROUP_BY.REPORTS: + return getReportSections(data, currentSearch, currentAccountID, formatPhoneNumber, reportActions); case CONST.SEARCH.GROUP_BY.FROM: return getMemberSections(data, queryJSON); case CONST.SEARCH.GROUP_BY.CARD: @@ -1661,14 +1662,13 @@ function getSortedSections( if (type === CONST.SEARCH.DATA_TYPES.TASK) { return getSortedTaskData(data as TaskListItemType[], localeCompare, sortBy, sortOrder); } - if (type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT) { - return getSortedReportData(data as TransactionReportGroupListItemType[], localeCompare); - } if (groupBy) { // Disabling the default-case lint rule here is actually safer as this forces us to make the switch cases exhaustive // eslint-disable-next-line default-case switch (groupBy) { + case CONST.SEARCH.GROUP_BY.REPORTS: + return getSortedReportData(data as TransactionReportGroupListItemType[], localeCompare); case CONST.SEARCH.GROUP_BY.FROM: return getSortedMemberData(data as TransactionMemberGroupListItemType[], localeCompare); case CONST.SEARCH.GROUP_BY.CARD: @@ -1810,7 +1810,7 @@ function getSortedReportActionData(data: ReportActionListItemType[], localeCompa * Checks if the search results contain any data, useful for determining if the search results are empty. */ function isSearchResultsEmpty(searchResults: SearchResults, groupBy?: SearchGroupBy) { - if (groupBy) { + if (groupBy && groupBy !== CONST.SEARCH.GROUP_BY.REPORTS) { return !Object.keys(searchResults?.data).some((key) => isGroupEntry(key)); } return !Object.keys(searchResults?.data).some( @@ -2113,7 +2113,7 @@ function isSearchDataLoaded(searchResults: SearchResults | undefined, queryJSON: return isDataLoaded; } -function getStatusOptions(type: SearchDataTypes) { +function getStatusOptions(type: SearchDataTypes, groupBy: SearchGroupBy | undefined) { switch (type) { case CONST.SEARCH.DATA_TYPES.INVOICE: return getInvoiceStatusOptions(); @@ -2121,11 +2121,9 @@ function getStatusOptions(type: SearchDataTypes) { return getTripStatusOptions(); case CONST.SEARCH.DATA_TYPES.TASK: return getTaskStatusOptions(); - case CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT: - return getExpenseReportedStatusOptions(); case CONST.SEARCH.DATA_TYPES.EXPENSE: default: - return getExpenseStatusOptions(); + return groupBy === CONST.SEARCH.GROUP_BY.REPORTS ? getExpenseReportedStatusOptions() : getExpenseStatusOptions(); } } @@ -2151,7 +2149,6 @@ function getHasOptions(type: SearchDataTypes) { function getTypeOptions(policies: OnyxCollection, currentUserLogin?: string) { const typeOptions: Array> = [ {text: translateLocal('common.expense'), value: CONST.SEARCH.DATA_TYPES.EXPENSE}, - {text: translateLocal('common.expenseReport'), value: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT}, {text: translateLocal('common.chat'), value: CONST.SEARCH.DATA_TYPES.CHAT}, {text: translateLocal('common.invoice'), value: CONST.SEARCH.DATA_TYPES.INVOICE}, {text: translateLocal('common.trip'), value: CONST.SEARCH.DATA_TYPES.TRIP}, diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 0e755df46844..9e93f0fcbda2 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -12445,11 +12445,7 @@ function shouldOptimisticallyUpdateSearch( isInvoice: boolean | undefined, transaction?: OnyxEntry, ) { - if ( - currentSearchQueryJSON.type !== CONST.SEARCH.DATA_TYPES.INVOICE && - currentSearchQueryJSON.type !== CONST.SEARCH.DATA_TYPES.EXPENSE && - currentSearchQueryJSON.type !== CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT - ) { + if (currentSearchQueryJSON.type !== CONST.SEARCH.DATA_TYPES.INVOICE && currentSearchQueryJSON.type !== CONST.SEARCH.DATA_TYPES.EXPENSE) { return false; } let shouldOptimisticallyUpdateByStatus; @@ -12475,10 +12471,7 @@ function shouldOptimisticallyUpdateSearch( const unapprovedCashSimilarSearchHash = suggestedSearches[CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CASH].similarSearchHash; const validSearchTypes = - (!isInvoice && currentSearchQueryJSON.type === CONST.SEARCH.DATA_TYPES.EXPENSE) || - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - (isInvoice && currentSearchQueryJSON.type === CONST.SEARCH.DATA_TYPES.INVOICE) || - currentSearchQueryJSON.type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT; + (!isInvoice && currentSearchQueryJSON.type === CONST.SEARCH.DATA_TYPES.EXPENSE) || (isInvoice && currentSearchQueryJSON.type === CONST.SEARCH.DATA_TYPES.INVOICE); return ( shouldOptimisticallyUpdateByStatus && diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 37a457b2177d..2caad0868ce7 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -9,7 +9,7 @@ import type {LocaleContextProps} from '@components/LocaleContextProvider'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import {usePersonalDetails} from '@components/OnyxListItemProvider'; import ScrollView from '@components/ScrollView'; -import type {SearchAmountFilterKeys, SearchDateFilterKeys, SearchFilterKey} from '@components/Search/types'; +import type {SearchAmountFilterKeys, SearchDateFilterKeys, SearchFilterKey, SearchGroupBy} from '@components/Search/types'; import SpacerView from '@components/SpacerView'; import Text from '@components/Text'; import useAdvancedSearchFilters from '@hooks/useAdvancedSearchFilters'; @@ -398,10 +398,7 @@ function getFilterDisplayTitle( if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.TYPE) { const filterValue = filters[key]; - if (filterValue === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT) { - return translate('common.expenseReport'); - } - return filterValue ? translate(`common.${filterValue}`) : undefined; + return filterValue ? translate(`common.${filterValue as ValueOf}`) : undefined; } if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.ACTION) { @@ -433,8 +430,8 @@ function getFilterDisplayTitle( return Array.isArray(filterValue) ? filterValue.join(', ') : filterValue; } -function getStatusFilterDisplayTitle(filters: Partial, type: SearchDataTypes, translate: LocaleContextProps['translate']) { - const statusOptions = getStatusOptions(type).concat({text: translate('common.all'), value: CONST.SEARCH.STATUS.EXPENSE.ALL}); +function getStatusFilterDisplayTitle(filters: Partial, type: SearchDataTypes, groupBy: SearchGroupBy | undefined, translate: LocaleContextProps['translate']) { + const statusOptions = getStatusOptions(type, groupBy).concat({text: translate('common.all'), value: CONST.SEARCH.STATUS.EXPENSE.ALL}); let filterValue = filters?.status; if (!filterValue?.length) { @@ -498,6 +495,8 @@ function AdvancedSearchFilters() { const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: false}); const [savedSearches] = useOnyx(ONYXKEYS.SAVED_SEARCHES, {canBeMissing: true}); const [searchAdvancedFilters = getEmptyObject()] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, {canBeMissing: true}); + + const groupBy = searchAdvancedFilters.groupBy; const [userCardList] = useOnyx(ONYXKEYS.CARD_LIST, {canBeMissing: false}); const [workspaceCardFeeds] = useOnyx(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST, {canBeMissing: false}); const allCards = useMemo(() => mergeCardListWithWorkspaceFeeds(workspaceCardFeeds ?? CONST.EMPTY_OBJECT, userCardList, true), [userCardList, workspaceCardFeeds]); @@ -570,7 +569,7 @@ function AdvancedSearchFilters() { const workspacesData = workspaces.flatMap((value) => value.data); filterTitle = baseFilterConfig[key].getTitle(searchAdvancedFilters, workspacesData); } else if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.STATUS) { - filterTitle = baseFilterConfig[key].getTitle(searchAdvancedFilters, currentType, translate); + filterTitle = baseFilterConfig[key].getTitle(searchAdvancedFilters, currentType, groupBy, translate); } else { filterTitle = baseFilterConfig[key].getTitle(searchAdvancedFilters, key, translate, localeCompare); } @@ -592,7 +591,7 @@ function AdvancedSearchFilters() { items: filters.at(0) ?? [], }, { - titleTranslationKey: queryJSON?.type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT ? 'common.reports' : 'common.expenses', + titleTranslationKey: 'common.expenses', items: filters.at(1) ?? [], }, { diff --git a/src/pages/Search/EmptySearchView.tsx b/src/pages/Search/EmptySearchView.tsx index 3e558711e87d..99d9ae707f12 100644 --- a/src/pages/Search/EmptySearchView.tsx +++ b/src/pages/Search/EmptySearchView.tsx @@ -15,6 +15,7 @@ import MenuItem from '@components/MenuItem'; import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction'; import ScrollView from '@components/ScrollView'; import {SearchScopeProvider} from '@components/Search/SearchScopeProvider'; +import type {SearchGroupBy} from '@components/Search/types'; import SearchRowSkeleton from '@components/Skeletons/SearchRowSkeleton'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; @@ -48,6 +49,7 @@ import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; type EmptySearchViewProps = { similarSearchHash: number; + groupBy?: SearchGroupBy | undefined; type: SearchDataTypes; hasResults: boolean; }; @@ -88,7 +90,7 @@ const tripsFeatures: FeatureListItem[] = [ }, ]; -function EmptySearchView({similarSearchHash, type, hasResults}: EmptySearchViewProps) { +function EmptySearchView({similarSearchHash, type, groupBy, hasResults}: EmptySearchViewProps) { const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const {typeMenuSections} = useSearchTypeMenuSections(); @@ -126,6 +128,7 @@ function EmptySearchView({similarSearchHash, type, hasResults}: EmptySearchViewP ) => function EmptySearchViewContent({ similarSearchHash, type, + groupBy, hasResults, currentUserPersonalDetails, typeMenuSections, @@ -288,7 +292,7 @@ function EmptySearchViewContent({ }; // If we are grouping by reports, show a custom message rather than a type-specific message - if (type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT) { + if (groupBy === CONST.SEARCH.GROUP_BY.REPORTS) { if (hasResults) { return { ...defaultViewItemHeader, @@ -441,6 +445,7 @@ function EmptySearchViewContent({ }; } }, [ + groupBy, type, typeMenuItems, similarSearchHash, diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersStatusPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersStatusPage.tsx index 0c1beb5f1a26..f37f1d3798f2 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersStatusPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersStatusPage.tsx @@ -23,6 +23,7 @@ function SearchFiltersStatusPage() { const {translate} = useLocalize(); const [searchAdvancedFiltersForm, searchAdvancedFiltersFormResult] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, {canBeMissing: true}); const currentType = searchAdvancedFiltersForm?.type ?? CONST.SEARCH.DATA_TYPES.EXPENSE; + const currentGroupBy = searchAdvancedFiltersForm?.groupBy; const [selectedItems, setSelectedItems] = useState(() => { if (!searchAdvancedFiltersForm?.status || searchAdvancedFiltersForm.status === CONST.SEARCH.STATUS.EXPENSE.ALL) { return []; @@ -35,7 +36,7 @@ function SearchFiltersStatusPage() { return searchAdvancedFiltersForm.status; }); - const items = useMemo(() => getStatusOptions(currentType), [currentType]); + const items = useMemo(() => getStatusOptions(currentType, currentGroupBy), [currentGroupBy, currentType]); const listData: ListItem[] = useMemo(() => { return items.map((statusOption) => ({ diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index e8c57db38b03..79d283256bb0 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -305,14 +305,14 @@ function SearchPage({route}: SearchPageProps) { // Determine if only full reports are selected by comparing the reportIDs of the selected transactions and the reportIDs of the selected reports const areFullReportsSelected = selectedTransactionReportIDs.length === selectedReportIDs.length && selectedTransactionReportIDs.every((id) => selectedReportIDs.includes(id)); - const typeExpenseReport = queryJSON?.type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT; + const groupByReports = queryJSON?.groupBy === CONST.SEARCH.GROUP_BY.REPORTS; const typeInvoice = queryJSON?.type === CONST.REPORT.TYPE.INVOICE; const typeExpense = queryJSON?.type === CONST.REPORT.TYPE.EXPENSE; const isAllOneTransactionReport = Object.values(selectedTransactions).every((transaction) => transaction.isFromOneTransactionReport); // If we're grouping by invoice or report, and all the expenses on the report are selected, or if all // the selected expenses are the only expenses of their parent expense report include the report level export option. - const includeReportLevelExport = ((typeExpenseReport || typeInvoice) && areFullReportsSelected) || (typeExpense && !typeExpenseReport && isAllOneTransactionReport); + const includeReportLevelExport = ((groupByReports || typeInvoice) && areFullReportsSelected) || (typeExpense && !groupByReports && isAllOneTransactionReport); // Collect a list of export templates available to the user from their account, policy, and custom integrations templates const policy = selectedPolicyIDs.length === 1 ? policies?.[`${ONYXKEYS.COLLECTION.POLICY}${selectedPolicyIDs.at(0)}`] : undefined; diff --git a/src/types/form/SearchAdvancedFiltersForm.ts b/src/types/form/SearchAdvancedFiltersForm.ts index 6d4fead73af9..b92bcf690b81 100644 --- a/src/types/form/SearchAdvancedFiltersForm.ts +++ b/src/types/form/SearchAdvancedFiltersForm.ts @@ -251,60 +251,7 @@ const ALLOWED_TYPE_FILTERS = { FILTER_KEYS.ATTENDEE, FILTER_KEYS.ATTENDEE_NOT, ], - [CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT]: [ - FILTER_KEYS.TYPE, - FILTER_KEYS.STATUS, - FILTER_KEYS.FROM, - FILTER_KEYS.FROM_NOT, - FILTER_KEYS.TO, - FILTER_KEYS.TO_NOT, - FILTER_KEYS.KEYWORD, - FILTER_KEYS.POLICY_ID, - FILTER_KEYS.DATE_ON, - FILTER_KEYS.DATE_NOT, - FILTER_KEYS.DATE_AFTER, - FILTER_KEYS.DATE_BEFORE, - FILTER_KEYS.TOTAL_EQUAL_TO, - FILTER_KEYS.TOTAL_NOT, - FILTER_KEYS.TOTAL_GREATER_THAN, - FILTER_KEYS.TOTAL_LESS_THAN, - FILTER_KEYS.CURRENCY, - FILTER_KEYS.CURRENCY_NOT, - FILTER_KEYS.GROUP_CURRENCY, - FILTER_KEYS.PAYER, - FILTER_KEYS.PAYER_NOT, - FILTER_KEYS.WITHDRAWAL_TYPE, - FILTER_KEYS.WITHDRAWAL_TYPE_NOT, - FILTER_KEYS.WITHDRAWN_AFTER, - FILTER_KEYS.WITHDRAWN_BEFORE, - FILTER_KEYS.WITHDRAWN_ON, - FILTER_KEYS.WITHDRAWN_NOT, - FILTER_KEYS.REPORT_ID, - FILTER_KEYS.REPORT_ID_NOT, - FILTER_KEYS.SUBMITTED_ON, - FILTER_KEYS.SUBMITTED_NOT, - FILTER_KEYS.SUBMITTED_AFTER, - FILTER_KEYS.SUBMITTED_BEFORE, - FILTER_KEYS.APPROVED_AFTER, - FILTER_KEYS.APPROVED_BEFORE, - FILTER_KEYS.APPROVED_ON, - FILTER_KEYS.APPROVED_NOT, - FILTER_KEYS.PAID_AFTER, - FILTER_KEYS.PAID_BEFORE, - FILTER_KEYS.PAID_ON, - FILTER_KEYS.PAID_NOT, - FILTER_KEYS.EXPORTED_AFTER, - FILTER_KEYS.EXPORTED_BEFORE, - FILTER_KEYS.EXPORTED_ON, - FILTER_KEYS.EXPORTED_NOT, - FILTER_KEYS.EXPORTER, - FILTER_KEYS.ACTION, - FILTER_KEYS.ACTION_NOT, - FILTER_KEYS.WITHDRAWAL_ID, - FILTER_KEYS.WITHDRAWAL_ID_NOT, - FILTER_KEYS.TITLE, - FILTER_KEYS.TITLE_NOT, - ], + [CONST.SEARCH.DATA_TYPES.INVOICE]: [ FILTER_KEYS.TYPE, FILTER_KEYS.STATUS, diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index d00f3fbffcee..97d5fa79bf77 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -213,10 +213,11 @@ describe('actions/IOU', () => { ...createRandomTransaction(1), }; const currentSearchQueryJSON = { - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, status: '' as SearchStatus, sortBy: CONST.SEARCH.TABLE_COLUMNS.DATE, sortOrder: CONST.SEARCH.SORT_ORDER.DESC, + groupBy: CONST.SEARCH.GROUP_BY.REPORTS, filters: { operator: CONST.SEARCH.SYNTAX_OPERATORS.AND, left: { @@ -230,7 +231,7 @@ describe('actions/IOU', () => { right: '20671314', }, }, - inputQuery: 'sortBy:date sortOrder:desc type:expense-report action:submit from:20671314', + inputQuery: 'sortBy:date sortOrder:desc type:expense groupBy:reports action:submit from:20671314', flatFilters: [ { key: CONST.SEARCH.SYNTAX_FILTER_KEYS.ACTION, @@ -253,7 +254,7 @@ describe('actions/IOU', () => { ], hash: 1920151829, recentSearchHash: 2100977843, - similarSearchHash: 1855682507, + similarSearchHash: 1476388677, } as SearchQueryJSON; const iouReport: Report = {...createRandomReport(2), type: CONST.REPORT.TYPE.EXPENSE, stateNum: CONST.REPORT.STATE_NUM.OPEN, statusNum: CONST.REPORT.STATUS_NUM.OPEN}; @@ -271,10 +272,11 @@ describe('actions/IOU', () => { ...createRandomTransaction(1), }; const currentSearchQueryJSON = { - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, status: '' as SearchStatus, sortBy: CONST.SEARCH.TABLE_COLUMNS.DATE, sortOrder: CONST.SEARCH.SORT_ORDER.DESC, + groupBy: CONST.SEARCH.GROUP_BY.REPORTS, filters: { operator: CONST.SEARCH.SYNTAX_OPERATORS.AND, left: { @@ -310,9 +312,9 @@ describe('actions/IOU', () => { ], hash: 1510971479, - inputQuery: 'sortBy:date sortOrder:desc type:expense-report action:approve to:20671314', + inputQuery: 'sortBy:date sortOrder:desc type:expense groupBy:reports action:approve to:20671314', recentSearchHash: 967911777, - similarSearchHash: 1539858783, + similarSearchHash: 601088623, } as SearchQueryJSON; const iouReport: Report = {...createRandomReport(2), type: CONST.REPORT.TYPE.EXPENSE, stateNum: CONST.REPORT.STATE_NUM.OPEN, statusNum: CONST.REPORT.STATUS_NUM.OPEN}; @@ -331,10 +333,11 @@ describe('actions/IOU', () => { reimbursable: true, }; const currentSearchQueryJSON = { - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, status: '' as SearchStatus, sortBy: CONST.SEARCH.TABLE_COLUMNS.DATE, sortOrder: CONST.SEARCH.SORT_ORDER.DESC, + groupBy: CONST.SEARCH.GROUP_BY.REPORTS, filters: { operator: CONST.SEARCH.SYNTAX_OPERATORS.EQUAL_TO, left: 'reimbursable', diff --git a/tests/ui/components/EmptySearchViewTest.tsx b/tests/ui/components/EmptySearchViewTest.tsx index 20d5595324dc..11fc8d106a8c 100644 --- a/tests/ui/components/EmptySearchViewTest.tsx +++ b/tests/ui/components/EmptySearchViewTest.tsx @@ -121,7 +121,8 @@ describe('EmptySearchView', () => { // Given a query string for expense search with draft status const queryString = buildQueryStringFromFilterFormValues({ - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, + groupBy: CONST.SEARCH.GROUP_BY.REPORTS, action: CONST.SEARCH.ACTION_FILTERS.SUBMIT, from: [CURRENT_USER_ACCOUNT_ID.toString()], }); @@ -134,6 +135,7 @@ describe('EmptySearchView', () => { similarSearchHash={queryJSON?.similarSearchHash ?? 1} type={dataType} hasResults={false} + groupBy={CONST.SEARCH.GROUP_BY.REPORTS} /> , ); @@ -155,7 +157,8 @@ describe('EmptySearchView', () => { // Given: A query string for expense search with draft status const queryString = buildQueryStringFromFilterFormValues({ - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, + groupBy: CONST.SEARCH.GROUP_BY.REPORTS, action: CONST.SEARCH.ACTION_FILTERS.SUBMIT, from: [CURRENT_USER_ACCOUNT_ID.toString()], }); @@ -168,6 +171,7 @@ describe('EmptySearchView', () => { similarSearchHash={queryJSON?.similarSearchHash ?? 1} type={dataType} hasResults={false} + groupBy={CONST.SEARCH.GROUP_BY.REPORTS} /> , ); diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts index 56796b6a20ed..77fb3fd2514c 100644 --- a/tests/unit/Search/SearchUIUtilsTest.ts +++ b/tests/unit/Search/SearchUIUtilsTest.ts @@ -940,7 +940,7 @@ const transactionsListItems = [ const transactionReportGroupListItems = [ { - groupedBy: 'expense-report', + groupedBy: 'reports', accountID: 18439984, action: 'submit', allActions: ['submit'], @@ -1046,7 +1046,7 @@ const transactionReportGroupListItems = [ unheldTotal: -5000, }, { - groupedBy: 'expense-report', + groupedBy: 'reports', accountID: 18439984, action: 'review', allActions: ['review', 'approve'], @@ -1157,7 +1157,7 @@ const transactionReportGroupListItems = [ unheldTotal: -5000, }, { - groupedBy: 'expense-report', + groupedBy: 'reports', accountID: 18439984, chatReportID: '6155022250251839', chatType: undefined, @@ -1198,7 +1198,7 @@ const transactionReportGroupListItems = [ transactions: [transactionsListItems.at(2), transactionsListItems.at(3)], }, { - groupedBy: 'expense-report', + groupedBy: 'reports', accountID: 18439984, action: 'view', allActions: ['view'], @@ -1658,16 +1658,16 @@ describe('SearchUIUtils', () => { expect(SearchUIUtils.getListItem(CONST.SEARCH.DATA_TYPES.EXPENSE, CONST.SEARCH.STATUS.EXPENSE.ALL, undefined)).toStrictEqual(TransactionListItem); }); - it('should return TransactionGroupListItem when type is EXPENSE-REPORT', () => { - expect(SearchUIUtils.getListItem(CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, CONST.SEARCH.STATUS.EXPENSE.ALL)).toStrictEqual(TransactionGroupListItem); + it('should return TransactionGroupListItem when type is EXPENSE and groupBy is report', () => { + expect(SearchUIUtils.getListItem(CONST.SEARCH.DATA_TYPES.EXPENSE, CONST.SEARCH.STATUS.EXPENSE.ALL, CONST.SEARCH.GROUP_BY.REPORTS)).toStrictEqual(TransactionGroupListItem); }); - it('should return TransactionListItem when type is TRIP', () => { - expect(SearchUIUtils.getListItem(CONST.SEARCH.DATA_TYPES.TRIP, CONST.SEARCH.STATUS.EXPENSE.ALL)).toStrictEqual(TransactionListItem); + it('should return TransactionGroupListItem when type is TRIP and groupBy is report', () => { + expect(SearchUIUtils.getListItem(CONST.SEARCH.DATA_TYPES.TRIP, CONST.SEARCH.STATUS.EXPENSE.ALL, CONST.SEARCH.GROUP_BY.REPORTS)).toStrictEqual(TransactionGroupListItem); }); - it('should return TransactionListItem when type is INVOICE', () => { - expect(SearchUIUtils.getListItem(CONST.SEARCH.DATA_TYPES.INVOICE, CONST.SEARCH.STATUS.EXPENSE.ALL)).toStrictEqual(TransactionListItem); + it('should return TransactionGroupListItem when type is INVOICE and groupBy is report', () => { + expect(SearchUIUtils.getListItem(CONST.SEARCH.DATA_TYPES.INVOICE, CONST.SEARCH.STATUS.EXPENSE.ALL, CONST.SEARCH.GROUP_BY.REPORTS)).toStrictEqual(TransactionGroupListItem); }); it('should return TransactionGroupListItem when type is EXPENSE and groupBy is member', () => { @@ -1733,7 +1733,13 @@ describe('SearchUIUtils', () => { }, }; - const result = SearchUIUtils.getSections(CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, testSearchResults.data, 2074551, formatPhoneNumber) as TransactionGroupListItemType[]; + const result = SearchUIUtils.getSections( + CONST.SEARCH.DATA_TYPES.EXPENSE, + testSearchResults.data, + 2074551, + formatPhoneNumber, + CONST.SEARCH.GROUP_BY.REPORTS, + ) as TransactionGroupListItemType[]; const reportGroup = result.find((group) => group.transactions?.some((transaction) => transaction.transactionID === distanceTransactionID)); @@ -1746,16 +1752,22 @@ describe('SearchUIUtils', () => { expect(Object.keys(distanceTransaction ?? {}).length).toBe(expectedPropertyCount); }); - it('should return transactionReportGroupListItems result when type is expense-report', () => { - expect(SearchUIUtils.getSections(CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, searchResults.data, 2074551, formatPhoneNumber)).toStrictEqual(transactionReportGroupListItems); + it('should return getReportSections result when type is EXPENSE and groupBy is report', () => { + expect(SearchUIUtils.getSections(CONST.SEARCH.DATA_TYPES.EXPENSE, searchResults.data, 2074551, formatPhoneNumber, CONST.SEARCH.GROUP_BY.REPORTS)).toStrictEqual( + transactionReportGroupListItems, + ); }); - it('should return transactionsListItems result when type is TRIP', () => { - expect(SearchUIUtils.getSections(CONST.SEARCH.DATA_TYPES.TRIP, searchResults.data, 2074551, formatPhoneNumber)).toStrictEqual(transactionsListItems); + it('should return getReportSections result when type is TRIP and groupBy is report', () => { + expect(SearchUIUtils.getSections(CONST.SEARCH.DATA_TYPES.TRIP, searchResults.data, 2074551, formatPhoneNumber, CONST.SEARCH.GROUP_BY.REPORTS)).toStrictEqual( + transactionReportGroupListItems, + ); }); - it('should return transactionsListItems result when type is INVOICE and groupBy is report', () => { - expect(SearchUIUtils.getSections(CONST.SEARCH.DATA_TYPES.INVOICE, searchResults.data, 2074551, formatPhoneNumber)).toStrictEqual(transactionsListItems); + it('should return getReportSections result when type is INVOICE and groupBy is report', () => { + expect(SearchUIUtils.getSections(CONST.SEARCH.DATA_TYPES.INVOICE, searchResults.data, 2074551, formatPhoneNumber, CONST.SEARCH.GROUP_BY.REPORTS)).toStrictEqual( + transactionReportGroupListItems, + ); }); it('should handle data where transaction keys appear before report keys in getReportSections', () => { @@ -1783,8 +1795,8 @@ describe('SearchUIUtils', () => { [`policy_${policyID}`]: searchResults.data[`policy_${policyID}`], }; - const resultTransactionFirst = SearchUIUtils.getSections(CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, testDataTransactionFirst, 2074551, formatPhoneNumber); - const resultReportFirst = SearchUIUtils.getSections(CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, testDataReportFirst, 2074551, formatPhoneNumber); + const resultTransactionFirst = SearchUIUtils.getSections(CONST.SEARCH.DATA_TYPES.EXPENSE, testDataTransactionFirst, 2074551, formatPhoneNumber, CONST.SEARCH.GROUP_BY.REPORTS); + const resultReportFirst = SearchUIUtils.getSections(CONST.SEARCH.DATA_TYPES.EXPENSE, testDataReportFirst, 2074551, formatPhoneNumber, CONST.SEARCH.GROUP_BY.REPORTS); expect(resultTransactionFirst).toBeDefined(); expect(Array.isArray(resultTransactionFirst)).toBe(true); @@ -1855,22 +1867,22 @@ describe('SearchUIUtils', () => { expect(SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.EXPENSE, '', transactionsListItems, localeCompare, 'date', 'asc', undefined)).toStrictEqual(transactionsListItems); }); - it('should return getSortedReportData result when type is expense-report', () => { - expect(SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, '', transactionReportGroupListItems, localeCompare, 'date', 'asc')).toStrictEqual( - transactionReportGroupListItems, - ); + it('should return getSortedReportData result when type is EXPENSE and groupBy is report', () => { + expect( + SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.EXPENSE, '', transactionReportGroupListItems, localeCompare, 'date', 'asc', CONST.SEARCH.GROUP_BY.REPORTS), + ).toStrictEqual(transactionReportGroupListItems); }); it('should return getSortedReportData result when type is TRIP and groupBy is report', () => { - expect(SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.TRIP, '', transactionReportGroupListItems, localeCompare, 'date', 'asc')).toStrictEqual( - transactionReportGroupListItems, - ); + expect( + SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.TRIP, '', transactionReportGroupListItems, localeCompare, 'date', 'asc', CONST.SEARCH.GROUP_BY.REPORTS), + ).toStrictEqual(transactionReportGroupListItems); }); it('should return getSortedReportData result when type is INVOICE and groupBy is report', () => { - expect(SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.INVOICE, '', transactionReportGroupListItems, localeCompare, 'date', 'asc')).toStrictEqual( - transactionReportGroupListItems, - ); + expect( + SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.INVOICE, '', transactionReportGroupListItems, localeCompare, 'date', 'asc', CONST.SEARCH.GROUP_BY.REPORTS), + ).toStrictEqual(transactionReportGroupListItems); }); it('should return getSortedMemberData result when type is EXPENSE and groupBy is member', () => { @@ -1916,7 +1928,7 @@ describe('SearchUIUtils', () => { }), expect.objectContaining({ translationPath: 'common.reports', - type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + type: CONST.SEARCH.DATA_TYPES.EXPENSE, icon: Expensicons.Document, }), expect.objectContaining({ @@ -2268,7 +2280,7 @@ describe('SearchUIUtils', () => { .map((section) => section.menuItems) .flat(); - const expectedQueries = ['type:expense sortBy:date sortOrder:desc', 'type:expense-report sortBy:date sortOrder:desc', 'type:chat sortBy:date sortOrder:desc']; + const expectedQueries = ['type:expense sortBy:date sortOrder:desc', 'type:expense sortBy:date sortOrder:desc groupBy:reports', 'type:chat sortBy:date sortOrder:desc']; menuItems.forEach((item, index) => { expect(item.searchQuery).toStrictEqual(expectedQueries.at(index)); diff --git a/tests/unit/Search/handleActionButtonPressTest.ts b/tests/unit/Search/handleActionButtonPressTest.ts index 71f46c581209..4fc14390e6a0 100644 --- a/tests/unit/Search/handleActionButtonPressTest.ts +++ b/tests/unit/Search/handleActionButtonPressTest.ts @@ -9,7 +9,7 @@ import type {LastPaymentMethod, SearchResults} from '@src/types/onyx'; jest.mock('@src/components/ConfirmedRoute.tsx'); const mockReportItemWithHold = { - groupedBy: 'expense-report', + groupedBy: 'reports', shouldAnimateInHighlight: false, accountID: 1206, action: 'approve', diff --git a/tests/unit/TransactionGroupListItemTest.tsx b/tests/unit/TransactionGroupListItemTest.tsx index ab6155105f05..91621081fb60 100644 --- a/tests/unit/TransactionGroupListItemTest.tsx +++ b/tests/unit/TransactionGroupListItemTest.tsx @@ -110,7 +110,7 @@ const mockReport: TransactionReportGroupListItemType = { displayName: 'Main Applause QA', }, transactions: [], - groupedBy: 'expense-report', + groupedBy: 'reports', keyForList: '515146912679679', }; @@ -153,7 +153,7 @@ describe('TransactionGroupListItem', () => { item: report, showTooltip: false, onSelectRow: mockOnSelectRow, - searchType: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, + groupBy: CONST.SEARCH.GROUP_BY.REPORTS, canSelectMultiple: true, };