From 8ac9d8c5ad401b109fbaf546348c49855ff9ee94 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 10 May 2023 13:32:28 -1000 Subject: [PATCH 01/22] method to get most recent blahblah --- src/libs/ReportActionsUtils.js | 34 ++++++++++++++++++++++++++++++++++ src/libs/actions/App.js | 9 ++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 86034d8a14ef..2534ebb92df9 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -285,6 +285,39 @@ function getLinkedTransactionID(reportID, reportActionID) { return reportAction.originalMessage.IOUTransactionID; } +/** + * @returns {object} + */ +function getMostRecentStoredReportAction() { + let mostRecentReportAction; + let mostRecentReportActionCreated = new Date(0).toISOString(); + + // Flatten all the actions + // Loop over them all to find the one that is the most recent + const flatReportActions = _.flatten(_.map(allReportActions, actions => _.values(actions))); + _.each(flatReportActions, (action) => { + // Pending actions should not be counted here as a user could create a comment or some other action while offline and the server might know about + // messages they have not seen yet. + if (!_.isEmpty(action.pendingAction)) { + return; + } + + // All actions should have this, but if not they are not useful to us. + if (!action.created) { + return; + } + + if (action.created < mostRecentReportActionCreated) { + return; + } + + mostRecentReportActionCreated = action.created; + mostRecentReportAction = action; + }); + + return mostRecentReportAction; +} + export { getSortedReportActions, getLastVisibleAction, @@ -298,4 +331,5 @@ export { getLastClosedReportAction, getLatestReportActionFromOnyxData, getLinkedTransactionID, + getMostRecentStoredReportAction, }; diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index e2d49f11c69e..14eb8a03078a 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -15,6 +15,7 @@ import ROUTES from '../../ROUTES'; import * as SessionUtils from '../SessionUtils'; import getCurrentUrl from '../Navigation/currentUrl'; import * as Session from './Session'; +import * as ReportActionsUtils from '../ReportActionsUtils'; let currentUserAccountID; let currentUserEmail = ''; @@ -184,9 +185,15 @@ function openApp() { * Refreshes data when the app reconnects */ function reconnectApp() { + // When the app reconnects we do a fast "sync" of the LHN and only return chats that have new messages. We achieve this by sending the most recent reportActionID + // we have locally. And then only update the user about chats with messages that have occurred after that reportActionID. + // + // 1. Look through the local report actions to find the most recent reportActionID out of all of them + // 2. Send this to the server so that it can compute which chats are critical for the user to see and then follow up with a more complete sync later + const mostRecentReportAction = ReportActionsUtils.getMostRecentStoredReportAction(); API.write( CONST.NETWORK.COMMAND.RECONNECT_APP, - {policyIDList: getNonOptimisticPolicyIDs(allPolicies)}, + {policyIDList: getNonOptimisticPolicyIDs(allPolicies), mostRecentReportActionID: mostRecentReportAction.reportActionID}, { optimisticData: [ { From 72dcafca73e635bcca1c94947ecbc978f724c443 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Thu, 11 May 2023 12:20:33 -1000 Subject: [PATCH 02/22] add getMostRecentReportActionLastModified() --- src/libs/ReportActionsUtils.js | 20 ++++++++++---------- src/libs/actions/App.js | 7 +++---- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 2534ebb92df9..22f8db27f4e4 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -286,11 +286,11 @@ function getLinkedTransactionID(reportID, reportActionID) { } /** - * @returns {object} + * @returns {string} */ -function getMostRecentStoredReportAction() { - let mostRecentReportAction; - let mostRecentReportActionCreated = new Date(0).toISOString(); +function getMostRecentReportActionLastModified() { + let mostRecentlyModifiedReportAction; + let mostRecentReportActionLastModified = new Date(0).toISOString(); // Flatten all the actions // Loop over them all to find the one that is the most recent @@ -303,19 +303,19 @@ function getMostRecentStoredReportAction() { } // All actions should have this, but if not they are not useful to us. - if (!action.created) { + if (!action.lastModified) { return; } - if (action.created < mostRecentReportActionCreated) { + if (action.lastModified < mostRecentReportActionLastModified) { return; } - mostRecentReportActionCreated = action.created; - mostRecentReportAction = action; + mostRecentReportActionLastModified = action.lastModified; + mostRecentlyModifiedReportAction = action; }); - return mostRecentReportAction; + return mostRecentlyModifiedReportAction; } export { @@ -331,5 +331,5 @@ export { getLastClosedReportAction, getLatestReportActionFromOnyxData, getLinkedTransactionID, - getMostRecentStoredReportAction, + getMostRecentReportActionLastModified, }; diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 14eb8a03078a..aa83a8a11d51 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -188,12 +188,11 @@ function reconnectApp() { // When the app reconnects we do a fast "sync" of the LHN and only return chats that have new messages. We achieve this by sending the most recent reportActionID // we have locally. And then only update the user about chats with messages that have occurred after that reportActionID. // - // 1. Look through the local report actions to find the most recent reportActionID out of all of them - // 2. Send this to the server so that it can compute which chats are critical for the user to see and then follow up with a more complete sync later - const mostRecentReportAction = ReportActionsUtils.getMostRecentStoredReportAction(); + // - Look through the local report actions to find the most recently modified report action + // - We Send this to the server so that it can compute which chats are critical for the user to see so we can update them in the LHN API.write( CONST.NETWORK.COMMAND.RECONNECT_APP, - {policyIDList: getNonOptimisticPolicyIDs(allPolicies), mostRecentReportActionID: mostRecentReportAction.reportActionID}, + {policyIDList: getNonOptimisticPolicyIDs(allPolicies), mostRecentReportActionLastModified: ReportActionsUtils.getMostRecentReportActionLastModified()}, { optimisticData: [ { From 3b680b0efafabf4edfe3c391d2be3aaabc4ecddc Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Thu, 11 May 2023 12:36:17 -1000 Subject: [PATCH 03/22] Actually send the timestamp --- src/libs/ReportActionsUtils.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 510f48d3a555..427376a7f95f 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -289,7 +289,7 @@ function getLinkedTransactionID(reportID, reportActionID) { * @returns {string} */ function getMostRecentReportActionLastModified() { - let mostRecentlyModifiedReportAction; + // Start with the oldest date possible let mostRecentReportActionLastModified = new Date(0).toISOString(); // Flatten all the actions @@ -312,10 +312,9 @@ function getMostRecentReportActionLastModified() { } mostRecentReportActionLastModified = action.lastModified; - mostRecentlyModifiedReportAction = action; }); - return mostRecentlyModifiedReportAction; + return mostRecentReportActionLastModified; } function isCreatedTaskReportAction(reportAction) { From e17680640320c7e313dee45b2d0505de96e10d46 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Thu, 11 May 2023 14:29:00 -1000 Subject: [PATCH 04/22] Subscribe to correct key --- src/libs/ReportActionsUtils.js | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 427376a7f95f..7734e4ea69d8 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -11,6 +11,19 @@ import ONYXKEYS from '../ONYXKEYS'; import Log from './Log'; import isReportMessageAttachment from './isReportMessageAttachment'; +const allReports = {}; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + callback: (report, key) => { + if (!key || !report) { + return; + } + + const reportID = CollectionUtils.extractCollectionItemID(key); + allReports[reportID] = report; + }, +}); + const allReportActions = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS, @@ -302,16 +315,27 @@ function getMostRecentReportActionLastModified() { return; } - // All actions should have this, but if not they are not useful to us. - if (!action.lastModified) { + let lastModified = action.lastModified; + if (!lastModified) { + lastModified = action.created; + } + + if (lastModified < mostRecentReportActionLastModified) { return; } - if (action.lastModified < mostRecentReportActionLastModified) { + mostRecentReportActionLastModified = lastModified; + }); + + // We might not have actions so we also look at the report objects to see if any have a lastVisibleActionLastModified that is more recent. We don't need to get + // any reports that have been updated before either a recently updated report or reportAction as we should be up to date on these + _.each(allReports, (report) => { + const reportLastVisibleActionLastModified = report.lastVisibleActionLastModified || report.lastVisibleActionCreated; + if (reportLastVisibleActionLastModified < mostRecentReportActionLastModified) { return; } - mostRecentReportActionLastModified = action.lastModified; + mostRecentReportActionLastModified = reportLastVisibleActionLastModified; }); return mostRecentReportActionLastModified; From 32e19d002a17748f6ad7279137cd0517b62cf7e0 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 19 May 2023 12:09:29 -1000 Subject: [PATCH 05/22] Run prettier --- src/libs/ReportActionsUtils.js | 74 +++++++++++++++++----------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 541f5197f6d0..ea8cca24011a 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -383,43 +383,43 @@ function getLinkedTransactionID(reportID, reportActionID) { * @returns {string} */ function getMostRecentReportActionLastModified() { - // Start with the oldest date possible - let mostRecentReportActionLastModified = new Date(0).toISOString(); - - // Flatten all the actions - // Loop over them all to find the one that is the most recent - const flatReportActions = _.flatten(_.map(allReportActions, actions => _.values(actions))); - _.each(flatReportActions, (action) => { - // Pending actions should not be counted here as a user could create a comment or some other action while offline and the server might know about - // messages they have not seen yet. - if (!_.isEmpty(action.pendingAction)) { - return; - } - - let lastModified = action.lastModified; - if (!lastModified) { - lastModified = action.created; - } - - if (lastModified < mostRecentReportActionLastModified) { - return; - } - - mostRecentReportActionLastModified = lastModified; - }); - - // We might not have actions so we also look at the report objects to see if any have a lastVisibleActionLastModified that is more recent. We don't need to get - // any reports that have been updated before either a recently updated report or reportAction as we should be up to date on these - _.each(allReports, (report) => { - const reportLastVisibleActionLastModified = report.lastVisibleActionLastModified || report.lastVisibleActionCreated; - if (reportLastVisibleActionLastModified < mostRecentReportActionLastModified) { - return; - } - - mostRecentReportActionLastModified = reportLastVisibleActionLastModified; - }); - - return mostRecentReportActionLastModified; + // Start with the oldest date possible + let mostRecentReportActionLastModified = new Date(0).toISOString(); + + // Flatten all the actions + // Loop over them all to find the one that is the most recent + const flatReportActions = _.flatten(_.map(allReportActions, (actions) => _.values(actions))); + _.each(flatReportActions, (action) => { + // Pending actions should not be counted here as a user could create a comment or some other action while offline and the server might know about + // messages they have not seen yet. + if (!_.isEmpty(action.pendingAction)) { + return; + } + + let lastModified = action.lastModified; + if (!lastModified) { + lastModified = action.created; + } + + if (lastModified < mostRecentReportActionLastModified) { + return; + } + + mostRecentReportActionLastModified = lastModified; + }); + + // We might not have actions so we also look at the report objects to see if any have a lastVisibleActionLastModified that is more recent. We don't need to get + // any reports that have been updated before either a recently updated report or reportAction as we should be up to date on these + _.each(allReports, (report) => { + const reportLastVisibleActionLastModified = report.lastVisibleActionLastModified || report.lastVisibleActionCreated; + if (reportLastVisibleActionLastModified < mostRecentReportActionLastModified) { + return; + } + + mostRecentReportActionLastModified = reportLastVisibleActionLastModified; + }); + + return mostRecentReportActionLastModified; } /** From bb88c621a6d5c4b64b4ab735181b4f35e1182388 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 13 Jun 2023 13:47:28 -1000 Subject: [PATCH 06/22] check reports and policies --- src/libs/actions/App.js | 50 +++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index aa83a8a11d51..56cfb5109983 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -138,17 +138,50 @@ AppState.addEventListener('change', (nextAppState) => { appState = nextAppState; }); -/** - * Fetches data needed for app initialization - */ -function openApp() { - isReadyToOpenApp.then(() => { - // We need a fresh connection/callback here to make sure that the list of policyIDs that is sent to OpenApp is the most updated list from Onyx +function getPolicies() { + return new Promise((resolve) => { const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY, waitForCollectionCallback: true, callback: (policies) => { Onyx.disconnect(connectionID); + resolve(policies); + }, + }); + }); +} +function getCollection(key) { + return new Promise((resolve) => { + const connectionID = Onyx.connect({ + key, + waitForCollectionCallback: true, + callback: (reports) => { + Onyx.disconnect(connectionID); + resolve(reports); + }, + }); + }); +} + +function getReports() { +} + +/** + * Fetches data needed for app initialization + */ +function openApp() { + let hasExistingReportData = false; + isReadyToOpenApp.then(() => + // If we are opening the app after a first sign in then we will have no data whatsoever. This is easily checked by looking to see if + // the user has any report data at all. All users should have at least one report with Concierge so this is a reliable way to check if + // we are signing in the first time or if the app is being opened after it was killed or the page refreshed. + getCollection(ONYXKEYS.COLLECTION.REPORT) + .then((reports) => { + console.log({reports}); + hasExistingReportData = !_.isEmpty(reports); + return getCollection(ONYXKEYS.COLLECTION.POLICY); + }) + .then((policies) => { API.read( 'OpenApp', {policyIDList: getNonOptimisticPolicyIDs(policies)}, @@ -176,9 +209,8 @@ function openApp() { ], }, ); - }, - }); - }); + }) + ); } /** From ec5a7962c0f68fe415738206c10e93622c37a450 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 13 Jun 2023 15:15:46 -1000 Subject: [PATCH 07/22] no app changes --- src/libs/actions/App.js | 58 +++++++---------------------------------- 1 file changed, 10 insertions(+), 48 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 556c7696eea7..eccf2623f7f5 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -15,7 +15,6 @@ import ROUTES from '../../ROUTES'; import * as SessionUtils from '../SessionUtils'; import getCurrentUrl from '../Navigation/currentUrl'; import * as Session from './Session'; -import * as ReportActionsUtils from '../ReportActionsUtils'; let currentUserAccountID; let currentUserEmail; @@ -138,50 +137,17 @@ AppState.addEventListener('change', (nextAppState) => { appState = nextAppState; }); -function getPolicies() { - return new Promise((resolve) => { +/** + * Fetches data needed for app initialization + */ +function openApp() { + isReadyToOpenApp.then(() => { + // We need a fresh connection/callback here to make sure that the list of policyIDs that is sent to OpenApp is the most updated list from Onyx const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY, waitForCollectionCallback: true, callback: (policies) => { Onyx.disconnect(connectionID); - resolve(policies); - }, - }); - }); -} -function getCollection(key) { - return new Promise((resolve) => { - const connectionID = Onyx.connect({ - key, - waitForCollectionCallback: true, - callback: (reports) => { - Onyx.disconnect(connectionID); - resolve(reports); - }, - }); - }); -} - -function getReports() { -} - -/** - * Fetches data needed for app initialization - */ -function openApp() { - let hasExistingReportData = false; - isReadyToOpenApp.then(() => - // If we are opening the app after a first sign in then we will have no data whatsoever. This is easily checked by looking to see if - // the user has any report data at all. All users should have at least one report with Concierge so this is a reliable way to check if - // we are signing in the first time or if the app is being opened after it was killed or the page refreshed. - getCollection(ONYXKEYS.COLLECTION.REPORT) - .then((reports) => { - console.log({reports}); - hasExistingReportData = !_.isEmpty(reports); - return getCollection(ONYXKEYS.COLLECTION.POLICY); - }) - .then((policies) => { API.read( 'OpenApp', {policyIDList: getNonOptimisticPolicyIDs(policies)}, @@ -209,22 +175,18 @@ function openApp() { ], }, ); - }) - ); + }, + }); + }); } /** * Refreshes data when the app reconnects */ function reconnectApp() { - // When the app reconnects we do a fast "sync" of the LHN and only return chats that have new messages. We achieve this by sending the most recent reportActionID - // we have locally. And then only update the user about chats with messages that have occurred after that reportActionID. - // - // - Look through the local report actions to find the most recently modified report action - // - We Send this to the server so that it can compute which chats are critical for the user to see so we can update them in the LHN API.write( CONST.NETWORK.COMMAND.RECONNECT_APP, - {policyIDList: getNonOptimisticPolicyIDs(allPolicies), mostRecentReportActionLastModified: ReportActionsUtils.getMostRecentReportActionLastModified()}, + {policyIDList: getNonOptimisticPolicyIDs(allPolicies)}, { optimisticData: [ { From 79feeef15079076e609314cc1d0a8c1a002b1cb5 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 13 Jun 2023 15:16:50 -1000 Subject: [PATCH 08/22] Revert "no app changes" This reverts commit ec5a7962c0f68fe415738206c10e93622c37a450. --- src/libs/actions/App.js | 58 ++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index eccf2623f7f5..556c7696eea7 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -15,6 +15,7 @@ import ROUTES from '../../ROUTES'; import * as SessionUtils from '../SessionUtils'; import getCurrentUrl from '../Navigation/currentUrl'; import * as Session from './Session'; +import * as ReportActionsUtils from '../ReportActionsUtils'; let currentUserAccountID; let currentUserEmail; @@ -137,17 +138,50 @@ AppState.addEventListener('change', (nextAppState) => { appState = nextAppState; }); -/** - * Fetches data needed for app initialization - */ -function openApp() { - isReadyToOpenApp.then(() => { - // We need a fresh connection/callback here to make sure that the list of policyIDs that is sent to OpenApp is the most updated list from Onyx +function getPolicies() { + return new Promise((resolve) => { const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY, waitForCollectionCallback: true, callback: (policies) => { Onyx.disconnect(connectionID); + resolve(policies); + }, + }); + }); +} +function getCollection(key) { + return new Promise((resolve) => { + const connectionID = Onyx.connect({ + key, + waitForCollectionCallback: true, + callback: (reports) => { + Onyx.disconnect(connectionID); + resolve(reports); + }, + }); + }); +} + +function getReports() { +} + +/** + * Fetches data needed for app initialization + */ +function openApp() { + let hasExistingReportData = false; + isReadyToOpenApp.then(() => + // If we are opening the app after a first sign in then we will have no data whatsoever. This is easily checked by looking to see if + // the user has any report data at all. All users should have at least one report with Concierge so this is a reliable way to check if + // we are signing in the first time or if the app is being opened after it was killed or the page refreshed. + getCollection(ONYXKEYS.COLLECTION.REPORT) + .then((reports) => { + console.log({reports}); + hasExistingReportData = !_.isEmpty(reports); + return getCollection(ONYXKEYS.COLLECTION.POLICY); + }) + .then((policies) => { API.read( 'OpenApp', {policyIDList: getNonOptimisticPolicyIDs(policies)}, @@ -175,18 +209,22 @@ function openApp() { ], }, ); - }, - }); - }); + }) + ); } /** * Refreshes data when the app reconnects */ function reconnectApp() { + // When the app reconnects we do a fast "sync" of the LHN and only return chats that have new messages. We achieve this by sending the most recent reportActionID + // we have locally. And then only update the user about chats with messages that have occurred after that reportActionID. + // + // - Look through the local report actions to find the most recently modified report action + // - We Send this to the server so that it can compute which chats are critical for the user to see so we can update them in the LHN API.write( CONST.NETWORK.COMMAND.RECONNECT_APP, - {policyIDList: getNonOptimisticPolicyIDs(allPolicies)}, + {policyIDList: getNonOptimisticPolicyIDs(allPolicies), mostRecentReportActionLastModified: ReportActionsUtils.getMostRecentReportActionLastModified()}, { optimisticData: [ { From e1ddfc22cb6da1dbe99415d68b5a0b07b8536cdf Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 13 Jun 2023 15:19:25 -1000 Subject: [PATCH 09/22] revert stuff --- src/libs/actions/App.js | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 556c7696eea7..a07087379ab3 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -150,38 +150,17 @@ function getPolicies() { }); }); } -function getCollection(key) { - return new Promise((resolve) => { - const connectionID = Onyx.connect({ - key, - waitForCollectionCallback: true, - callback: (reports) => { - Onyx.disconnect(connectionID); - resolve(reports); - }, - }); - }); -} - -function getReports() { -} /** * Fetches data needed for app initialization */ function openApp() { - let hasExistingReportData = false; - isReadyToOpenApp.then(() => - // If we are opening the app after a first sign in then we will have no data whatsoever. This is easily checked by looking to see if - // the user has any report data at all. All users should have at least one report with Concierge so this is a reliable way to check if - // we are signing in the first time or if the app is being opened after it was killed or the page refreshed. - getCollection(ONYXKEYS.COLLECTION.REPORT) - .then((reports) => { - console.log({reports}); - hasExistingReportData = !_.isEmpty(reports); - return getCollection(ONYXKEYS.COLLECTION.POLICY); - }) - .then((policies) => { + isReadyToOpenApp.then(() => { + const connectionID = Onyx.connect({ + key: ONYXKEYS.POLICY, + waitForCollectionCallback: true, + callback: (policies) => { + Onyx.disconnect(connectionID); API.read( 'OpenApp', {policyIDList: getNonOptimisticPolicyIDs(policies)}, @@ -209,8 +188,9 @@ function openApp() { ], }, ); - }) - ); + }, + }); + }); } /** From 2ac3528f15c86b1a6531a1e902f09e0a5c29b715 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 13 Jun 2023 15:19:44 -1000 Subject: [PATCH 10/22] revert more stuff --- src/libs/actions/App.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index a07087379ab3..e20188cabbe5 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -138,19 +138,6 @@ AppState.addEventListener('change', (nextAppState) => { appState = nextAppState; }); -function getPolicies() { - return new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY, - waitForCollectionCallback: true, - callback: (policies) => { - Onyx.disconnect(connectionID); - resolve(policies); - }, - }); - }); -} - /** * Fetches data needed for app initialization */ From 6adf6de408d27e415ae924f638c52c962333ed2a Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 13 Jun 2023 15:20:07 -1000 Subject: [PATCH 11/22] More --- src/libs/actions/App.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index e20188cabbe5..308c01e3da6a 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -143,8 +143,9 @@ AppState.addEventListener('change', (nextAppState) => { */ function openApp() { isReadyToOpenApp.then(() => { + // We need a fresh connection/callback here to make sure that the list of policyIDs that is sent to OpenApp is the most updated list from Onyx const connectionID = Onyx.connect({ - key: ONYXKEYS.POLICY, + key: ONYXKEYS.COLLECTION.POLICY, waitForCollectionCallback: true, callback: (policies) => { Onyx.disconnect(connectionID); From 4df46787b6c44d16929c626fe1a6011b4a05ee2e Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Thu, 15 Jun 2023 07:03:14 -1000 Subject: [PATCH 12/22] account for possible undefined report value --- src/libs/ReportActionsUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 992c751889c7..9de23c6bd61c 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -451,7 +451,7 @@ function getMostRecentReportActionLastModified() { // any reports that have been updated before either a recently updated report or reportAction as we should be up to date on these _.each(allReports, (report) => { const reportLastVisibleActionLastModified = report.lastVisibleActionLastModified || report.lastVisibleActionCreated; - if (reportLastVisibleActionLastModified < mostRecentReportActionLastModified) { + if (!reportLastVisibleActionLastModified || reportLastVisibleActionLastModified < mostRecentReportActionLastModified) { return; } From 112b97dc19462b79bad54c4ebc29a82aa6480f33 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 16 Jun 2023 08:19:42 -1000 Subject: [PATCH 13/22] update comment --- src/libs/actions/App.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 308c01e3da6a..294ee71fc1b5 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -185,11 +185,11 @@ function openApp() { * Refreshes data when the app reconnects */ function reconnectApp() { - // When the app reconnects we do a fast "sync" of the LHN and only return chats that have new messages. We achieve this by sending the most recent reportActionID + // When the app reconnects we do a fast "sync" of the LHN and only return chats that have new messages. We achieve this by sending the most recent reportActionID. // we have locally. And then only update the user about chats with messages that have occurred after that reportActionID. // - // - Look through the local report actions to find the most recently modified report action - // - We Send this to the server so that it can compute which chats are critical for the user to see so we can update them in the LHN + // - Look through the local report actions and reports to find the most recently modified report action or report. + // - We send this to the server so that it can compute which chats are critical for the user to see and return only those as an optimization. API.write( CONST.NETWORK.COMMAND.RECONNECT_APP, {policyIDList: getNonOptimisticPolicyIDs(allPolicies), mostRecentReportActionLastModified: ReportActionsUtils.getMostRecentReportActionLastModified()}, From a88a3cb92d6b2dff436f1fa53d906c85af0aadf2 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 16 Jun 2023 10:48:04 -1000 Subject: [PATCH 14/22] Revert problem code --- src/CONST.js | 3 - src/libs/HttpUtils.js | 22 +----- .../Navigation/AppNavigator/AuthScreens.js | 10 ++- src/libs/SessionUtils.js | 33 ++++++++- src/libs/actions/App.js | 73 +++++++++++-------- src/libs/actions/PersistedRequests.js | 9 +-- src/libs/actions/SignInRedirect.js | 2 + 7 files changed, 88 insertions(+), 64 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 50bfb5675bd8..8b954a010da6 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -724,9 +724,6 @@ const CONST = { MAX_RETRY_WAIT_TIME_MS: 10 * 1000, PROCESS_REQUEST_DELAY_MS: 1000, MAX_PENDING_TIME_MS: 10 * 1000, - COMMAND: { - RECONNECT_APP: 'ReconnectApp', - }, }, DEFAULT_TIME_ZONE: {automatic: true, selected: 'America/Los_Angeles'}, DEFAULT_ACCOUNT_DATA: {errors: null, success: '', isLoading: false}, diff --git a/src/libs/HttpUtils.js b/src/libs/HttpUtils.js index e76517e2059f..5a8185a03038 100644 --- a/src/libs/HttpUtils.js +++ b/src/libs/HttpUtils.js @@ -22,9 +22,6 @@ Onyx.connect({ // We use the AbortController API to terminate pending request in `cancelPendingRequests` let cancellationController = new AbortController(); -// To terminate pending ReconnectApp requests https://github.com/Expensify/App/issues/15627 -let reconnectAppCancellationController = new AbortController(); - /** * Send an HTTP request, and attempt to resolve the json response. * If there is a network error, we'll set the application offline. @@ -33,18 +30,12 @@ let reconnectAppCancellationController = new AbortController(); * @param {String} [method] * @param {Object} [body] * @param {Boolean} [canCancel] - * @param {String} [command] * @returns {Promise} */ -function processHTTPRequest(url, method = 'get', body = null, canCancel = true, command = '') { - let signal; - if (canCancel) { - signal = command === CONST.NETWORK.COMMAND.RECONNECT_APP ? reconnectAppCancellationController.signal : cancellationController.signal; - } - +function processHTTPRequest(url, method = 'get', body = null, canCancel = true) { return fetch(url, { // We hook requests to the same Controller signal, so we can cancel them all at once - signal, + signal: canCancel ? cancellationController.signal : undefined, method, body, }) @@ -136,12 +127,7 @@ function xhr(command, data, type = CONST.NETWORK.METHOD.POST, shouldUseSecure = }); const url = ApiUtils.getCommandURL({shouldUseSecure, command}); - return processHTTPRequest(url, type, formData, data.canCancel, command); -} - -function cancelPendingReconnectAppRequest() { - reconnectAppCancellationController.abort(); - reconnectAppCancellationController = new AbortController(); + return processHTTPRequest(url, type, formData, data.canCancel); } function cancelPendingRequests() { @@ -150,11 +136,9 @@ function cancelPendingRequests() { // We create a new instance because once `abort()` is called any future requests using the same controller would // automatically get rejected: https://dom.spec.whatwg.org/#abortcontroller-api-integration cancellationController = new AbortController(); - cancelPendingReconnectAppRequest(); } export default { xhr, cancelPendingRequests, - cancelPendingReconnectAppRequest, }; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index fb02a811b0ec..182e1cca4a65 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -32,6 +32,7 @@ import CentralPaneNavigator from './Navigators/CentralPaneNavigator'; import NAVIGATORS from '../../../NAVIGATORS'; import FullScreenNavigator from './Navigators/FullScreenNavigator'; import styles from '../../../styles/styles'; +import * as SessionUtils from '../../SessionUtils'; let currentUserEmail; Onyx.connect({ @@ -119,7 +120,14 @@ class AuthScreens extends React.Component { User.subscribeToUserEvents(); }); - App.openApp(); + // If we are on this screen then we are "logged in", but the user might not have "just logged in". They could be reopening the app + // or returning from background. If so, we'll assume they have some app data already and we can call reconnectApp() instead of openApp(). + if (SessionUtils.didUserLogInDuringSession()) { + App.openApp(); + } else { + App.reconnectApp(); + } + App.setUpPoliciesAndNavigate(this.props.session); if (this.props.lastOpenedPublicRoomID) { diff --git a/src/libs/SessionUtils.js b/src/libs/SessionUtils.js index 875b540e5599..4d4d4b7658b9 100644 --- a/src/libs/SessionUtils.js +++ b/src/libs/SessionUtils.js @@ -1,4 +1,7 @@ +import Onyx from 'react-native-onyx'; +import _ from 'underscore'; import lodashGet from 'lodash/get'; +import ONYXKEYS from '../ONYXKEYS'; /** * Determine if the transitioning user is logging in as a new user. @@ -28,7 +31,35 @@ function isLoggingInAsNewUser(transitionURL, sessionEmail) { return linkedEmail !== sessionEmail; } +let loggedInDuringSession; + +// To tell if the user logged in during this session we will check the value of session.authToken once when the app's JS inits. When the user logs out +// we can reset this flag so that it can be updated again. +Onyx.connect({ + key: ONYXKEYS.SESSION, + callback: (session) => { + if (!_.isUndefined(loggedInDuringSession)) { + return; + } + + if (session && session.authToken) { + loggedInDuringSession = false; + } else { + loggedInDuringSession = true; + } + }, +}); + +function resetDidUserLogInDuringSession() { + loggedInDuringSession = undefined; +} + +function didUserLogInDuringSession() { + return Boolean(loggedInDuringSession); +} + export { - // eslint-disable-next-line import/prefer-default-export isLoggingInAsNewUser, + didUserLogInDuringSession, + resetDidUserLogInDuringSession, }; diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 821e7f13a254..d01ebd25aebb 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -183,38 +183,47 @@ function openApp() { * Refreshes data when the app reconnects */ function reconnectApp() { - // When the app reconnects we do a fast "sync" of the LHN and only return chats that have new messages. We achieve this by sending the most recent reportActionID. - // we have locally. And then only update the user about chats with messages that have occurred after that reportActionID. - // - // - Look through the local report actions and reports to find the most recently modified report action or report. - // - We send this to the server so that it can compute which chats are critical for the user to see and return only those as an optimization. - API.write( - CONST.NETWORK.COMMAND.RECONNECT_APP, - {policyIDList: getNonOptimisticPolicyIDs(allPolicies), mostRecentReportActionLastModified: ReportActionsUtils.getMostRecentReportActionLastModified()}, - { - optimisticData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.IS_LOADING_REPORT_DATA, - value: true, - }, - ], - successData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.IS_LOADING_REPORT_DATA, - value: false, - }, - ], - failureData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.IS_LOADING_REPORT_DATA, - value: false, - }, - ], - }, - ); + isReadyToOpenApp.then(() => { + const connectionID = Onyx.connect({ + key: ONYXKEYS.COLLECTION.POLICY, + waitForCollectionCallback: true, + callback: (policies) => { + Onyx.disconnect(connectionID); + // When the app reconnects we do a fast "sync" of the LHN and only return chats that have new messages. We achieve this by sending the most recent reportActionID. + // we have locally. And then only update the user about chats with messages that have occurred after that reportActionID. + // + // - Look through the local report actions and reports to find the most recently modified report action or report. + // - We send this to the server so that it can compute which chats are critical for the user to see and return only those as an optimization. + API.write( + 'ReconnectApp', + {policyIDList: getNonOptimisticPolicyIDs(policies), mostRecentReportActionLastModified: ReportActionsUtils.getMostRecentReportActionLastModified()}, + { + optimisticData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.IS_LOADING_REPORT_DATA, + value: true, + }, + ], + successData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.IS_LOADING_REPORT_DATA, + value: false, + }, + ], + failureData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.IS_LOADING_REPORT_DATA, + value: false, + }, + ], + }, + ); + }, + }); + }); } /** diff --git a/src/libs/actions/PersistedRequests.js b/src/libs/actions/PersistedRequests.js index e3aafd18c35d..d893ee255287 100644 --- a/src/libs/actions/PersistedRequests.js +++ b/src/libs/actions/PersistedRequests.js @@ -1,8 +1,6 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; -import CONST from '../../CONST'; import ONYXKEYS from '../../ONYXKEYS'; -import HttpUtils from '../HttpUtils'; let persistedRequests = []; @@ -19,12 +17,7 @@ function clear() { * @param {Array} requestsToPersist */ function save(requestsToPersist) { - HttpUtils.cancelPendingReconnectAppRequest(); - persistedRequests = _.chain(persistedRequests) - .concat(requestsToPersist) - .partition((request) => request.command !== CONST.NETWORK.COMMAND.RECONNECT_APP) - .flatten() - .value(); + persistedRequests = persistedRequests.concat(requestsToPersist); Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, persistedRequests); } diff --git a/src/libs/actions/SignInRedirect.js b/src/libs/actions/SignInRedirect.js index a500635222d6..a010621c4eea 100644 --- a/src/libs/actions/SignInRedirect.js +++ b/src/libs/actions/SignInRedirect.js @@ -10,6 +10,7 @@ import navigationRef from '../Navigation/navigationRef'; import SCREENS from '../../SCREENS'; import Navigation from '../Navigation/Navigation'; import * as ErrorUtils from '../ErrorUtils'; +import * as SessionUtils from '../SessionUtils'; let currentIsOffline; let currentShouldForceOffline; @@ -87,6 +88,7 @@ function redirectToSignIn(errorMessage) { NetworkConnection.clearReconnectionCallbacks(); clearStorageAndRedirect(errorMessage); resetHomeRouteParams(); + SessionUtils.resetDidUserLogInDuringSession(); } export default redirectToSignIn; From c0583f8ca6ba077fbc1bf2eb0f4093ee652ffa3d Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 16 Jun 2023 11:02:54 -1000 Subject: [PATCH 15/22] DRY up openApp/reconnectApp method --- src/libs/actions/App.js | 71 +++++++++++------------------------------ 1 file changed, 18 insertions(+), 53 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index d01ebd25aebb..5d23fddd9654 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -44,13 +44,6 @@ Onyx.connect({ }, }); -let allPolicies = []; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY, - waitForCollectionCallback: true, - callback: (policies) => (allPolicies = policies), -}); - let preferredLocale; Onyx.connect({ key: ONYXKEYS.NVP_PREFERRED_LOCALE, @@ -138,18 +131,30 @@ AppState.addEventListener('change', (nextAppState) => { /** * Fetches data needed for app initialization + * @param {boolean} [isReconnecting] */ -function openApp() { +function openApp(isReconnecting = false) { isReadyToOpenApp.then(() => { - // We need a fresh connection/callback here to make sure that the list of policyIDs that is sent to OpenApp is the most updated list from Onyx const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY, waitForCollectionCallback: true, callback: (policies) => { + // When the app reconnects we do a fast "sync" of the LHN and only return chats that have new messages. We achieve this by sending the most recent reportActionID. + // we have locally. And then only update the user about chats with messages that have occurred after that reportActionID. + // + // - Look through the local report actions and reports to find the most recently modified report action or report. + // - We send this to the server so that it can compute which chats are critical for the user to see and return only those as an optimization. + const params = {policyIDList: getNonOptimisticPolicyIDs(policies)}; + if (isReconnecting) { + params.mostRecentReportActionLastModified = ReportActionsUtils.getMostRecentReportActionLastModified(); + } Onyx.disconnect(connectionID); - API.read( - 'OpenApp', - {policyIDList: getNonOptimisticPolicyIDs(policies)}, + + // eslint-disable-next-line rulesdir/no-multiple-api-calls + const apiMethod = isReconnecting ? API.write : API.read; + apiMethod( + isReconnecting ? 'ReconnectApp' : 'OpenApp', + params, { optimisticData: [ { @@ -183,47 +188,7 @@ function openApp() { * Refreshes data when the app reconnects */ function reconnectApp() { - isReadyToOpenApp.then(() => { - const connectionID = Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY, - waitForCollectionCallback: true, - callback: (policies) => { - Onyx.disconnect(connectionID); - // When the app reconnects we do a fast "sync" of the LHN and only return chats that have new messages. We achieve this by sending the most recent reportActionID. - // we have locally. And then only update the user about chats with messages that have occurred after that reportActionID. - // - // - Look through the local report actions and reports to find the most recently modified report action or report. - // - We send this to the server so that it can compute which chats are critical for the user to see and return only those as an optimization. - API.write( - 'ReconnectApp', - {policyIDList: getNonOptimisticPolicyIDs(policies), mostRecentReportActionLastModified: ReportActionsUtils.getMostRecentReportActionLastModified()}, - { - optimisticData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.IS_LOADING_REPORT_DATA, - value: true, - }, - ], - successData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.IS_LOADING_REPORT_DATA, - value: false, - }, - ], - failureData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.IS_LOADING_REPORT_DATA, - value: false, - }, - ], - }, - ); - }, - }); - }); + openApp(true); } /** From 0942351991c4328d8731995eaf96752658b9c9ae Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 16 Jun 2023 11:09:46 -1000 Subject: [PATCH 16/22] run prettier add js doc --- src/libs/SessionUtils.js | 9 ++++---- src/libs/actions/App.js | 50 ++++++++++++++++++---------------------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/libs/SessionUtils.js b/src/libs/SessionUtils.js index 4d4d4b7658b9..7b1fc9f42d25 100644 --- a/src/libs/SessionUtils.js +++ b/src/libs/SessionUtils.js @@ -54,12 +54,11 @@ function resetDidUserLogInDuringSession() { loggedInDuringSession = undefined; } +/** + * @returns {boolean} + */ function didUserLogInDuringSession() { return Boolean(loggedInDuringSession); } -export { - isLoggingInAsNewUser, - didUserLogInDuringSession, - resetDidUserLogInDuringSession, -}; +export {isLoggingInAsNewUser, didUserLogInDuringSession, resetDidUserLogInDuringSession}; diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 5d23fddd9654..6053bbb81a98 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -152,33 +152,29 @@ function openApp(isReconnecting = false) { // eslint-disable-next-line rulesdir/no-multiple-api-calls const apiMethod = isReconnecting ? API.write : API.read; - apiMethod( - isReconnecting ? 'ReconnectApp' : 'OpenApp', - params, - { - optimisticData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.IS_LOADING_REPORT_DATA, - value: true, - }, - ], - successData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.IS_LOADING_REPORT_DATA, - value: false, - }, - ], - failureData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.IS_LOADING_REPORT_DATA, - value: false, - }, - ], - }, - ); + apiMethod(isReconnecting ? 'ReconnectApp' : 'OpenApp', params, { + optimisticData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.IS_LOADING_REPORT_DATA, + value: true, + }, + ], + successData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.IS_LOADING_REPORT_DATA, + value: false, + }, + ], + failureData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.IS_LOADING_REPORT_DATA, + value: false, + }, + ], + }); }, }); }); From daf4e6f7b976383692eaf4d758b08b615d23aed9 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 20 Jun 2023 13:54:37 -1000 Subject: [PATCH 17/22] Log an alert if we exceed max execution time --- src/CONST.js | 1 + src/libs/ReportActionsUtils.js | 4 ++++ src/libs/actions/Timing.js | 8 +++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/CONST.js b/src/CONST.js index 8b954a010da6..e158f8efe38c 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -652,6 +652,7 @@ const CONST = { }, }, TIMING: { + CALCULATE_MOST_RECENT_LAST_MODIFIED_ACTION: 'calc_most_recent_last_modified_action', SEARCH_RENDER: 'search_render', HOMEPAGE_INITIAL_RENDER: 'homepage_initial_render', REPORT_INITIAL_RENDER: 'report_initial_render', diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 3b9bf2ce79e0..16855ef799e9 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -10,6 +10,7 @@ import ONYXKEYS from '../ONYXKEYS'; import Log from './Log'; import * as CurrencyUtils from './CurrencyUtils'; import isReportMessageAttachment from './isReportMessageAttachment'; +import Timing from './actions/Timing'; const allReports = {}; Onyx.connect({ @@ -426,6 +427,8 @@ function getLinkedTransactionID(reportID, reportActionID) { * @returns {string} */ function getMostRecentReportActionLastModified() { + Timing.start(CONST.TIMING.CALCULATE_MOST_RECENT_LAST_MODIFIED_ACTION); + // Start with the oldest date possible let mostRecentReportActionLastModified = new Date(0).toISOString(); @@ -462,6 +465,7 @@ function getMostRecentReportActionLastModified() { mostRecentReportActionLastModified = reportLastVisibleActionLastModified; }); + Timing.end(CONST.TIMING.CALCULATE_MOST_RECENT_LAST_MODIFIED_ACTION, 500); return mostRecentReportActionLastModified; } diff --git a/src/libs/actions/Timing.js b/src/libs/actions/Timing.js index 0f6a67d0879e..928cac51d960 100644 --- a/src/libs/actions/Timing.js +++ b/src/libs/actions/Timing.js @@ -2,6 +2,7 @@ import getPlatform from '../getPlatform'; import * as Environment from '../Environment/Environment'; import Firebase from '../Firebase'; import * as API from '../API'; +import Log from '../Log'; let timestampData = {}; @@ -26,8 +27,9 @@ function start(eventName, shouldUseFirebase = false) { * * @param {String} eventName - event name used as timestamp key * @param {String} [secondaryName] - optional secondary event name, passed to grafana + * @param {number} [maxExecutionTime] - optional amount of time to wait before logging an alert */ -function end(eventName, secondaryName = '') { +function end(eventName, secondaryName = '', maxExecutionTime = 0) { if (!timestampData[eventName]) { return; } @@ -51,6 +53,10 @@ function end(eventName, secondaryName = '') { return; } + if (maxExecutionTime && eventTime > maxExecutionTime) { + Log.alert(`${eventName} exceeded max execution time of ${maxExecutionTime}.`, {eventTime, eventName}); + } + API.write('SendPerformanceTiming', { name: grafanaEventName, value: eventTime, From 87b1c91be49007ac953291521fa0537eb7fd51a7 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 27 Jun 2023 10:49:42 -1000 Subject: [PATCH 18/22] Apply suggested feedback --- src/libs/ReportActionsUtils.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 39f7e9f5530a..506a4d457764 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -442,11 +442,7 @@ function getMostRecentReportActionLastModified() { return; } - let lastModified = action.lastModified; - if (!lastModified) { - lastModified = action.created; - } - + const lastModified = action.lastModified || action.created; if (lastModified < mostRecentReportActionLastModified) { return; } From c256bb419a7fad10b1f7985c191074f59147bc5d Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 27 Jun 2023 13:21:01 -1000 Subject: [PATCH 19/22] Fix --- src/libs/ReportActionsUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 506a4d457764..ca1996e8a764 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -461,7 +461,7 @@ function getMostRecentReportActionLastModified() { mostRecentReportActionLastModified = reportLastVisibleActionLastModified; }); - Timing.end(CONST.TIMING.CALCULATE_MOST_RECENT_LAST_MODIFIED_ACTION, 500); + Timing.end(CONST.TIMING.CALCULATE_MOST_RECENT_LAST_MODIFIED_ACTION, '', 500); return mostRecentReportActionLastModified; } From 0a83f503eff6d46d2f065b888cd80d717a62b7f8 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 27 Jun 2023 13:32:21 -1000 Subject: [PATCH 20/22] Fix dependency cycle --- src/libs/ReportActionsUtils.js | 4 ---- src/libs/actions/App.js | 3 +++ src/libs/actions/Timing.js | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index ca1996e8a764..d873e9a82c5a 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -10,7 +10,6 @@ import ONYXKEYS from '../ONYXKEYS'; import Log from './Log'; import * as CurrencyUtils from './CurrencyUtils'; import isReportMessageAttachment from './isReportMessageAttachment'; -import Timing from './actions/Timing'; const allReports = {}; Onyx.connect({ @@ -427,8 +426,6 @@ function getLinkedTransactionID(reportID, reportActionID) { * @returns {string} */ function getMostRecentReportActionLastModified() { - Timing.start(CONST.TIMING.CALCULATE_MOST_RECENT_LAST_MODIFIED_ACTION); - // Start with the oldest date possible let mostRecentReportActionLastModified = new Date(0).toISOString(); @@ -461,7 +458,6 @@ function getMostRecentReportActionLastModified() { mostRecentReportActionLastModified = reportLastVisibleActionLastModified; }); - Timing.end(CONST.TIMING.CALCULATE_MOST_RECENT_LAST_MODIFIED_ACTION, '', 500); return mostRecentReportActionLastModified; } diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 6053bbb81a98..83d0f5469988 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -16,6 +16,7 @@ import * as SessionUtils from '../SessionUtils'; import getCurrentUrl from '../Navigation/currentUrl'; import * as Session from './Session'; import * as ReportActionsUtils from '../ReportActionsUtils'; +import Timing from './Timing'; let currentUserAccountID; Onyx.connect({ @@ -146,7 +147,9 @@ function openApp(isReconnecting = false) { // - We send this to the server so that it can compute which chats are critical for the user to see and return only those as an optimization. const params = {policyIDList: getNonOptimisticPolicyIDs(policies)}; if (isReconnecting) { + Timing.start(CONST.TIMING.CALCULATE_MOST_RECENT_LAST_MODIFIED_ACTION); params.mostRecentReportActionLastModified = ReportActionsUtils.getMostRecentReportActionLastModified(); + Timing.end(CONST.TIMING.CALCULATE_MOST_RECENT_LAST_MODIFIED_ACTION, '', 500); } Onyx.disconnect(connectionID); diff --git a/src/libs/actions/Timing.js b/src/libs/actions/Timing.js index 30fd8353ad40..e0cfbc3031d4 100644 --- a/src/libs/actions/Timing.js +++ b/src/libs/actions/Timing.js @@ -1,7 +1,6 @@ import getPlatform from '../getPlatform'; import * as Environment from '../Environment/Environment'; import Firebase from '../Firebase'; -// eslint-disable-next-line import/no-cycle import * as API from '../API'; import Log from '../Log'; From 76f76ade3dede805b204558506afbbcca98a4212 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 28 Jun 2023 10:19:37 -1000 Subject: [PATCH 21/22] Make requested changes --- src/libs/actions/App.js | 2 +- src/libs/actions/Timing.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 83d0f5469988..56cf911b9848 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -144,7 +144,7 @@ function openApp(isReconnecting = false) { // we have locally. And then only update the user about chats with messages that have occurred after that reportActionID. // // - Look through the local report actions and reports to find the most recently modified report action or report. - // - We send this to the server so that it can compute which chats are critical for the user to see and return only those as an optimization. + // - We send this to the server so that it can compute which new chats the user needs to see and return only those as an optimization. const params = {policyIDList: getNonOptimisticPolicyIDs(policies)}; if (isReconnecting) { Timing.start(CONST.TIMING.CALCULATE_MOST_RECENT_LAST_MODIFIED_ACTION); diff --git a/src/libs/actions/Timing.js b/src/libs/actions/Timing.js index e0cfbc3031d4..2be2cdc6fa63 100644 --- a/src/libs/actions/Timing.js +++ b/src/libs/actions/Timing.js @@ -27,7 +27,7 @@ function start(eventName, shouldUseFirebase = false) { * * @param {String} eventName - event name used as timestamp key * @param {String} [secondaryName] - optional secondary event name, passed to grafana - * @param {number} [maxExecutionTime] - optional amount of time to wait before logging an alert + * @param {number} [maxExecutionTime] - optional amount of time (ms) to wait before logging a warn */ function end(eventName, secondaryName = '', maxExecutionTime = 0) { if (!timestampData[eventName]) { @@ -54,7 +54,7 @@ function end(eventName, secondaryName = '', maxExecutionTime = 0) { } if (maxExecutionTime && eventTime > maxExecutionTime) { - Log.alert(`${eventName} exceeded max execution time of ${maxExecutionTime}.`, {eventTime, eventName}); + Log.warn(`${eventName} exceeded max execution time of ${maxExecutionTime}.`, {eventTime, eventName}); } API.read( From 2341952673f7237037b7b5f28ddb7480a7d98348 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 3 Jul 2023 13:02:16 -1000 Subject: [PATCH 22/22] prettier --- src/libs/ReportActionsUtils.js | 66 +++++++++++++++++----------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index 376eb2273b55..86096b300c12 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -457,39 +457,39 @@ function getReportAction(reportID, reportActionID) { * @returns {string} */ function getMostRecentReportActionLastModified() { - // Start with the oldest date possible - let mostRecentReportActionLastModified = new Date(0).toISOString(); - - // Flatten all the actions - // Loop over them all to find the one that is the most recent - const flatReportActions = _.flatten(_.map(allReportActions, (actions) => _.values(actions))); - _.each(flatReportActions, (action) => { - // Pending actions should not be counted here as a user could create a comment or some other action while offline and the server might know about - // messages they have not seen yet. - if (!_.isEmpty(action.pendingAction)) { - return; - } - - const lastModified = action.lastModified || action.created; - if (lastModified < mostRecentReportActionLastModified) { - return; - } - - mostRecentReportActionLastModified = lastModified; - }); - - // We might not have actions so we also look at the report objects to see if any have a lastVisibleActionLastModified that is more recent. We don't need to get - // any reports that have been updated before either a recently updated report or reportAction as we should be up to date on these - _.each(allReports, (report) => { - const reportLastVisibleActionLastModified = report.lastVisibleActionLastModified || report.lastVisibleActionCreated; - if (!reportLastVisibleActionLastModified || reportLastVisibleActionLastModified < mostRecentReportActionLastModified) { - return; - } - - mostRecentReportActionLastModified = reportLastVisibleActionLastModified; - }); - - return mostRecentReportActionLastModified; + // Start with the oldest date possible + let mostRecentReportActionLastModified = new Date(0).toISOString(); + + // Flatten all the actions + // Loop over them all to find the one that is the most recent + const flatReportActions = _.flatten(_.map(allReportActions, (actions) => _.values(actions))); + _.each(flatReportActions, (action) => { + // Pending actions should not be counted here as a user could create a comment or some other action while offline and the server might know about + // messages they have not seen yet. + if (!_.isEmpty(action.pendingAction)) { + return; + } + + const lastModified = action.lastModified || action.created; + if (lastModified < mostRecentReportActionLastModified) { + return; + } + + mostRecentReportActionLastModified = lastModified; + }); + + // We might not have actions so we also look at the report objects to see if any have a lastVisibleActionLastModified that is more recent. We don't need to get + // any reports that have been updated before either a recently updated report or reportAction as we should be up to date on these + _.each(allReports, (report) => { + const reportLastVisibleActionLastModified = report.lastVisibleActionLastModified || report.lastVisibleActionCreated; + if (!reportLastVisibleActionLastModified || reportLastVisibleActionLastModified < mostRecentReportActionLastModified) { + return; + } + + mostRecentReportActionLastModified = reportLastVisibleActionLastModified; + }); + + return mostRecentReportActionLastModified; } /**