From d5c7dd95dd49e77b9c8b0dbf75419f3d8eeab0eb Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Fri, 1 Sep 2023 01:19:52 +0200 Subject: [PATCH 01/20] sidebar Performance improvments --- src/libs/ReportActionsUtils.js | 18 +++++--- src/libs/ReportUtils.js | 4 +- src/libs/SidebarUtils.js | 82 ++++++++++++++++++++-------------- 3 files changed, 61 insertions(+), 43 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index c90efb54785d..b401dc39cae8 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -1,9 +1,9 @@ +/* eslint-disable rulesdir/prefer-underscore-method */ import lodashGet from 'lodash/get'; import _ from 'underscore'; -import lodashMerge from 'lodash/merge'; +import {max, parseISO} from 'date-fns'; import lodashFindLast from 'lodash/findLast'; import Onyx from 'react-native-onyx'; -import moment from 'moment'; import * as CollectionUtils from './CollectionUtils'; import CONST from '../CONST'; import ONYXKEYS from '../ONYXKEYS'; @@ -371,14 +371,18 @@ function shouldReportActionBeVisibleAsLastAction(reportAction) { * @return {Object} */ function getLastVisibleAction(reportID, actionsToMerge = {}) { - const actions = _.toArray(lodashMerge({}, allReportActions[reportID], actionsToMerge)); - const visibleActions = _.filter(actions, (action) => shouldReportActionBeVisibleAsLastAction(action)); + const actions = Object.values({ + ...allReportActions[reportID], + ...actionsToMerge, + }); + const visibleActions = actions.filter((action) => shouldReportActionBeVisibleAsLastAction(action)); - if (_.isEmpty(visibleActions)) { + if (visibleActions.length === 0) { return {}; } - - return _.max(visibleActions, (action) => moment.utc(action.created).valueOf()); + const maxDate = max(visibleActions.map((action) => parseISO(action.created))); + const maxAction = visibleActions.find((action) => new Date(action.created).toString() === maxDate.toString()); + return maxAction; } /** diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 3bd63fc0a073..a0d1b93fb52a 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2754,7 +2754,7 @@ function shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, !report || !report.reportID || report.isHidden || - (_.isEmpty(report.participantAccountIDs) && !isChatThread(report) && !isPublicRoom(report) && !isArchivedRoom(report) && !isMoneyRequestReport(report) && !isTaskReport(report)) + (report.participantAccountIDs.length === 0 && !isChatThread(report) && !isPublicRoom(report) && !isArchivedRoom(report) && !isMoneyRequestReport(report) && !isTaskReport(report)) ) { return false; } @@ -2790,7 +2790,7 @@ function shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, // Include reports that have errors from trying to add a workspace // If we excluded it, then the red-brock-road pattern wouldn't work for the user to resolve the error - if (report.errorFields && !_.isEmpty(report.errorFields.addWorkspaceRoom)) { + if (report.errorFields && report.errorFields.addWorkspaceRoom !== 0) { return true; } diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 118035f9f605..2da974960c5d 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -1,8 +1,9 @@ +/* eslint-disable rulesdir/prefer-underscore-method */ import Onyx from 'react-native-onyx'; import _ from 'underscore'; import lodashGet from 'lodash/get'; -import lodashOrderBy from 'lodash/orderBy'; import Str from 'expensify-common/lib/str'; +import CryptoJS from 'crypto-js'; import ONYXKEYS from '../ONYXKEYS'; import * as ReportUtils from './ReportUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; @@ -75,6 +76,9 @@ function setIsSidebarLoadedReady() { resolveSidebarIsReadyPromise(); } +// Define a cache object to store the memoized results +const reportIDsCache = new Map(); + /** * @param {String} currentReportId * @param {Object} allReportsDict @@ -85,22 +89,37 @@ function setIsSidebarLoadedReady() { * @returns {String[]} An array of reportIDs sorted in the proper order */ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions) { + // Generate a unique cache key based on the function arguments + const cachedReports = JSON.stringify([currentReportId, allReportsDict, betas, policies, priorityMode, Object.values(allReportActions).length], (key, value) => { + // Exclude 'participantAccountIDs' and 'participants' properties from all objects in the 'allReportsDict' array + if (key === 'participantAccountIDs' || key === 'participants' || key === 'lastMessageText') { + return undefined; + } + return value; + }); + // // Check if the result is already in the cache + if (reportIDsCache.has(cachedReports)) { + return reportIDsCache.get(cachedReports); + } + const isInGSDMode = priorityMode === CONST.PRIORITY_MODE.GSD; const isInDefaultMode = !isInGSDMode; // Filter out all the reports that shouldn't be displayed - const reportsToDisplay = _.filter(allReportsDict, (report) => ReportUtils.shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, policies, allReportActions, true)); + const reportsToDisplay = Object.values(allReportsDict).filter((report) => + ReportUtils.shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, policies, allReportActions, true), + ); - if (_.isEmpty(reportsToDisplay)) { + if (reportsToDisplay.length === 0) { // Display Concierge chat report when there is no report to be displayed - const conciergeChatReport = _.find(allReportsDict, ReportUtils.isConciergeChatReport); + const conciergeChatReport = Object.values(allReportsDict).find(ReportUtils.isConciergeChatReport); if (conciergeChatReport) { reportsToDisplay.push(conciergeChatReport); } } // There are a few properties that need to be calculated for the report which are used when sorting reports. - _.each(reportsToDisplay, (report) => { + reportsToDisplay.forEach((report) => { // Normally, the spread operator would be used here to clone the report and prevent the need to reassign the params. // However, this code needs to be very performant to handle thousands of reports, so in the interest of speed, we're just going to disable this lint rule and add // the reportDisplayName property to the report object directly. @@ -121,43 +140,36 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p // 5. Archived reports // - Sorted by lastVisibleActionCreated in default (most recent) view mode // - Sorted by reportDisplayName in GSD (focus) view mode - let pinnedReports = []; - let outstandingIOUReports = []; - let draftReports = []; - let nonArchivedReports = []; - let archivedReports = []; - _.each(reportsToDisplay, (report) => { + const pinnedReports = []; + const outstandingIOUReports = []; + const draftReports = []; + const nonArchivedReports = []; + const archivedReports = []; + reportsToDisplay.forEach((report) => { if (report.isPinned) { pinnedReports.push(report); - return; - } - - if (ReportUtils.isWaitingForIOUActionFromCurrentUser(report)) { + } else if (ReportUtils.isWaitingForIOUActionFromCurrentUser(report)) { outstandingIOUReports.push(report); - return; - } - - if (report.hasDraft) { + } else if (report.hasDraft) { draftReports.push(report); - return; - } - - if (ReportUtils.isArchivedRoom(report)) { + } else if (ReportUtils.isArchivedRoom(report)) { archivedReports.push(report); - return; + } else { + nonArchivedReports.push(report); } - - nonArchivedReports.push(report); }); // Sort each group of reports accordingly - pinnedReports = _.sortBy(pinnedReports, (report) => report.displayName.toLowerCase()); - outstandingIOUReports = lodashOrderBy(outstandingIOUReports, ['iouReportAmount', (report) => report.displayName.toLowerCase()], ['desc', 'asc']); - draftReports = _.sortBy(draftReports, (report) => report.displayName.toLowerCase()); - nonArchivedReports = isInDefaultMode - ? lodashOrderBy(nonArchivedReports, ['lastVisibleActionCreated', (report) => report.displayName.toLowerCase()], ['desc', 'asc']) - : lodashOrderBy(nonArchivedReports, [(report) => report.displayName.toLowerCase()], ['asc']); - archivedReports = _.sortBy(archivedReports, (report) => (isInDefaultMode ? report.lastVisibleActionCreated : report.displayName.toLowerCase())); + pinnedReports.sort((a, b) => a.displayName.localeCompare(b.displayName)); + outstandingIOUReports.sort((a, b) => b.iouReportAmount - a.iouReportAmount || a.displayName.localeCompare(b.displayName)); + draftReports.sort((a, b) => a.displayName.localeCompare(b.displayName)); + if (isInDefaultMode) { + nonArchivedReports.sort((a, b) => new Date(b.lastVisibleActionCreated) - new Date(a.lastVisibleActionCreated) || a.displayName.localeCompare(b.displayName)); + archivedReports.sort((a, b) => new Date(b.lastVisibleActionCreated) - new Date(a.lastVisibleActionCreated)); + } else { + nonArchivedReports.sort((a, b) => a.displayName.localeCompare(b.displayName)); + archivedReports.sort((a, b) => a.displayName.localeCompare(b.displayName)); + } // For archived reports ensure that most recent reports are at the top by reversing the order of the arrays because underscore will only sort them in ascending order if (isInDefaultMode) { @@ -166,7 +178,9 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p // Now that we have all the reports grouped and sorted, they must be flattened into an array and only return the reportID. // The order the arrays are concatenated in matters and will determine the order that the groups are displayed in the sidebar. - return _.pluck([].concat(pinnedReports).concat(outstandingIOUReports).concat(draftReports).concat(nonArchivedReports).concat(archivedReports), 'reportID'); + const LHNReports = [].concat(pinnedReports, outstandingIOUReports, draftReports, nonArchivedReports, archivedReports).map((report) => report.reportID); + reportIDsCache.set(cachedReports, LHNReports); + return LHNReports; } /** From d0f687c304b01d69851f6a94715f8001fb64f4ae Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Fri, 1 Sep 2023 01:31:52 +0200 Subject: [PATCH 02/20] adjustments --- src/libs/ReportActionsUtils.js | 2 +- src/libs/SidebarUtils.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index b401dc39cae8..125e3e601085 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -381,7 +381,7 @@ function getLastVisibleAction(reportID, actionsToMerge = {}) { return {}; } const maxDate = max(visibleActions.map((action) => parseISO(action.created))); - const maxAction = visibleActions.find((action) => new Date(action.created).toString() === maxDate.toString()); + const maxAction = visibleActions.find((action) => parseISO(action.created).toString() === maxDate.toString()); return maxAction; } diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 2da974960c5d..d193c9c42311 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -3,7 +3,6 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; import lodashGet from 'lodash/get'; import Str from 'expensify-common/lib/str'; -import CryptoJS from 'crypto-js'; import ONYXKEYS from '../ONYXKEYS'; import * as ReportUtils from './ReportUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; @@ -91,7 +90,7 @@ const reportIDsCache = new Map(); function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions) { // Generate a unique cache key based on the function arguments const cachedReports = JSON.stringify([currentReportId, allReportsDict, betas, policies, priorityMode, Object.values(allReportActions).length], (key, value) => { - // Exclude 'participantAccountIDs' and 'participants' properties from all objects in the 'allReportsDict' array + // Exclude 'participantAccountIDs', 'participants' and 'lastMessageText' properties from all objects in the 'allReportsDict' array if (key === 'participantAccountIDs' || key === 'participants' || key === 'lastMessageText') { return undefined; } From 33017cf94db08729ccaae4dd5f693b58e3f109d3 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Fri, 1 Sep 2023 17:49:50 +0200 Subject: [PATCH 03/20] adjustments --- src/libs/ReportActionsUtils.js | 12 +++++------ src/libs/ReportUtils.js | 32 +++++++++++++--------------- src/libs/SidebarUtils.js | 39 +++++++++++++++++----------------- 3 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 125e3e601085..6f65ada87da0 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -1,7 +1,7 @@ /* eslint-disable rulesdir/prefer-underscore-method */ import lodashGet from 'lodash/get'; import _ from 'underscore'; -import {max, parseISO} from 'date-fns'; +import {max, parseISO, isEqual} from 'date-fns'; import lodashFindLast from 'lodash/findLast'; import Onyx from 'react-native-onyx'; import * as CollectionUtils from './CollectionUtils'; @@ -328,9 +328,9 @@ function shouldReportActionBeVisible(reportAction, key) { // Filter out any unsupported reportAction types if ( - !_.has(CONST.REPORT.ACTIONS.TYPE, reportAction.actionName) && - !_.contains(_.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG), reportAction.actionName) && - !_.contains(_.values(CONST.REPORT.ACTIONS.TYPE.TASK), reportAction.actionName) + !Object.values(CONST.REPORT.ACTIONS.TYPE).includes(reportAction.actionName) && + !Object.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG).includes(reportAction.actionName) && + !Object.values(CONST.REPORT.ACTIONS.TYPE.TASK).includes(reportAction.actionName) ) { return false; } @@ -346,7 +346,7 @@ function shouldReportActionBeVisible(reportAction, key) { // All other actions are displayed except thread parents, deleted, or non-pending actions const isDeleted = isDeletedAction(reportAction); - const isPending = !_.isEmpty(reportAction.pendingAction); + const isPending = !!reportAction.pendingAction; return !isDeleted || isPending || isDeletedParentAction(reportAction); } @@ -381,7 +381,7 @@ function getLastVisibleAction(reportID, actionsToMerge = {}) { return {}; } const maxDate = max(visibleActions.map((action) => parseISO(action.created))); - const maxAction = visibleActions.find((action) => parseISO(action.created).toString() === maxDate.toString()); + const maxAction = visibleActions.find((action) => isEqual(parseISO(action.created), maxDate)); return maxAction; } diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index a0d1b93fb52a..35e0468f9366 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1,3 +1,4 @@ +/* eslint-disable rulesdir/prefer-underscore-method */ import _ from 'underscore'; import {format, parseISO} from 'date-fns'; import Str from 'expensify-common/lib/str'; @@ -86,7 +87,7 @@ function getChatType(report) { * @returns {Object} */ function getPolicy(policyID) { - const policy = lodashGet(allPolicies, `${ONYXKEYS.COLLECTION.POLICY}${policyID}`) || {}; + const policy = allPolicies[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`] || {}; return policy; } @@ -151,7 +152,7 @@ function getReportParticipantsTitle(accountIDs) { * @returns {Boolean} */ function isChatReport(report) { - return lodashGet(report, 'type') === CONST.REPORT.TYPE.CHAT; + return report.type === CONST.REPORT.TYPE.CHAT; } /** @@ -161,7 +162,7 @@ function isChatReport(report) { * @returns {Boolean} */ function isExpenseReport(report) { - return lodashGet(report, 'type') === CONST.REPORT.TYPE.EXPENSE; + return report.type === CONST.REPORT.TYPE.EXPENSE; } /** @@ -171,7 +172,7 @@ function isExpenseReport(report) { * @returns {Boolean} */ function isIOUReport(report) { - return lodashGet(report, 'type') === CONST.REPORT.TYPE.IOU; + return report.type === CONST.REPORT.TYPE.IOU; } /** @@ -181,7 +182,7 @@ function isIOUReport(report) { * @returns {Boolean} */ function isTaskReport(report) { - return lodashGet(report, 'type') === CONST.REPORT.TYPE.TASK; + return report.type === CONST.REPORT.TYPE.TASK; } /** @@ -221,7 +222,7 @@ function isCompletedTaskReport(report) { * @returns {Boolean} */ function isReportManager(report) { - return lodashGet(report, 'managerID') === currentUserAccountID; + return report.managerID === currentUserAccountID; } /** @@ -231,7 +232,7 @@ function isReportManager(report) { * @returns {Boolean} */ function isReportApproved(report) { - return lodashGet(report, 'stateNum') === CONST.REPORT.STATE_NUM.SUBMITTED && lodashGet(report, 'statusNum') === CONST.REPORT.STATUS.APPROVED; + return report.statusNum === CONST.REPORT.STATE_NUM.SUBMITTED && report.statusNum === CONST.REPORT.STATUS.APPROVED; } /** @@ -255,9 +256,8 @@ function sortReportsByLastRead(reports) { * @returns {Boolean} */ function isSettled(reportID) { - const report = lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {}); - - if (_.isEmpty(report) || report.isWaitingOnBankAccount) { + const report = allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] || {}; + if (Object.keys(report).length === 0 || report.isWaitingOnBankAccount) { return false; } @@ -271,7 +271,7 @@ function isSettled(reportID) { * @returns {Boolean} */ function isCurrentUserSubmitter(reportID) { - const report = lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {}); + const report = allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] || {}; return report && report.ownerEmail === currentUserEmail; } @@ -378,8 +378,7 @@ function isChatRoom(report) { * @returns {Boolean} */ function isPublicRoom(report) { - const visibility = lodashGet(report, 'visibility', ''); - return visibility === CONST.REPORT.VISIBILITY.PUBLIC || visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE; + return report.visibility === CONST.REPORT.VISIBILITY.PUBLIC || report.visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE; } /** @@ -389,8 +388,7 @@ function isPublicRoom(report) { * @returns {Boolean} */ function isPublicAnnounceRoom(report) { - const visibility = lodashGet(report, 'visibility', ''); - return visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE; + return report.visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE; } /** @@ -560,7 +558,7 @@ function findLastAccessedReport(reports, ignoreDomainRooms, policies, isFirstTim * @returns {Boolean} */ function isArchivedRoom(report) { - return lodashGet(report, ['statusNum']) === CONST.REPORT.STATUS.CLOSED && lodashGet(report, ['stateNum']) === CONST.REPORT.STATE_NUM.SUBMITTED; + return report.stateNum === CONST.REPORT.STATUS.CLOSED && report.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED; } /** @@ -728,7 +726,7 @@ function isMoneyRequest(reportOrID) { * @returns {Boolean} */ function isMoneyRequestReport(reportOrID) { - const report = _.isObject(reportOrID) ? reportOrID : allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`]; + const report = typeof reportOrID === 'object' ? reportOrID : allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`]; return isIOUReport(report) || isExpenseReport(report); } diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index d193c9c42311..fb0fdbcefe60 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -89,13 +89,17 @@ const reportIDsCache = new Map(); */ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions) { // Generate a unique cache key based on the function arguments - const cachedReports = JSON.stringify([currentReportId, allReportsDict, betas, policies, priorityMode, Object.values(allReportActions).length], (key, value) => { - // Exclude 'participantAccountIDs', 'participants' and 'lastMessageText' properties from all objects in the 'allReportsDict' array - if (key === 'participantAccountIDs' || key === 'participants' || key === 'lastMessageText') { - return undefined; - } - return value; - }); + const cachedReports = JSON.stringify( + // eslint-disable-next-line es/no-optional-chaining + [currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions[`reportActions_${currentReportId}`]?.length || 1], + (key, value) => { + // Exclude 'participantAccountIDs', 'participants' and 'lastMessageText' properties from all objects in the 'allReportsDict' array + if (key === 'participantAccountIDs' || key === 'participants' || key === 'lastMessageText') { + return undefined; + } + return value; + }, + ); // // Check if the result is already in the cache if (reportIDsCache.has(cachedReports)) { return reportIDsCache.get(cachedReports); @@ -159,20 +163,17 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p }); // Sort each group of reports accordingly - pinnedReports.sort((a, b) => a.displayName.localeCompare(b.displayName)); - outstandingIOUReports.sort((a, b) => b.iouReportAmount - a.iouReportAmount || a.displayName.localeCompare(b.displayName)); - draftReports.sort((a, b) => a.displayName.localeCompare(b.displayName)); + pinnedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); + outstandingIOUReports.sort((a, b) => b.iouReportAmount - a.iouReportAmount || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); + draftReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); if (isInDefaultMode) { - nonArchivedReports.sort((a, b) => new Date(b.lastVisibleActionCreated) - new Date(a.lastVisibleActionCreated) || a.displayName.localeCompare(b.displayName)); - archivedReports.sort((a, b) => new Date(b.lastVisibleActionCreated) - new Date(a.lastVisibleActionCreated)); + nonArchivedReports.sort( + (a, b) => new Date(b.lastVisibleActionCreated) - new Date(a.lastVisibleActionCreated) || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()), + ); + archivedReports.sort((a, b) => new Date(a.lastVisibleActionCreated) - new Date(b.lastVisibleActionCreated)); } else { - nonArchivedReports.sort((a, b) => a.displayName.localeCompare(b.displayName)); - archivedReports.sort((a, b) => a.displayName.localeCompare(b.displayName)); - } - - // For archived reports ensure that most recent reports are at the top by reversing the order of the arrays because underscore will only sort them in ascending order - if (isInDefaultMode) { - archivedReports.reverse(); + nonArchivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); + archivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); } // Now that we have all the reports grouped and sorted, they must be flattened into an array and only return the reportID. From 3ac7d3c35ceff66e7dec964f72ca84340c10e517 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Fri, 1 Sep 2023 19:03:45 +0200 Subject: [PATCH 04/20] cache improve --- src/libs/SidebarUtils.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index fb0fdbcefe60..8170bf7eb068 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -78,6 +78,16 @@ function setIsSidebarLoadedReady() { // Define a cache object to store the memoized results const reportIDsCache = new Map(); +// Function to set a key-value pair while maintaining the maximum key limit +function setWithLimit(map, key, value) { + if (map.size >= 5) { + // If the map has reached its limit, remove the first (oldest) key-value pair + const firstKey = map.keys().next().value; + map.delete(firstKey); + } + map.set(key, value); +} + /** * @param {String} currentReportId * @param {Object} allReportsDict @@ -179,7 +189,7 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p // Now that we have all the reports grouped and sorted, they must be flattened into an array and only return the reportID. // The order the arrays are concatenated in matters and will determine the order that the groups are displayed in the sidebar. const LHNReports = [].concat(pinnedReports, outstandingIOUReports, draftReports, nonArchivedReports, archivedReports).map((report) => report.reportID); - reportIDsCache.set(cachedReports, LHNReports); + setWithLimit(reportIDsCache, cachedReports, LHNReports); return LHNReports; } From 497db511a0254e7152c05628dfc968a3bb02533f Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Fri, 1 Sep 2023 19:48:55 +0200 Subject: [PATCH 05/20] fix tests --- src/libs/ReportActionsUtils.js | 1 - src/libs/ReportUtils.js | 9 +++++---- tests/actions/IOUTest.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 6f65ada87da0..75173ce672a0 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -330,7 +330,6 @@ function shouldReportActionBeVisible(reportAction, key) { if ( !Object.values(CONST.REPORT.ACTIONS.TYPE).includes(reportAction.actionName) && !Object.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG).includes(reportAction.actionName) && - !Object.values(CONST.REPORT.ACTIONS.TYPE.TASK).includes(reportAction.actionName) ) { return false; } diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 35e0468f9366..6c6487d172a9 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -87,8 +87,8 @@ function getChatType(report) { * @returns {Object} */ function getPolicy(policyID) { - const policy = allPolicies[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`] || {}; - return policy; + if (!allPolicies || !policyID) return {}; + return allPolicies[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]; } /** @@ -256,8 +256,9 @@ function sortReportsByLastRead(reports) { * @returns {Boolean} */ function isSettled(reportID) { - const report = allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] || {}; - if (Object.keys(report).length === 0 || report.isWaitingOnBankAccount) { + if (!allReports) return false; + const report = allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + if ((report && Object.keys(report).length === 0) || report.isWaitingOnBankAccount) { return false; } diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index 6fbbe19cec8e..96e89dce12c4 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -32,7 +32,7 @@ describe('actions/IOU', () => { }); describe('requestMoney', () => { - it('creates new chat if needed', () => { + it.only('creates new chat if needed', () => { const amount = 10000; const comment = 'Giv money plz'; const merchant = 'KFC'; From de864d347bb2d37e6b5f9581dc686345c0606a00 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Fri, 1 Sep 2023 19:51:16 +0200 Subject: [PATCH 06/20] fix --- src/libs/ReportActionsUtils.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 75173ce672a0..e1471757debd 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -327,10 +327,7 @@ function shouldReportActionBeVisible(reportAction, key) { } // Filter out any unsupported reportAction types - if ( - !Object.values(CONST.REPORT.ACTIONS.TYPE).includes(reportAction.actionName) && - !Object.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG).includes(reportAction.actionName) && - ) { + if (!Object.values(CONST.REPORT.ACTIONS.TYPE).includes(reportAction.actionName) && !Object.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG).includes(reportAction.actionName)) { return false; } From ed8e76c6eeed91083c19a790ed5fa3661ac16309 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Fri, 1 Sep 2023 20:02:42 +0200 Subject: [PATCH 07/20] fix --- src/libs/ReportUtils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 6c6487d172a9..8ca0ae6c2949 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -88,7 +88,7 @@ function getChatType(report) { */ function getPolicy(policyID) { if (!allPolicies || !policyID) return {}; - return allPolicies[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]; + return allPolicies[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`] || {}; } /** @@ -152,6 +152,7 @@ function getReportParticipantsTitle(accountIDs) { * @returns {Boolean} */ function isChatReport(report) { + if (!report) return false; return report.type === CONST.REPORT.TYPE.CHAT; } From 79e40b8d5856101146c5dc42cfa1379ce23c51e5 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 4 Sep 2023 17:09:52 +0200 Subject: [PATCH 08/20] fix tests --- src/libs/ReportUtils.js | 7 ++++--- tests/actions/IOUTest.js | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 8ca0ae6c2949..773a686106f9 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -163,6 +163,7 @@ function isChatReport(report) { * @returns {Boolean} */ function isExpenseReport(report) { + if (!report) return false; return report.type === CONST.REPORT.TYPE.EXPENSE; } @@ -173,6 +174,7 @@ function isExpenseReport(report) { * @returns {Boolean} */ function isIOUReport(report) { + if (!report) return false; return report.type === CONST.REPORT.TYPE.IOU; } @@ -183,6 +185,7 @@ function isIOUReport(report) { * @returns {Boolean} */ function isTaskReport(report) { + if (!report) return false; return report.type === CONST.REPORT.TYPE.TASK; } @@ -2774,10 +2777,8 @@ function shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, if (report.hasDraft || isWaitingForIOUActionFromCurrentUser(report) || isWaitingForTaskCompleteFromAssignee(report)) { return true; } - const lastVisibleMessage = ReportActionsUtils.getLastVisibleMessage(report.reportID); const isEmptyChat = !lastVisibleMessage.lastMessageText && !lastVisibleMessage.lastMessageTranslationKey; - // Hide only chat threads that haven't been commented on (other threads are actionable) if (isChatThread(report) && isEmptyChat) { return false; @@ -2790,7 +2791,7 @@ function shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, // Include reports that have errors from trying to add a workspace // If we excluded it, then the red-brock-road pattern wouldn't work for the user to resolve the error - if (report.errorFields && report.errorFields.addWorkspaceRoom !== 0) { + if (report.errorFields && report.errorFields.addWorkspaceRoom && report.errorFields.addWorkspaceRoom !== 0) { return true; } diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index 96e89dce12c4..6fbbe19cec8e 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -32,7 +32,7 @@ describe('actions/IOU', () => { }); describe('requestMoney', () => { - it.only('creates new chat if needed', () => { + it('creates new chat if needed', () => { const amount = 10000; const comment = 'Giv money plz'; const merchant = 'KFC'; From 48ab69a7166b8794a766a933fb42c86aef97ef87 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 4 Sep 2023 23:05:13 +0200 Subject: [PATCH 09/20] adjustments --- src/libs/ReportUtils.js | 2 +- src/libs/SidebarUtils.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 773a686106f9..1aca06846dc0 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -261,7 +261,7 @@ function sortReportsByLastRead(reports) { */ function isSettled(reportID) { if (!allReports) return false; - const report = allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] || {}; if ((report && Object.keys(report).length === 0) || report.isWaitingOnBankAccount) { return false; } diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 8170bf7eb068..b589526d516b 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -110,6 +110,7 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p return value; }, ); + // // Check if the result is already in the cache if (reportIDsCache.has(cachedReports)) { return reportIDsCache.get(cachedReports); From 67dbbd98e9ae1f4825588add3a0ef1d5150c0f4c Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 5 Sep 2023 15:40:00 +0200 Subject: [PATCH 10/20] tests cache fix --- src/libs/SidebarUtils.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index b589526d516b..2c4658eec0bf 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -88,6 +88,9 @@ function setWithLimit(map, key, value) { map.set(key, value); } +// Variable to verify initial ONYX actions +let hasInitialReportActions = false; + /** * @param {String} currentReportId * @param {Object} allReportsDict @@ -112,9 +115,10 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p ); // // Check if the result is already in the cache - if (reportIDsCache.has(cachedReports)) { + if (reportIDsCache.has(cachedReports) && hasInitialReportActions) { return reportIDsCache.get(cachedReports); } + hasInitialReportActions = Object.values(lastReportActions).length > 0; const isInGSDMode = priorityMode === CONST.PRIORITY_MODE.GSD; const isInDefaultMode = !isInGSDMode; From cad9c3f97e9d437674b74ce313023f99544e02b3 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 5 Sep 2023 21:36:05 +0200 Subject: [PATCH 11/20] no report verify --- src/libs/ReportUtils.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 1aca06846dc0..d271ae5a0c6f 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -226,6 +226,7 @@ function isCompletedTaskReport(report) { * @returns {Boolean} */ function isReportManager(report) { + if (!report) return false; return report.managerID === currentUserAccountID; } @@ -236,6 +237,7 @@ function isReportManager(report) { * @returns {Boolean} */ function isReportApproved(report) { + if (!report) return false; return report.statusNum === CONST.REPORT.STATE_NUM.SUBMITTED && report.statusNum === CONST.REPORT.STATUS.APPROVED; } @@ -383,6 +385,7 @@ function isChatRoom(report) { * @returns {Boolean} */ function isPublicRoom(report) { + if (!report) return false; return report.visibility === CONST.REPORT.VISIBILITY.PUBLIC || report.visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE; } @@ -393,6 +396,7 @@ function isPublicRoom(report) { * @returns {Boolean} */ function isPublicAnnounceRoom(report) { + if (!report) return false; return report.visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE; } @@ -563,6 +567,7 @@ function findLastAccessedReport(reports, ignoreDomainRooms, policies, isFirstTim * @returns {Boolean} */ function isArchivedRoom(report) { + if (!report) return false; return report.stateNum === CONST.REPORT.STATUS.CLOSED && report.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED; } From fbc5fa23c9006065662c8fe21a5c2b4cb3263745 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Wed, 6 Sep 2023 13:42:05 +0200 Subject: [PATCH 12/20] adjustments --- src/libs/SidebarUtils.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 2c4658eec0bf..c40207437abb 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -88,7 +88,7 @@ function setWithLimit(map, key, value) { map.set(key, value); } -// Variable to verify initial ONYX actions +// Variable to verify if ONYX actions are loaded let hasInitialReportActions = false; /** @@ -102,7 +102,7 @@ let hasInitialReportActions = false; */ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions) { // Generate a unique cache key based on the function arguments - const cachedReports = JSON.stringify( + const cachedReportsKey = JSON.stringify( // eslint-disable-next-line es/no-optional-chaining [currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions[`reportActions_${currentReportId}`]?.length || 1], (key, value) => { @@ -115,8 +115,8 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p ); // // Check if the result is already in the cache - if (reportIDsCache.has(cachedReports) && hasInitialReportActions) { - return reportIDsCache.get(cachedReports); + if (reportIDsCache.has(cachedReportsKey) && hasInitialReportActions) { + return reportIDsCache.get(cachedReportsKey); } hasInitialReportActions = Object.values(lastReportActions).length > 0; @@ -194,7 +194,7 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p // Now that we have all the reports grouped and sorted, they must be flattened into an array and only return the reportID. // The order the arrays are concatenated in matters and will determine the order that the groups are displayed in the sidebar. const LHNReports = [].concat(pinnedReports, outstandingIOUReports, draftReports, nonArchivedReports, archivedReports).map((report) => report.reportID); - setWithLimit(reportIDsCache, cachedReports, LHNReports); + setWithLimit(reportIDsCache, cachedReportsKey, LHNReports); return LHNReports; } From 46563f0a91834e54a5b1c2407b046fc5f51a932b Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 11 Sep 2023 14:00:41 +0200 Subject: [PATCH 13/20] fixes --- src/libs/ReportUtils.js | 29 ++++++++++------------------- src/libs/SidebarUtils.js | 12 +++++------- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index e89462629c45..6b43a26c5921 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -160,8 +160,7 @@ function getReportParticipantsTitle(accountIDs) { * @returns {Boolean} */ function isChatReport(report) { - if (!report) return false; - return report.type === CONST.REPORT.TYPE.CHAT; + return report && report.type === CONST.REPORT.TYPE.CHAT; } /** @@ -171,8 +170,7 @@ function isChatReport(report) { * @returns {Boolean} */ function isExpenseReport(report) { - if (!report) return false; - return report.type === CONST.REPORT.TYPE.EXPENSE; + return report && report.type === CONST.REPORT.TYPE.EXPENSE; } /** @@ -182,8 +180,7 @@ function isExpenseReport(report) { * @returns {Boolean} */ function isIOUReport(report) { - if (!report) return false; - return report.type === CONST.REPORT.TYPE.IOU; + return report && report.type === CONST.REPORT.TYPE.IOU; } /** @@ -193,8 +190,7 @@ function isIOUReport(report) { * @returns {Boolean} */ function isTaskReport(report) { - if (!report) return false; - return report.type === CONST.REPORT.TYPE.TASK; + return report && report.type === CONST.REPORT.TYPE.TASK; } /** @@ -234,8 +230,7 @@ function isCompletedTaskReport(report) { * @returns {Boolean} */ function isReportManager(report) { - if (!report) return false; - return report.managerID === currentUserAccountID; + return report && report.managerID === currentUserAccountID; } /** @@ -245,8 +240,7 @@ function isReportManager(report) { * @returns {Boolean} */ function isReportApproved(report) { - if (!report) return false; - return report.statusNum === CONST.REPORT.STATE_NUM.SUBMITTED && report.statusNum === CONST.REPORT.STATUS.APPROVED; + return report && report.statusNum === CONST.REPORT.STATE_NUM.SUBMITTED && report.statusNum === CONST.REPORT.STATUS.APPROVED; } /** @@ -393,8 +387,7 @@ function isChatRoom(report) { * @returns {Boolean} */ function isPublicRoom(report) { - if (!report) return false; - return report.visibility === CONST.REPORT.VISIBILITY.PUBLIC || report.visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE; + return (report && report.visibility === CONST.REPORT.VISIBILITY.PUBLIC) || report.visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE; } /** @@ -404,8 +397,7 @@ function isPublicRoom(report) { * @returns {Boolean} */ function isPublicAnnounceRoom(report) { - if (!report) return false; - return report.visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE; + return report && report.visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE; } /** @@ -575,8 +567,7 @@ function findLastAccessedReport(reports, ignoreDomainRooms, policies, isFirstTim * @returns {Boolean} */ function isArchivedRoom(report) { - if (!report) return false; - return report.stateNum === CONST.REPORT.STATUS.CLOSED && report.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED; + return report && report.stateNum === CONST.REPORT.STATUS.CLOSED && report.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED; } /** @@ -2835,7 +2826,7 @@ function shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, // Include reports that have errors from trying to add a workspace // If we excluded it, then the red-brock-road pattern wouldn't work for the user to resolve the error - if (report.errorFields && report.errorFields.addWorkspaceRoom && report.errorFields.addWorkspaceRoom !== 0) { + if (report.errorFields && report.errorFields.addWorkspaceRoom) { return true; } diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index c40207437abb..15b2f00fc784 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -104,7 +104,7 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p // Generate a unique cache key based on the function arguments const cachedReportsKey = JSON.stringify( // eslint-disable-next-line es/no-optional-chaining - [currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions[`reportActions_${currentReportId}`]?.length || 1], + [currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentReportId}`]?.length || 1], (key, value) => { // Exclude 'participantAccountIDs', 'participants' and 'lastMessageText' properties from all objects in the 'allReportsDict' array if (key === 'participantAccountIDs' || key === 'participants' || key === 'lastMessageText') { @@ -114,7 +114,7 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p }, ); - // // Check if the result is already in the cache + // Check if the result is already in the cache if (reportIDsCache.has(cachedReportsKey) && hasInitialReportActions) { return reportIDsCache.get(cachedReportsKey); } @@ -122,15 +122,13 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p const isInGSDMode = priorityMode === CONST.PRIORITY_MODE.GSD; const isInDefaultMode = !isInGSDMode; - + const allReportsDictValues = Object.values(allReportsDict); // Filter out all the reports that shouldn't be displayed - const reportsToDisplay = Object.values(allReportsDict).filter((report) => - ReportUtils.shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, policies, allReportActions, true), - ); + const reportsToDisplay = allReportsDictValues.filter((report) => ReportUtils.shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, policies, allReportActions, true)); if (reportsToDisplay.length === 0) { // Display Concierge chat report when there is no report to be displayed - const conciergeChatReport = Object.values(allReportsDict).find(ReportUtils.isConciergeChatReport); + const conciergeChatReport = allReportsDictValues.find(ReportUtils.isConciergeChatReport); if (conciergeChatReport) { reportsToDisplay.push(conciergeChatReport); } From 9199e0cd9d9ead0d9e71d8bbdfaf88b98eb37c50 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 11 Sep 2023 14:07:15 +0200 Subject: [PATCH 14/20] fixes --- src/libs/ReportUtils.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index c363c78813cd..2b4c4c263244 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -266,7 +266,7 @@ function sortReportsByLastRead(reports) { function isSettled(reportID) { if (!allReports) return false; const report = allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] || {}; - if ((report && Object.keys(report).length === 0) || report.isWaitingOnBankAccount) { + if ((typeof report === 'object' && Object.keys(report).length === 0) || report.isWaitingOnBankAccount) { return false; } @@ -280,6 +280,9 @@ function isSettled(reportID) { * @returns {Boolean} */ function isCurrentUserSubmitter(reportID) { + if (!allReports) { + return false; + } const report = allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] || {}; return report && report.ownerEmail === currentUserEmail; } From 782e43efebbdabc838a589620301007e5dbe2ddf Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 11 Sep 2023 14:37:46 +0200 Subject: [PATCH 15/20] regression fixes --- src/libs/ReportUtils.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 2b4c4c263244..b2347c745d5d 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -570,7 +570,7 @@ function findLastAccessedReport(reports, ignoreDomainRooms, policies, isFirstTim * @returns {Boolean} */ function isArchivedRoom(report) { - return report && report.stateNum === CONST.REPORT.STATUS.CLOSED && report.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED; + return report && report.statusNum === CONST.REPORT.STATUS.CLOSED && report.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED; } /** @@ -2796,7 +2796,13 @@ function shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, !report || !report.reportID || report.isHidden || - (report.participantAccountIDs.length === 0 && !isChatThread(report) && !isPublicRoom(report) && !isArchivedRoom(report) && !isMoneyRequestReport(report) && !isTaskReport(report)) + (report.participantAccountIDs && + report.participantAccountIDs.length === 0 && + !isChatThread(report) && + !isPublicRoom(report) && + !isArchivedRoom(report) && + !isMoneyRequestReport(report) && + !isTaskReport(report)) ) { return false; } From ca8a7ccf77ad01aef123669a24b61008a239dd52 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 11 Sep 2023 18:29:33 +0200 Subject: [PATCH 16/20] adjustments --- src/libs/SidebarUtils.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 15b2f00fc784..3065e91b4988 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -106,7 +106,10 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p // eslint-disable-next-line es/no-optional-chaining [currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentReportId}`]?.length || 1], (key, value) => { - // Exclude 'participantAccountIDs', 'participants' and 'lastMessageText' properties from all objects in the 'allReportsDict' array + /** + * Exclude 'participantAccountIDs', 'participants' and 'lastMessageText' not to overwhelm a cached key value with huge data, + * which we don't need to store in a cacheKey + */ if (key === 'participantAccountIDs' || key === 'participants' || key === 'lastMessageText') { return undefined; } @@ -118,6 +121,8 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p if (reportIDsCache.has(cachedReportsKey) && hasInitialReportActions) { return reportIDsCache.get(cachedReportsKey); } + + // This is needed to prevent caching when Onyx is empty for a second render hasInitialReportActions = Object.values(lastReportActions).length > 0; const isInGSDMode = priorityMode === CONST.PRIORITY_MODE.GSD; From 06080a4ca94410822ef915b4543e4ae47c82d528 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Wed, 13 Sep 2023 17:55:26 +0200 Subject: [PATCH 17/20] lodashMerge alternative --- src/libs/ReportActionsUtils.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 25e1b82038c6..b837b9dfce2c 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -4,6 +4,7 @@ import _ from 'underscore'; import {max, parseISO, isEqual} from 'date-fns'; import lodashFindLast from 'lodash/findLast'; import Onyx from 'react-native-onyx'; +import lodashMerge from 'lodash/merge'; import * as CollectionUtils from './CollectionUtils'; import CONST from '../CONST'; import ONYXKEYS from '../ONYXKEYS'; @@ -375,9 +376,15 @@ function shouldReportActionBeVisibleAsLastAction(reportAction) { * @return {Object} */ function getLastVisibleAction(reportID, actionsToMerge = {}) { + let updatedActionsToMerge = actionsToMerge; + if (Object.keys(updatedActionsToMerge).length !== 0) { + const actionID = Object.keys(actionsToMerge)[0]; + updatedActionsToMerge = {[actionID]: {...allReportActions[reportID][actionID], ...actionsToMerge[actionID]}}; + } + const actions = Object.values({ ...allReportActions[reportID], - ...actionsToMerge, + ...updatedActionsToMerge, }); const visibleActions = actions.filter((action) => shouldReportActionBeVisibleAsLastAction(action)); From 2e51898d2f48989aca28af8e050dfd4a47b0a46b Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Wed, 13 Sep 2023 18:00:47 +0200 Subject: [PATCH 18/20] lint fix --- src/libs/ReportActionsUtils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index b837b9dfce2c..fb8b6d066030 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -4,7 +4,6 @@ import _ from 'underscore'; import {max, parseISO, isEqual} from 'date-fns'; import lodashFindLast from 'lodash/findLast'; import Onyx from 'react-native-onyx'; -import lodashMerge from 'lodash/merge'; import * as CollectionUtils from './CollectionUtils'; import CONST from '../CONST'; import ONYXKEYS from '../ONYXKEYS'; From 22da8ded225bd50d49c23892de06d64617582073 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Wed, 13 Sep 2023 18:34:00 +0200 Subject: [PATCH 19/20] updated lastVisible action to handle multiple objects --- src/libs/ReportActionsUtils.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index fb8b6d066030..9bff24aa9d87 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -375,12 +375,12 @@ function shouldReportActionBeVisibleAsLastAction(reportAction) { * @return {Object} */ function getLastVisibleAction(reportID, actionsToMerge = {}) { - let updatedActionsToMerge = actionsToMerge; - if (Object.keys(updatedActionsToMerge).length !== 0) { - const actionID = Object.keys(actionsToMerge)[0]; - updatedActionsToMerge = {[actionID]: {...allReportActions[reportID][actionID], ...actionsToMerge[actionID]}}; + const updatedActionsToMerge = {}; + if (actionsToMerge && Object.keys(actionsToMerge).length !== 0) { + Object.keys(actionsToMerge).forEach( + (actionToMergeID) => (updatedActionsToMerge[actionToMergeID] = {...allReportActions[reportID][actionToMergeID], ...actionsToMerge[actionToMergeID]}), + ); } - const actions = Object.values({ ...allReportActions[reportID], ...updatedActionsToMerge, From 42fff4a12e9548fb6f47c3e750aca6cfcc8b10a2 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 18 Sep 2023 13:31:38 +0200 Subject: [PATCH 20/20] adjustments --- src/libs/ReportUtils.js | 2 +- src/libs/SidebarUtils.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index b2347c745d5d..25d535d281f4 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -390,7 +390,7 @@ function isChatRoom(report) { * @returns {Boolean} */ function isPublicRoom(report) { - return (report && report.visibility === CONST.REPORT.VISIBILITY.PUBLIC) || report.visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE; + return report && (report.visibility === CONST.REPORT.VISIBILITY.PUBLIC || report.visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE); } /** diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 3065e91b4988..b1d38cb72bd2 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -188,6 +188,7 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p nonArchivedReports.sort( (a, b) => new Date(b.lastVisibleActionCreated) - new Date(a.lastVisibleActionCreated) || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()), ); + // For archived reports ensure that most recent reports are at the top by reversing the order archivedReports.sort((a, b) => new Date(a.lastVisibleActionCreated) - new Date(b.lastVisibleActionCreated)); } else { nonArchivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()));