From d69426ce0e0f38ffe19837746826a388ce9046bb Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 11 Aug 2023 15:25:57 -0600 Subject: [PATCH 001/101] Fix path to build Android correctly --- fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 60d60934c2ba..ec68c74472de 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,7 +17,7 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="#{Dir.pwd}/../src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="../src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" gradle( From 85f0d93e444f6437bff64eba4809c66ea7f2ea68 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 11 Aug 2023 15:31:03 -0600 Subject: [PATCH 002/101] Add `IS_MERGED` output --- .github/actions/javascript/getPullRequestDetails/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/javascript/getPullRequestDetails/action.yml b/.github/actions/javascript/getPullRequestDetails/action.yml index a59cf55bdf9f..6704d5220851 100644 --- a/.github/actions/javascript/getPullRequestDetails/action.yml +++ b/.github/actions/javascript/getPullRequestDetails/action.yml @@ -15,6 +15,8 @@ outputs: description: 'The merge_commit_sha of the given pull request' MERGE_ACTOR: description: 'The actor who merged the pull request' + IS_MERGED: + description: 'True if the pull request is merged' runs: using: 'node16' main: './index.js' From 45dd2b4e1b00bcea3ce29aa659874ea24f40c795 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 11 Aug 2023 15:35:14 -0600 Subject: [PATCH 003/101] Add two more missing outputs --- .github/actions/javascript/getPullRequestDetails/action.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/actions/javascript/getPullRequestDetails/action.yml b/.github/actions/javascript/getPullRequestDetails/action.yml index 6704d5220851..ed2c60f018a1 100644 --- a/.github/actions/javascript/getPullRequestDetails/action.yml +++ b/.github/actions/javascript/getPullRequestDetails/action.yml @@ -13,10 +13,14 @@ inputs: outputs: MERGE_COMMIT_SHA: description: 'The merge_commit_sha of the given pull request' + HEAD_COMMIT_SHA: + description: 'The head_commit_sha of the given pull request' MERGE_ACTOR: description: 'The actor who merged the pull request' IS_MERGED: description: 'True if the pull request is merged' + FORKED_REPO_URL: + description: 'Output forked repo URL if PR includes changes from a fork' runs: using: 'node16' main: './index.js' From 20c1e05b2a54b3b9d06124839ecb6c6833e3a7f5 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 11 Aug 2023 15:40:54 -0600 Subject: [PATCH 004/101] Temp comment out fork checkout --- .github/workflows/e2ePerformanceTests.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index fe364b376e3b..548f7e901667 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -81,12 +81,13 @@ jobs: - name: Unmerged PR - Fetch head ref of unmerged PR if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} run: | - if [[ ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} != '' ]]; then - git remote add pr_remote ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} - git fetch pr_remote ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 - else +# TODO: UNDO THIS +# if [[ ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} != '' ]]; then +# git remote add pr_remote ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} +# git fetch pr_remote ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 +# else git fetch origin ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 - fi +# fi - name: Unmerged PR - Set dummy git credentials before merging if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} From 0cd275462293f0ca4238545fbb8037cc40904e8d Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 11 Aug 2023 15:41:48 -0600 Subject: [PATCH 005/101] Another temporary fix --- .github/workflows/e2ePerformanceTests.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 548f7e901667..7888c8c47c25 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -81,13 +81,7 @@ jobs: - name: Unmerged PR - Fetch head ref of unmerged PR if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} run: | -# TODO: UNDO THIS -# if [[ ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} != '' ]]; then -# git remote add pr_remote ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} -# git fetch pr_remote ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 -# else git fetch origin ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 -# fi - name: Unmerged PR - Set dummy git credentials before merging if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} From f7f3a45a86728c1cccd49bde0407d05a1f7f1c31 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Tue, 15 Aug 2023 15:45:25 -0600 Subject: [PATCH 006/101] Tweak path --- fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index ec68c74472de..5dfccb4d93ec 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,7 +17,7 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="../src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="{Dir.pwd}/src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" gradle( From bd51745eb262a09b416b76c2cbc7f451c6edcedd Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Tue, 15 Aug 2023 16:23:32 -0600 Subject: [PATCH 007/101] Try fixing path yet again! --- fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 5dfccb4d93ec..cd11c5cf9e98 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,7 +17,7 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="{Dir.pwd}/src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" gradle( From 64e4effbd2c266308c09181007cd4d416c84f6e5 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Tue, 15 Aug 2023 16:52:54 -0600 Subject: [PATCH 008/101] Undo test commit --- .github/workflows/e2ePerformanceTests.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 7888c8c47c25..fe364b376e3b 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -81,7 +81,12 @@ jobs: - name: Unmerged PR - Fetch head ref of unmerged PR if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} run: | + if [[ ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} != '' ]]; then + git remote add pr_remote ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} + git fetch pr_remote ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 + else git fetch origin ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 + fi - name: Unmerged PR - Set dummy git credentials before merging if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} From 9debab5bceb6bb778ac7ed83589159096c05dc32 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Tue, 15 Aug 2023 17:14:28 -0600 Subject: [PATCH 009/101] Testing full flow --- .github/workflows/e2ePerformanceTests.yml | 60 +++-------------------- 1 file changed, 6 insertions(+), 54 deletions(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index fe364b376e3b..557af1a04786 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -16,42 +16,6 @@ on: required: true jobs: - buildBaseline: - runs-on: ubuntu-latest-xl - name: Build apk from latest release as a baseline - outputs: - VERSION: ${{ steps.getMostRecentRelease.outputs.VERSION }} - steps: - - uses: actions/checkout@v3 - - - name: Get most recent release version - id: getMostRecentRelease - run: echo "VERSION=$(gh release list --limit 1 | awk '{ print $1 }')" >> "$GITHUB_OUTPUT" - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Check if there's an existing artifact for this baseline - id: checkForExistingArtifact - uses: xSAVIKx/artifact-exists-action@3c5206b1411c0d2fc0840f56b7140646933d9d6a - with: - name: baseline-apk-${{ steps.getMostRecentRelease.outputs.VERSION }} - - - name: Skip build if there's already an existing artifact for the baseline - if: ${{ fromJSON(steps.checkForExistingArtifact.outputs.exists) }} - run: echo 'APK for baseline ${{ steps.getMostRecentRelease.outputs.VERSION }} already exists, reusing existing build' - - - name: Checkout "Baseline" commit (last release) - if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }} - run: | - git fetch origin tag ${{ steps.getMostRecentRelease.outputs.VERSION }} --no-tags --depth=1 - git switch --detach ${{ steps.getMostRecentRelease.outputs.VERSION }} - - - name: Build APK - if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }} - uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main - with: - ARTIFACT_NAME: baseline-apk-${{ steps.getMostRecentRelease.outputs.VERSION }} - buildDelta: runs-on: ubuntu-latest-xl name: Build apk from delta ref @@ -81,12 +45,7 @@ jobs: - name: Unmerged PR - Fetch head ref of unmerged PR if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} run: | - if [[ ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} != '' ]]; then - git remote add pr_remote ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} - git fetch pr_remote ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 - else git fetch origin ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 - fi - name: Unmerged PR - Set dummy git credentials before merging if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} @@ -119,7 +78,7 @@ jobs: runTestsInAWS: runs-on: ubuntu-latest - needs: [buildBaseline, buildDelta] + needs: [buildDelta] name: Run E2E tests in AWS device farm steps: - uses: actions/checkout@v3 @@ -127,25 +86,18 @@ jobs: - name: Make zip directory for everything to send to AWS Device Farm run: mkdir zip - - name: Download baseline APK - uses: actions/download-artifact@e9ef242655d12993efdcda9058dee2db83a2cb9b - id: downloadBaselineAPK - with: - name: baseline-apk-${{ needs.buildBaseline.outputs.VERSION }} - path: zip - - # The downloaded artifact will be a file named "app-e2eRelease.apk" so we have to rename it - - name: Rename baseline APK - run: mv "${{steps.downloadBaselineAPK.outputs.download-path}}/app-e2eRelease.apk" "${{steps.downloadBaselineAPK.outputs.download-path}}/app-e2eRelease-baseline.apk" - - name: Download delta APK uses: actions/download-artifact@e9ef242655d12993efdcda9058dee2db83a2cb9b + id: downloadDeltaAPK with: name: delta-apk-${{ needs.buildDelta.outputs.DELTA_REF }} path: zip - name: Rename delta APK - run: mv "${{steps.downloadBaselineAPK.outputs.download-path}}/app-e2eRelease.apk" "${{steps.downloadBaselineAPK.outputs.download-path}}/app-e2eRelease-compare.apk" + run: mv "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease.apk" "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease-compare.apk" + + - name: Copy Delta APK as compare for testing + run: mv "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease-compare.apk" "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease-baseline.apk" - name: Copy e2e code into zip folder run: cp -r tests/e2e zip From e1b500b38a023b5c82b99f0adcd0acac5b73b9a2 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Wed, 16 Aug 2023 11:12:06 -0600 Subject: [PATCH 010/101] Add more logs --- src/libs/E2E/tests/openSearchPageTest.e2e.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/libs/E2E/tests/openSearchPageTest.e2e.js b/src/libs/E2E/tests/openSearchPageTest.e2e.js index 2f0f72f35bdd..12fcfc3fd1a7 100644 --- a/src/libs/E2E/tests/openSearchPageTest.e2e.js +++ b/src/libs/E2E/tests/openSearchPageTest.e2e.js @@ -7,12 +7,16 @@ import CONST from '../../../CONST'; const test = () => { // check for login (if already logged in the action will simply resolve) + console.debug('[E2E] Logging in for search'); + E2ELogin().then((neededLogin) => { if (neededLogin) { // we don't want to submit the first login to the results return E2EClient.submitTestDone(); } + console.debug('[E2E] Logged in, getting search metrics and submitting them…'); + Performance.subscribeToMeasurements((entry) => { if (entry.name !== CONST.TIMING.SEARCH_RENDER) { return; @@ -21,7 +25,14 @@ const test = () => { E2EClient.submitTestResults({ name: 'Open Search Page TTI', duration: entry.duration, - }).then(E2EClient.submitTestDone); + }) + .then(() => { + console.debug('[E2E] Done with search, exiting…'); + E2EClient.submitTestDone(); + }) + .catch((err) => { + console.debug('[E2E] Error while submitting test results:', err); + }); }); Navigation.navigate(ROUTES.SEARCH); From 6a93aeb4167656de56731b75e20e4acbc114113b Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Wed, 16 Aug 2023 13:10:24 -0600 Subject: [PATCH 011/101] Add more logs --- src/libs/E2E/tests/openSearchPageTest.e2e.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/E2E/tests/openSearchPageTest.e2e.js b/src/libs/E2E/tests/openSearchPageTest.e2e.js index 12fcfc3fd1a7..ded45f55fd9c 100644 --- a/src/libs/E2E/tests/openSearchPageTest.e2e.js +++ b/src/libs/E2E/tests/openSearchPageTest.e2e.js @@ -18,10 +18,12 @@ const test = () => { console.debug('[E2E] Logged in, getting search metrics and submitting them…'); Performance.subscribeToMeasurements((entry) => { + console.debug(`[E2E] Entry: ${entry}`); if (entry.name !== CONST.TIMING.SEARCH_RENDER) { return; } + console.debug(`[E2E] Submitting!`); E2EClient.submitTestResults({ name: 'Open Search Page TTI', duration: entry.duration, From 25af1459173556bef2f09ba0c8dc87db9e2fb707 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Wed, 16 Aug 2023 14:13:20 -0600 Subject: [PATCH 012/101] =?UTF-8?q?Fix=20logs=20=F0=9F=99=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/E2E/tests/openSearchPageTest.e2e.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/E2E/tests/openSearchPageTest.e2e.js b/src/libs/E2E/tests/openSearchPageTest.e2e.js index ded45f55fd9c..e96d70c95d94 100644 --- a/src/libs/E2E/tests/openSearchPageTest.e2e.js +++ b/src/libs/E2E/tests/openSearchPageTest.e2e.js @@ -18,7 +18,7 @@ const test = () => { console.debug('[E2E] Logged in, getting search metrics and submitting them…'); Performance.subscribeToMeasurements((entry) => { - console.debug(`[E2E] Entry: ${entry}`); + console.debug(`[E2E] Entry: ${JSON.stringify(entry)}`); if (entry.name !== CONST.TIMING.SEARCH_RENDER) { return; } From 028b384dce0f9888e0c20f4fd7a5cc1f6bd5586f Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Wed, 16 Aug 2023 15:48:21 -0600 Subject: [PATCH 013/101] Only navigate to search bar once sidebar is loaded --- src/libs/E2E/tests/openSearchPageTest.e2e.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/E2E/tests/openSearchPageTest.e2e.js b/src/libs/E2E/tests/openSearchPageTest.e2e.js index e96d70c95d94..3b2d91322cf0 100644 --- a/src/libs/E2E/tests/openSearchPageTest.e2e.js +++ b/src/libs/E2E/tests/openSearchPageTest.e2e.js @@ -18,6 +18,12 @@ const test = () => { console.debug('[E2E] Logged in, getting search metrics and submitting them…'); Performance.subscribeToMeasurements((entry) => { + if (entry.name === CONST.TIMING.SIDEBAR_LOADED) { + console.debug(`[E2E] Sidebar loaded, navigating to search route…`); + Navigation.navigate(ROUTES.SEARCH); + return; + } + console.debug(`[E2E] Entry: ${JSON.stringify(entry)}`); if (entry.name !== CONST.TIMING.SEARCH_RENDER) { return; @@ -36,8 +42,6 @@ const test = () => { console.debug('[E2E] Error while submitting test results:', err); }); }); - - Navigation.navigate(ROUTES.SEARCH); }); }; From 82713e6d8cf169d33e7a616b1bede527a94a7cf7 Mon Sep 17 00:00:00 2001 From: Jakub Trzebiatowski Date: Mon, 21 Aug 2023 10:29:40 +0200 Subject: [PATCH 014/101] Remove unused attachment placeholder code --- src/pages/home/report/ReportActionItem.js | 1 + .../home/report/ReportActionItemFragment.js | 19 ------------------- .../home/report/ReportActionItemMessage.js | 1 - .../home/report/ReportActionItemSingle.js | 1 - 4 files changed, 1 insertion(+), 21 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 8700327a168a..5dda82145f21 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -549,6 +549,7 @@ function ReportActionItem(props) { diff --git a/src/pages/home/report/ReportActionItemFragment.js b/src/pages/home/report/ReportActionItemFragment.js index 009c1118400b..b437010efe75 100644 --- a/src/pages/home/report/ReportActionItemFragment.js +++ b/src/pages/home/report/ReportActionItemFragment.js @@ -1,5 +1,4 @@ import React, {memo} from 'react'; -import {ActivityIndicator, View} from 'react-native'; import PropTypes from 'prop-types'; import Str from 'expensify-common/lib/str'; import reportActionFragmentPropTypes from './reportActionFragmentPropTypes'; @@ -46,9 +45,6 @@ const propTypes = { source: PropTypes.string, }), - /** Does this fragment belong to a reportAction that has not yet loaded? */ - loading: PropTypes.bool, - /** The reportAction's source */ source: PropTypes.oneOf(['Chronos', 'email', 'ios', 'android', 'web', 'email', '']), @@ -78,7 +74,6 @@ const defaultProps = { type: '', source: '', }, - loading: false, isSingleLine: false, source: '', style: [], @@ -89,20 +84,6 @@ const defaultProps = { function ReportActionItemFragment(props) { switch (props.fragment.type) { case 'COMMENT': { - // If this is an attachment placeholder, return the placeholder component - if (props.isAttachment && props.loading) { - return Str.isImage(props.attachmentInfo.name) ? ( - `} /> - ) : ( - - - - ); - } const {html, text} = props.fragment; // Threaded messages display "[Deleted message]" instead of being hidden altogether. diff --git a/src/pages/home/report/ReportActionItemMessage.js b/src/pages/home/report/ReportActionItemMessage.js index 7dcb2b51dbf3..fbad50c4f7e6 100644 --- a/src/pages/home/report/ReportActionItemMessage.js +++ b/src/pages/home/report/ReportActionItemMessage.js @@ -48,7 +48,6 @@ function ReportActionItemMessage(props) { pendingAction={props.action.pendingAction} source={lodashGet(props.action, 'originalMessage.source')} accountID={props.action.actorAccountID} - loading={props.action.isLoading} style={props.style} /> )) diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index c00f98c613e4..d1805cd148da 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -231,7 +231,6 @@ function ReportActionItemSingle(props) { accountID={actorAccountID} fragment={fragment} isAttachment={props.action.isAttachment} - isLoading={props.action.isLoading} delegateAccountID={props.action.delegateAccountID} isSingleLine actorIcon={icon} From 49f20da8dd368313b7c7feaa7300419ee66a5010 Mon Sep 17 00:00:00 2001 From: Jakub Trzebiatowski Date: Mon, 21 Aug 2023 11:08:52 +0200 Subject: [PATCH 015/101] Remove the remaining uses of the report action `isLoading` property --- src/pages/home/report/ReportActionItem.js | 3 +-- src/pages/home/report/reportActionPropTypes.js | 3 --- src/styles/StyleUtils.js | 6 +++--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 5dda82145f21..fe8eb4638e98 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -549,8 +549,7 @@ function ReportActionItem(props) { Date: Mon, 21 Aug 2023 09:01:26 -1000 Subject: [PATCH 016/101] Save queued updates to memory only --- src/ONYXKEYS.js | 3 --- src/libs/actions/QueuedOnyxUpdates.js | 16 +++++----------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 27e7f9f0ecf3..093ef83ef62b 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -24,9 +24,6 @@ export default { // Note: These are Persisted Requests - not all requests in the main queue as the key name might lead one to believe PERSISTED_REQUESTS: 'networkRequestQueue', - // Onyx updates from a response, or success or failure data from a request. - QUEUED_ONYX_UPDATES: 'queuedOnyxUpdates', - // Stores current date CURRENT_DATE: 'currentDate', diff --git a/src/libs/actions/QueuedOnyxUpdates.js b/src/libs/actions/QueuedOnyxUpdates.js index 486108dd56cf..f13ce83dcb97 100644 --- a/src/libs/actions/QueuedOnyxUpdates.js +++ b/src/libs/actions/QueuedOnyxUpdates.js @@ -1,24 +1,18 @@ -import Onyx from 'react-native-onyx'; -import ONYXKEYS from '../../ONYXKEYS'; - -// In this file we manage a queue of Onyx updates while the SequentialQueue is processing. There are functions to get the updates and clear the queue after saving the updates in Onyx. +// In this file we manage a queue of Onyx updates while the SequentialQueue is processing. There are functions to get the updates and clear the queue after saving the updates. let queuedOnyxUpdates = []; -Onyx.connect({ - key: ONYXKEYS.QUEUED_ONYX_UPDATES, - callback: (val) => (queuedOnyxUpdates = val || []), -}); /** * @param {Array} updates Onyx updates to queue for later - * @returns {Promise} + * @returns {Promise} */ function queueOnyxUpdates(updates) { - return Onyx.set(ONYXKEYS.QUEUED_ONYX_UPDATES, [...queuedOnyxUpdates, ...updates]); + queuedOnyxUpdates.concat(updates); + return Promise.resolve(); } function clear() { - Onyx.set(ONYXKEYS.QUEUED_ONYX_UPDATES, null); + queuedOnyxUpdates = []; } /** From 6307d475240e777bc6f3de1f167a6dc5ed802310 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 21 Aug 2023 09:05:30 -1000 Subject: [PATCH 017/101] concat returns a new array --- src/libs/actions/QueuedOnyxUpdates.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/QueuedOnyxUpdates.js b/src/libs/actions/QueuedOnyxUpdates.js index f13ce83dcb97..d8f2d0b2519c 100644 --- a/src/libs/actions/QueuedOnyxUpdates.js +++ b/src/libs/actions/QueuedOnyxUpdates.js @@ -7,7 +7,7 @@ let queuedOnyxUpdates = []; * @returns {Promise} */ function queueOnyxUpdates(updates) { - queuedOnyxUpdates.concat(updates); + queuedOnyxUpdates = queuedOnyxUpdates.concat(updates); return Promise.resolve(); } From f2e47536add964b8f38a8a22f88609c012afc36f Mon Sep 17 00:00:00 2001 From: Jakub Trzebiatowski Date: Tue, 22 Aug 2023 10:00:30 +0200 Subject: [PATCH 018/101] ReportActionItemFragment: Remove unused isAttachment property --- src/pages/home/report/ReportActionItemFragment.js | 4 ---- src/pages/home/report/ReportActionItemMessage.js | 1 - src/pages/home/report/ReportActionItemSingle.js | 1 - 3 files changed, 6 deletions(-) diff --git a/src/pages/home/report/ReportActionItemFragment.js b/src/pages/home/report/ReportActionItemFragment.js index b437010efe75..2988d62f8d38 100644 --- a/src/pages/home/report/ReportActionItemFragment.js +++ b/src/pages/home/report/ReportActionItemFragment.js @@ -27,9 +27,6 @@ const propTypes = { /** The message fragment needing to be displayed */ fragment: reportActionFragmentPropTypes.isRequired, - /** Is this fragment an attachment? */ - isAttachment: PropTypes.bool, - /** If this fragment is attachment than has info? */ attachmentInfo: PropTypes.shape({ /** The file name of attachment */ @@ -67,7 +64,6 @@ const propTypes = { }; const defaultProps = { - isAttachment: false, attachmentInfo: { name: '', size: 0, diff --git a/src/pages/home/report/ReportActionItemMessage.js b/src/pages/home/report/ReportActionItemMessage.js index fbad50c4f7e6..2850b396e113 100644 --- a/src/pages/home/report/ReportActionItemMessage.js +++ b/src/pages/home/report/ReportActionItemMessage.js @@ -42,7 +42,6 @@ function ReportActionItemMessage(props) { Date: Tue, 22 Aug 2023 10:07:20 +0200 Subject: [PATCH 019/101] Run Prettier --- src/pages/home/report/ReportActionItem.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 6d2b5ae14270..36d437ccb82f 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -556,12 +556,7 @@ function ReportActionItem(props) { draftMessage={props.draftMessage} isChronosReport={ReportUtils.chatIncludesChronos(originalReport)} /> - + ReportActions.clearReportActionErrors(props.report.reportID, props.action)} pendingAction={props.draftMessage ? null : props.action.pendingAction} From e08c5b4acafe23c27cffb18afad2aa2c6d079f91 Mon Sep 17 00:00:00 2001 From: Jakub Trzebiatowski Date: Tue, 22 Aug 2023 11:53:28 +0200 Subject: [PATCH 020/101] getReportActionItemStyle: Remove effectively unused hasError argument --- src/pages/home/report/ReportActionItem.js | 2 +- src/styles/StyleUtils.js | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 36d437ccb82f..fdf588921995 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -556,7 +556,7 @@ function ReportActionItem(props) { draftMessage={props.draftMessage} isChronosReport={ReportUtils.chatIncludesChronos(originalReport)} /> - + ReportActions.clearReportActionErrors(props.report.reportID, props.action)} pendingAction={props.draftMessage ? null : props.action.pendingAction} diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index 5aeb28d83e0e..6bb159a97297 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -637,10 +637,9 @@ function getLoginPagePromoStyle() { * Generate the styles for the ReportActionItem wrapper view. * * @param {Boolean} [isHovered] - * @param {Boolean} [hasError] * @returns {Object} */ -function getReportActionItemStyle(isHovered = false, hasError = false) { +function getReportActionItemStyle(isHovered = false) { return { display: 'flex', justifyContent: 'space-between', @@ -648,7 +647,7 @@ function getReportActionItemStyle(isHovered = false, hasError = false) { ? themeColors.hoverComponentBG : // Warning: Setting this to a non-transparent color will cause unread indicator to break on Android colors.transparent, - opacity: hasError ? 0.5 : 1, + opacity: 1, ...styles.cursorInitial, }; } From 08e20a9796d426ff16e46caed4ab262800b37774 Mon Sep 17 00:00:00 2001 From: Maciej Dobosz Date: Mon, 28 Aug 2023 15:00:23 +0200 Subject: [PATCH 021/101] Rewrite to functional component --- src/components/withLocalize.js | 68 +++++++++++++--------------------- 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/src/components/withLocalize.js b/src/components/withLocalize.js index def7110c1b40..4064ace042c0 100755 --- a/src/components/withLocalize.js +++ b/src/components/withLocalize.js @@ -62,49 +62,28 @@ const localeProviderDefaultProps = { currentUserPersonalDetails: {}, }; -class LocaleContextProvider extends React.Component { - /** - * The context this component exposes to child components - * @returns {object} translation util functions and locale - */ - getContextValue() { - return { - translate: this.translate.bind(this), - numberFormat: this.numberFormat.bind(this), - datetimeToRelative: this.datetimeToRelative.bind(this), - datetimeToCalendarTime: this.datetimeToCalendarTime.bind(this), - formatPhoneNumber: this.formatPhoneNumber.bind(this), - fromLocaleDigit: this.fromLocaleDigit.bind(this), - toLocaleDigit: this.toLocaleDigit.bind(this), - preferredLocale: this.props.preferredLocale, - }; - } +function LocaleContextProvider ({children, currentUserPersonalDetails, preferredLocale}) { + const selectedTimezone = lodashGet(currentUserPersonalDetails, 'timezone.selected'); /** * @param {String} phrase * @param {Object} [variables] * @returns {String} */ - translate(phrase, variables) { - return Localize.translate(this.props.preferredLocale, phrase, variables); - } + const translate = (phrase, variables) => Localize.translate(preferredLocale, phrase, variables) /** * @param {Number} number * @param {Intl.NumberFormatOptions} options * @returns {String} */ - numberFormat(number, options) { - return NumberFormatUtils.format(this.props.preferredLocale, number, options); - } + const numberFormat = (number, options) => NumberFormatUtils.format(preferredLocale, number, options) /** * @param {String} datetime * @returns {String} */ - datetimeToRelative(datetime) { - return DateUtils.datetimeToRelative(this.props.preferredLocale, datetime); - } + const datetimeToRelative = (datetime) => DateUtils.datetimeToRelative(preferredLocale, datetime) /** * @param {String} datetime - ISO-formatted datetime string @@ -112,37 +91,42 @@ class LocaleContextProvider extends React.Component { * @param {Boolean} isLowercase * @returns {String} */ - datetimeToCalendarTime(datetime, includeTimezone, isLowercase = false) { - return DateUtils.datetimeToCalendarTime(this.props.preferredLocale, datetime, includeTimezone, lodashGet(this.props, 'currentUserPersonalDetails.timezone.selected'), isLowercase); - } + const datetimeToCalendarTime = (datetime, includeTimezone, isLowercase = false) => DateUtils.datetimeToCalendarTime(preferredLocale, datetime, includeTimezone, selectedTimezone, isLowercase) /** * @param {String} phoneNumber * @returns {String} */ - formatPhoneNumber(phoneNumber) { - return LocalePhoneNumber.formatPhoneNumber(phoneNumber); - } + const formatPhoneNumber = (phoneNumber) => LocalePhoneNumber.formatPhoneNumber(phoneNumber) /** * @param {String} digit * @returns {String} */ - toLocaleDigit(digit) { - return LocaleDigitUtils.toLocaleDigit(this.props.preferredLocale, digit); - } - + const toLocaleDigit = (digit) => LocaleDigitUtils.toLocaleDigit(preferredLocale, digit) + /** * @param {String} localeDigit * @returns {String} */ - fromLocaleDigit(localeDigit) { - return LocaleDigitUtils.fromLocaleDigit(this.props.preferredLocale, localeDigit); - } + const fromLocaleDigit = (localeDigit) => LocaleDigitUtils.fromLocaleDigit(preferredLocale, localeDigit) - render() { - return {this.props.children}; - } + /** + * The context this component exposes to child components + * @returns {object} translation util functions and locale + */ + const getContextValue = () => ({ + translate, + numberFormat, + datetimeToRelative, + datetimeToCalendarTime, + formatPhoneNumber, + toLocaleDigit, + fromLocaleDigit, + preferredLocale, + }) + + return {children}; } LocaleContextProvider.propTypes = localeProviderPropTypes; From bde2831bbd84eb7d175832281d018ec7305308f2 Mon Sep 17 00:00:00 2001 From: Maciej Dobosz Date: Tue, 29 Aug 2023 12:02:35 +0200 Subject: [PATCH 022/101] Run prettier --- src/components/withLocalize.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/components/withLocalize.js b/src/components/withLocalize.js index 4064ace042c0..f133980f96d5 100755 --- a/src/components/withLocalize.js +++ b/src/components/withLocalize.js @@ -62,7 +62,7 @@ const localeProviderDefaultProps = { currentUserPersonalDetails: {}, }; -function LocaleContextProvider ({children, currentUserPersonalDetails, preferredLocale}) { +function LocaleContextProvider({children, currentUserPersonalDetails, preferredLocale}) { const selectedTimezone = lodashGet(currentUserPersonalDetails, 'timezone.selected'); /** @@ -70,20 +70,20 @@ function LocaleContextProvider ({children, currentUserPersonalDetails, preferred * @param {Object} [variables] * @returns {String} */ - const translate = (phrase, variables) => Localize.translate(preferredLocale, phrase, variables) + const translate = (phrase, variables) => Localize.translate(preferredLocale, phrase, variables); /** * @param {Number} number * @param {Intl.NumberFormatOptions} options * @returns {String} */ - const numberFormat = (number, options) => NumberFormatUtils.format(preferredLocale, number, options) + const numberFormat = (number, options) => NumberFormatUtils.format(preferredLocale, number, options); /** * @param {String} datetime * @returns {String} */ - const datetimeToRelative = (datetime) => DateUtils.datetimeToRelative(preferredLocale, datetime) + const datetimeToRelative = (datetime) => DateUtils.datetimeToRelative(preferredLocale, datetime); /** * @param {String} datetime - ISO-formatted datetime string @@ -91,25 +91,26 @@ function LocaleContextProvider ({children, currentUserPersonalDetails, preferred * @param {Boolean} isLowercase * @returns {String} */ - const datetimeToCalendarTime = (datetime, includeTimezone, isLowercase = false) => DateUtils.datetimeToCalendarTime(preferredLocale, datetime, includeTimezone, selectedTimezone, isLowercase) + const datetimeToCalendarTime = (datetime, includeTimezone, isLowercase = false) => + DateUtils.datetimeToCalendarTime(preferredLocale, datetime, includeTimezone, selectedTimezone, isLowercase); /** * @param {String} phoneNumber * @returns {String} */ - const formatPhoneNumber = (phoneNumber) => LocalePhoneNumber.formatPhoneNumber(phoneNumber) + const formatPhoneNumber = (phoneNumber) => LocalePhoneNumber.formatPhoneNumber(phoneNumber); /** * @param {String} digit * @returns {String} */ - const toLocaleDigit = (digit) => LocaleDigitUtils.toLocaleDigit(preferredLocale, digit) - + const toLocaleDigit = (digit) => LocaleDigitUtils.toLocaleDigit(preferredLocale, digit); + /** * @param {String} localeDigit * @returns {String} */ - const fromLocaleDigit = (localeDigit) => LocaleDigitUtils.fromLocaleDigit(preferredLocale, localeDigit) + const fromLocaleDigit = (localeDigit) => LocaleDigitUtils.fromLocaleDigit(preferredLocale, localeDigit); /** * The context this component exposes to child components @@ -124,7 +125,7 @@ function LocaleContextProvider ({children, currentUserPersonalDetails, preferred toLocaleDigit, fromLocaleDigit, preferredLocale, - }) + }); return {children}; } From 1dd186358d0779e3f81fd3da8c4650c119ddd882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 31 Aug 2023 10:20:27 +0200 Subject: [PATCH 023/101] point to correct .env file in build.gradle --- android/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index f4dacff0324c..fad4658591dd 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -58,7 +58,7 @@ project.ext.envConfigFiles = [ adhocRelease: ".env.adhoc", developmentRelease: ".env", developmentDebug: ".env", - e2eRelease: ".env.production" + e2eRelease: "tests/e2e/.env.e2e" ] /** From bc17ec74dc40c16db1551eeeae0ea05b819a4031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 12:40:08 +0200 Subject: [PATCH 024/101] fix e2e build locally --- android/app/build.gradle | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index fad4658591dd..4fe65dbc4e84 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -136,10 +136,20 @@ android { signingConfig signingConfigs.debug } release { - signingConfig signingConfigs.release productFlavors.production.signingConfig signingConfigs.release minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + + signingConfig null + // buildTypes take precedence over productFlavors when it comes to the signing configuration, + // thus we need to manually set the signing config, so that the e2e uses the debug config again. + // In other words, the signingConfig setting above will be ignored when we build the flavor in release mode. + productFlavors.all { flavor -> + // All release builds should be signed with the release config ... + flavor.signingConfig signingConfigs.release + } + // ... except for the e2e flavor, which we maybe want to build locally: + productFlavors.e2e.signingConfig signingConfigs.debug } } From cdd8111cf6d3eb6427d0b00066d77c8932fc6112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 12:41:13 +0200 Subject: [PATCH 025/101] fix local e2e build paths --- tests/e2e/config.local.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/config.local.js b/tests/e2e/config.local.js index cd0b04d7c3cf..4187d3d2246f 100644 --- a/tests/e2e/config.local.js +++ b/tests/e2e/config.local.js @@ -2,7 +2,7 @@ module.exports = { WARM_UP_RUNS: 1, RUNS: 8, APP_PATHS: { - baseline: './android/app/build/outputs/apk/e2eRelease/app-e2eRelease.apk', - compare: './android/app/build/outputs/apk/e2eRelease/app-e2eRelease.apk', + baseline: './android/app/build/outputs/apk/release/app-e2e-release.apk', + compare: './android/app/build/outputs/apk/release/app-e2e-release.apk', }, }; From 9406c50da963850d55cf350aa3ff51fdc2566a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 12:44:16 +0200 Subject: [PATCH 026/101] fix lines being printed twice --- tests/e2e/utils/logger.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/e2e/utils/logger.js b/tests/e2e/utils/logger.js index aa198aec3004..1f2fff315bfc 100644 --- a/tests/e2e/utils/logger.js +++ b/tests/e2e/utils/logger.js @@ -61,19 +61,16 @@ const progressInfo = (textParam) => { }; const info = (...args) => { - console.debug('> ', ...args); - log(...args); + log('> ', ...args); }; const warn = (...args) => { const lines = [`\n${COLOR_YELLOW}⚠️`, ...args, `${COLOR_RESET}\n`]; - console.debug(...lines); log(...lines); }; const note = (...args) => { const lines = [`\n💡${COLOR_DIM}`, ...args, `${COLOR_RESET}\n`]; - console.debug(...lines); log(...lines); }; From 1b16f1d772062590e584f3415d17b5c119091a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 12:49:43 +0200 Subject: [PATCH 027/101] fix local app path --- tests/e2e/config.local.js | 4 ++-- tests/e2e/testRunner.js | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/e2e/config.local.js b/tests/e2e/config.local.js index 4187d3d2246f..7ce7cfea7462 100644 --- a/tests/e2e/config.local.js +++ b/tests/e2e/config.local.js @@ -2,7 +2,7 @@ module.exports = { WARM_UP_RUNS: 1, RUNS: 8, APP_PATHS: { - baseline: './android/app/build/outputs/apk/release/app-e2e-release.apk', - compare: './android/app/build/outputs/apk/release/app-e2e-release.apk', + baseline: './android/app/build/outputs/apk/e2e/release/app-e2e-release.apk', + compare: './android/app/build/outputs/apk/e2e/release/app-e2e-release.apk', }, }; diff --git a/tests/e2e/testRunner.js b/tests/e2e/testRunner.js index db421ae64ef1..401828065063 100644 --- a/tests/e2e/testRunner.js +++ b/tests/e2e/testRunner.js @@ -89,6 +89,8 @@ const runTestsOnBranch = async (baselineOrCompare, branch) => { const appExists = fs.existsSync(appPath); if (!appExists) { Logger.warn(`Build mode "${buildMode}" is not possible, because the app does not exist. Falling back to build mode "full".`); + Logger.note(`App path: ${appPath}`); + buildMode = 'full'; } } From 88ce3670d7c49e6d062a38532c59c83b8f649ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 12:54:15 +0200 Subject: [PATCH 028/101] set correct app package name --- tests/e2e/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/config.js b/tests/e2e/config.js index d322fb970b2d..d7844a29f3e4 100644 --- a/tests/e2e/config.js +++ b/tests/e2e/config.js @@ -21,7 +21,7 @@ const TEST_NAMES = { * ``` */ module.exports = { - APP_PACKAGE: 'com.expensify.chat', + APP_PACKAGE: 'com.expensify.chat.adhoc', APP_PATHS: { baseline: './app-e2eRelease-baseline.apk', From 282197bf79bc954f961335d0769ca644e273dbd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 13:40:26 +0200 Subject: [PATCH 029/101] fix repackaging APK in e2e development mode --- .../android-repackage-app-bundle-and-sign.sh | 3 +- scripts/shellUtils.sh | 41 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/scripts/android-repackage-app-bundle-and-sign.sh b/scripts/android-repackage-app-bundle-and-sign.sh index fe4ee1e4b8fc..1636edc21388 100755 --- a/scripts/android-repackage-app-bundle-and-sign.sh +++ b/scripts/android-repackage-app-bundle-and-sign.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ./scripts/shellUtils.sh ### # Takes an android app that has been built with the debug keystore, @@ -41,7 +42,7 @@ if [ ! -f "$NEW_BUNDLE_FILE" ]; then echo "Bundle file not found: $NEW_BUNDLE_FILE" exit 1 fi -OUTPUT_APK=$(realpath "$OUTPUT_APK") +OUTPUT_APK=$(get_abs_path "$OUTPUT_APK") # check if "apktool" command is available if ! command -v apktool &> /dev/null then diff --git a/scripts/shellUtils.sh b/scripts/shellUtils.sh index 876933af9766..c6d21e9f14e1 100644 --- a/scripts/shellUtils.sh +++ b/scripts/shellUtils.sh @@ -41,3 +41,44 @@ function join_by_string { shift printf "%s" "$first" "${@/#/$separator}" } + +# Usage: get_abs_path +# Will make a path absolute, resolving any relative paths +# example: get_abs_path "./foo/bar" +get_abs_path() { + local the_path=$1 + local -a path_elements + IFS='/' read -ra path_elements <<< "$the_path" + + # If the path is already absolute, start with an empty string. + # We'll prepend the / later when reconstructing the path. + if [[ "$the_path" = /* ]]; then + abs_path="" + else + abs_path="$(pwd)" + fi + + # Handle each path element + for element in "${path_elements[@]}"; do + if [ "$element" = "." ] || [ -z "$element" ]; then + continue + elif [ "$element" = ".." ]; then + # Remove the last element from abs_path + abs_path=$(dirname "$abs_path") + else + # Append element to the absolute path + abs_path="${abs_path}/${element}" + fi + done + + # Remove any trailing '/' + abs_path=$(echo "$abs_path" | sed 's:/*$::') + + # Special case for root + [ -z "$abs_path" ] && abs_path="/" + + # Special case to remove any starting '//' when the input path was absolute + abs_path=$(echo "$abs_path" | sed 's:^//:/:') + + echo "$abs_path" +} From c3c32e47737af88c9fd958257ca36e80f2d8b7be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 14:17:59 +0200 Subject: [PATCH 030/101] give more explanation --- tests/e2e/ADDING_TESTS.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/e2e/ADDING_TESTS.md b/tests/e2e/ADDING_TESTS.md index 39cdb97ebed0..f525c492b1f8 100644 --- a/tests/e2e/ADDING_TESTS.md +++ b/tests/e2e/ADDING_TESTS.md @@ -97,6 +97,5 @@ Done! When you now start the test runner, your new test will be executed as well ## Quickly test your test To check your new test you can simply run `npm run test:e2e`, which uses the -`--development` flag. This will run the tests on the branch you are currently on -and will do fewer iterations. +`--development` flag. This will run the tests on the branch you are currently on, runs fewer iterations and most importantly, it tries to reuse the existing APK and just patch into the new app bundle, instead of rebuilding the release app from scratch. From ff374296c248aadb94d694fc43897b2ab4d6cbd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 14:21:30 +0200 Subject: [PATCH 031/101] explain debugging --- tests/e2e/ADDING_TESTS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/e2e/ADDING_TESTS.md b/tests/e2e/ADDING_TESTS.md index f525c492b1f8..566cf489e6a0 100644 --- a/tests/e2e/ADDING_TESTS.md +++ b/tests/e2e/ADDING_TESTS.md @@ -99,3 +99,8 @@ Done! When you now start the test runner, your new test will be executed as well To check your new test you can simply run `npm run test:e2e`, which uses the `--development` flag. This will run the tests on the branch you are currently on, runs fewer iterations and most importantly, it tries to reuse the existing APK and just patch into the new app bundle, instead of rebuilding the release app from scratch. +## Debugging your test + +You can use regular console statements to debug your test. The output will be visible +in logcat. I recommend opening the android studio logcat window and filter for `ReactNativeJS` to see the output you'd otherwise typically see in your metro bundler instance. + From 32940c469ec512f55530461beeabffcd434f094f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 15:00:32 +0200 Subject: [PATCH 032/101] Improve DX if any config is wrong --- src/libs/E2E/reactNativeLaunchingTest.js | 46 +++++++++++++++--------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/libs/E2E/reactNativeLaunchingTest.js b/src/libs/E2E/reactNativeLaunchingTest.js index 869f5d1f1f1a..f8bb59274b49 100644 --- a/src/libs/E2E/reactNativeLaunchingTest.js +++ b/src/libs/E2E/reactNativeLaunchingTest.js @@ -6,6 +6,7 @@ */ import Performance from '../Performance'; +import * as Metrics from '../Metrics'; // start the usual app Performance.markStart('regularAppStart'); @@ -19,6 +20,11 @@ console.debug('=========================='); console.debug('==== Running e2e test ===='); console.debug('=========================='); +// Check if the performance module is available +if (!Metrics.canCapturePerformanceMetrics()) { + throw new Error('Performance module not available! Please set CAPTURE_METRICS=true in your environment file!'); +} + // import your test here, define its name and config first in e2e/config.js const tests = { [E2EConfig.TEST_NAMES.AppStartTime]: require('./tests/appStartTimeTest.e2e').default, @@ -36,20 +42,28 @@ const appReady = new Promise((resolve) => { }); }); -E2EClient.getTestConfig().then((config) => { - const test = tests[config.name]; - if (!test) { - // instead of throwing, report the error to the server, which is better for DX - return E2EClient.submitTestResults({ - name: config.name, - error: `Test '${config.name}' not found`, - }); - } - console.debug(`[E2E] Configured for test ${config.name}. Waiting for app to become ready`); - - appReady.then(() => { - console.debug('[E2E] App is ready, running test…'); - Performance.measureFailSafe('appStartedToReady', 'regularAppStart'); - test(); +E2EClient.getTestConfig() + .then((config) => { + const test = tests[config.name]; + if (!test) { + // instead of throwing, report the error to the server, which is better for DX + return E2EClient.submitTestResults({ + name: config.name, + error: `Test '${config.name}' not found`, + }); + } + + console.debug(`[E2E] Configured for test ${config.name}. Waiting for app to become ready`); + appReady + .then(() => { + console.debug('[E2E] App is ready, running test…'); + Performance.measureFailSafe('appStartedToReady', 'regularAppStart'); + test(); + }) + .catch((error) => { + console.error('[E2E] Error while waiting for app to become ready', error); + }); + }) + .catch((error) => { + console.error("[E2E] Error while running test. Couldn't get test config!", error); }); -}); From bc114f9342ec082eccc8d964388280a54a292565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 17:53:12 +0200 Subject: [PATCH 033/101] move app loading to end --- src/libs/E2E/reactNativeLaunchingTest.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/E2E/reactNativeLaunchingTest.js b/src/libs/E2E/reactNativeLaunchingTest.js index f8bb59274b49..6836e9c6c296 100644 --- a/src/libs/E2E/reactNativeLaunchingTest.js +++ b/src/libs/E2E/reactNativeLaunchingTest.js @@ -8,11 +8,6 @@ import Performance from '../Performance'; import * as Metrics from '../Metrics'; -// start the usual app -Performance.markStart('regularAppStart'); -import '../../../index'; -Performance.markEnd('regularAppStart'); - import E2EConfig from '../../../tests/e2e/config'; import E2EClient from './client'; @@ -67,3 +62,8 @@ E2EClient.getTestConfig() .catch((error) => { console.error("[E2E] Error while running test. Couldn't get test config!", error); }); + +// start the usual app +Performance.markStart('regularAppStart'); +import '../../../appIndex'; +Performance.markEnd('regularAppStart'); From 37d93ffcce18bb2ecb88c51c12da65a0c75ffbea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 17:54:50 +0200 Subject: [PATCH 034/101] fix running tests in debug mode --- package.json | 2 +- tests/e2e/ADDING_TESTS.md | 49 ++++++++++++++++++++++++++++++++++- tests/e2e/config.local.js | 2 ++ tests/e2e/testRunner.js | 3 ++- tests/e2e/utils/installApp.js | 5 ++-- tests/e2e/utils/killApp.js | 4 +-- tests/e2e/utils/launchApp.js | 4 +-- 7 files changed, 60 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index e9358de7fd28..fd93d8817d54 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "analyze-packages": "ANALYZE_BUNDLE=true webpack --config config/webpack/webpack.common.js --env envFile=.env.production", "symbolicate:android": "npx metro-symbolicate android/app/build/generated/sourcemaps/react/release/index.android.bundle.map", "symbolicate:ios": "npx metro-symbolicate main.jsbundle.map", - "test:e2e": "node tests/e2e/testRunner.js --development" + "test:e2e": "node tests/e2e/testRunner.js" }, "dependencies": { "@expensify/react-native-web": "0.18.15", diff --git a/tests/e2e/ADDING_TESTS.md b/tests/e2e/ADDING_TESTS.md index 566cf489e6a0..7b1caa977a63 100644 --- a/tests/e2e/ADDING_TESTS.md +++ b/tests/e2e/ADDING_TESTS.md @@ -1,4 +1,51 @@ -# Add E2E Tests +# Adding new E2E Tests + +## Running your new test in development mode + +Typically you'd run all the tests with `npm run test:e2e` on your machine, +this will run the tests with some local settings, however that is not +optimal when you add a new test for which you want to quickly test if it works, as it +still runs the release version of the app. + +I recommend doing the following. + +> [!NOTE] +> All of the steps can be executed at once by running XXX (todo) + +1. Rename `./index.js` to `./appIndex.js` +2. Create a new `./index.js` with the following content: +```js +requrire("./src/libs/E2E/reactNativeLaunchingTest.js"); +``` +3. In `./src/libs/E2E/reactNativeLaunchingTest.js` change the main app import to the new `./appIndex.js` file: +```diff +- import '../../../index'; ++ import '../../../appIndex'; +``` + +> [!WARNING] +> Make sure to not commit these changes to the repository! + +Now you can start the metro bundler in e2e mode with: + +``` +CAPTURE_METRICS=TRUE E2E_Testing=true npm start -- --reset-cache +``` + +Then we can execute our test with: + +``` +npm run test:e2e -- --development --skipInstallDeps --buildMode skip --includes "My new test name" +``` + +> - `--development` will run the tests with a local config, which will run the tests with fewer iterations +> - `--skipInstallDeps` will skip the `npm install` step, which you probably don't need +> - `--buildMode skip` will skip rebuilding the app, and just run the existing app +> - `--includes "MyTestName"` will only run the test with the name "MyTestName" + + + +## Creating a new test Tests are executed on device, inside the app code. diff --git a/tests/e2e/config.local.js b/tests/e2e/config.local.js index 7ce7cfea7462..0c38c3f1056f 100644 --- a/tests/e2e/config.local.js +++ b/tests/e2e/config.local.js @@ -1,4 +1,6 @@ module.exports = { + APP_PACKAGE: 'com.expensify.chat.dev', + WARM_UP_RUNS: 1, RUNS: 8, APP_PATHS: { diff --git a/tests/e2e/testRunner.js b/tests/e2e/testRunner.js index 401828065063..57a550d87104 100644 --- a/tests/e2e/testRunner.js +++ b/tests/e2e/testRunner.js @@ -117,6 +117,7 @@ const runTestsOnBranch = async (baselineOrCompare, branch) => { const tempDir = `${config.OUTPUT_DIR}/temp`; const tempBundlePath = `${tempDir}/index.android.bundle`; await execAsync(`rm -rf ${tempDir} && mkdir ${tempDir}`); + // TODO: test if that breaks support for the env file await execAsync(`E2E_TESTING=true npx react-native bundle --platform android --dev false --entry-file ${config.ENTRY_FILE} --bundle-output ${tempBundlePath}`); // Repackage the existing native app with the new bundle @@ -127,7 +128,7 @@ const runTestsOnBranch = async (baselineOrCompare, branch) => { // Install app and reverse port let progressLog = Logger.progressInfo('Installing app and reversing port'); - await installApp('android', appPath); + await installApp('android', config.APP_PACKAGE, appPath); await reversePort(); progressLog.done(); diff --git a/tests/e2e/utils/installApp.js b/tests/e2e/utils/installApp.js index 136602375f85..ff961940826a 100644 --- a/tests/e2e/utils/installApp.js +++ b/tests/e2e/utils/installApp.js @@ -7,16 +7,17 @@ const Logger = require('./logger'); * It removes the app first if it already exists, so it's a clean installation. * * @param {String} platform + * @param {String} packageName * @param {String} path * @returns {Promise} */ -module.exports = function (platform = 'android', path) { +module.exports = function (platform = 'android', packageName = APP_PACKAGE, path) { if (platform !== 'android') { throw new Error(`installApp() missing implementation for platform: ${platform}`); } // Uninstall first, then install - return execAsync(`adb uninstall ${APP_PACKAGE}`) + return execAsync(`adb uninstall ${packageName}`) .catch((e) => { // Ignore errors Logger.warn('Failed to uninstall app:', e); diff --git a/tests/e2e/utils/killApp.js b/tests/e2e/utils/killApp.js index 9761ee7fc66e..bdef215bf752 100644 --- a/tests/e2e/utils/killApp.js +++ b/tests/e2e/utils/killApp.js @@ -1,11 +1,11 @@ const {APP_PACKAGE} = require('../config'); const execAsync = require('./execAsync'); -module.exports = function (platform = 'android') { +module.exports = function (platform = 'android', packageName = APP_PACKAGE) { if (platform !== 'android') { throw new Error(`killApp() missing implementation for platform: ${platform}`); } // Use adb to kill the app - return execAsync(`adb shell am force-stop ${APP_PACKAGE}`); + return execAsync(`adb shell am force-stop ${packageName}`); }; diff --git a/tests/e2e/utils/launchApp.js b/tests/e2e/utils/launchApp.js index dce17c7fbb3b..e0726d081086 100644 --- a/tests/e2e/utils/launchApp.js +++ b/tests/e2e/utils/launchApp.js @@ -1,11 +1,11 @@ const {APP_PACKAGE} = require('../config'); const execAsync = require('./execAsync'); -module.exports = function (platform = 'android') { +module.exports = function (platform = 'android', packageName = APP_PACKAGE) { if (platform !== 'android') { throw new Error(`launchApp() missing implementation for platform: ${platform}`); } // Use adb to start the app - return execAsync(`adb shell monkey -p ${APP_PACKAGE} -c android.intent.category.LAUNCHER 1`); + return execAsync(`adb shell monkey -p ${packageName} -c android.intent.category.LAUNCHER 1`); }; From 232a2e2c25d62196e61d83d1b653908fbf9cc8ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 18:03:15 +0200 Subject: [PATCH 035/101] fix tests --- src/libs/E2E/API.mock.js | 1 + tests/e2e/config.local.js | 6 ++++-- tests/e2e/testRunner.js | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libs/E2E/API.mock.js b/src/libs/E2E/API.mock.js index 501108025979..47f445f72222 100644 --- a/src/libs/E2E/API.mock.js +++ b/src/libs/E2E/API.mock.js @@ -19,6 +19,7 @@ const mocks = { BeginSignIn: mockBeginSignin, SigninUser: mockSigninUser, OpenApp: mockOpenApp, + ReconnectApp: mockOpenApp, OpenReport: mockOpenReport, AuthenticatePusher: mockAuthenticatePusher, }; diff --git a/tests/e2e/config.local.js b/tests/e2e/config.local.js index 0c38c3f1056f..97ccdc91312b 100644 --- a/tests/e2e/config.local.js +++ b/tests/e2e/config.local.js @@ -4,7 +4,9 @@ module.exports = { WARM_UP_RUNS: 1, RUNS: 8, APP_PATHS: { - baseline: './android/app/build/outputs/apk/e2e/release/app-e2e-release.apk', - compare: './android/app/build/outputs/apk/e2e/release/app-e2e-release.apk', + // baseline: './android/app/build/outputs/apk/e2e/release/app-e2e-release.apk', + baseline: './android/app/build/outputs/apk/development/debug/app-development-debug.apk', + // compare: './android/app/build/outputs/apk/e2e/release/app-e2e-release.apk', + compare: './android/app/build/outputs/apk/development/debug/app-development-debug.apk', }, }; diff --git a/tests/e2e/testRunner.js b/tests/e2e/testRunner.js index 57a550d87104..d945f693ea25 100644 --- a/tests/e2e/testRunner.js +++ b/tests/e2e/testRunner.js @@ -73,9 +73,9 @@ if (isDevMode) { const restartApp = async () => { Logger.log('Killing app …'); - await killApp('android'); + await killApp('android', config.APP_PACKAGE); Logger.log('Launching app …'); - await launchApp('android'); + await launchApp('android', config.APP_PACKAGE); }; const runTestsOnBranch = async (baselineOrCompare, branch) => { From ea62c3c6550973728f3ade10a70aeeac098f9340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 1 Sep 2023 18:05:44 +0200 Subject: [PATCH 036/101] add development flag back --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fd93d8817d54..e9358de7fd28 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "analyze-packages": "ANALYZE_BUNDLE=true webpack --config config/webpack/webpack.common.js --env envFile=.env.production", "symbolicate:android": "npx metro-symbolicate android/app/build/generated/sourcemaps/react/release/index.android.bundle.map", "symbolicate:ios": "npx metro-symbolicate main.jsbundle.map", - "test:e2e": "node tests/e2e/testRunner.js" + "test:e2e": "node tests/e2e/testRunner.js --development" }, "dependencies": { "@expensify/react-native-web": "0.18.15", From 3151b5f31adb04fb4a31324157653fe8901cc59c Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 1 Sep 2023 13:09:15 -1000 Subject: [PATCH 037/101] remove type --- src/ONYXKEYS.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index f381fab3fc64..d0e97e438736 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -302,7 +302,6 @@ type OnyxValues = { [ONYXKEYS.IS_SIDEBAR_LOADED]: boolean; [ONYXKEYS.SHOW_DOWNLOAD_APP_BANNER]: boolean; [ONYXKEYS.PERSISTED_REQUESTS]: OnyxTypes.Request[]; - [ONYXKEYS.QUEUED_ONYX_UPDATES]: OnyxTypes.QueuedOnyxUpdates; [ONYXKEYS.CURRENT_DATE]: string; [ONYXKEYS.CREDENTIALS]: OnyxTypes.Credentials; [ONYXKEYS.IOU]: OnyxTypes.IOU; From 0d9a79a4f8a141e7e8dd9af5be690e45d2db908c Mon Sep 17 00:00:00 2001 From: Maciej Dobosz Date: Wed, 6 Sep 2023 16:34:24 +0200 Subject: [PATCH 038/101] Extract LocaleContext to separate file --- .storybook/preview.js | 2 +- src/App.js | 2 +- src/components/createLocaleContext.js | 122 +++++++++++++++++++++++++ src/components/withLocalize.js | 123 +------------------------- src/hooks/useLocalize.js | 2 +- tests/utils/LHNTestUtils.js | 2 +- 6 files changed, 129 insertions(+), 124 deletions(-) create mode 100644 src/components/createLocaleContext.js diff --git a/.storybook/preview.js b/.storybook/preview.js index 7ccfd74e0e45..a13e93dbe8ad 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -6,7 +6,7 @@ import './fonts.css'; import ComposeProviders from '../src/components/ComposeProviders'; import HTMLEngineProvider from '../src/components/HTMLEngineProvider'; import OnyxProvider from '../src/components/OnyxProvider'; -import {LocaleContextProvider} from '../src/components/withLocalize'; +import {LocaleContextProvider} from '../src/components/createLocaleContext'; import ONYXKEYS from '../src/ONYXKEYS'; Onyx.init({ diff --git a/src/App.js b/src/App.js index c432a0b666c8..cd2e57a8d193 100644 --- a/src/App.js +++ b/src/App.js @@ -9,7 +9,7 @@ import {PickerStateProvider} from 'react-native-picker-select'; import CustomStatusBar from './components/CustomStatusBar'; import ErrorBoundary from './components/ErrorBoundary'; import Expensify from './Expensify'; -import {LocaleContextProvider} from './components/withLocalize'; +import {LocaleContextProvider} from './components/createLocaleContext'; import OnyxProvider from './components/OnyxProvider'; import HTMLEngineProvider from './components/HTMLEngineProvider'; import PopoverContextProvider from './components/PopoverProvider'; diff --git a/src/components/createLocaleContext.js b/src/components/createLocaleContext.js new file mode 100644 index 000000000000..be5bb9904b6a --- /dev/null +++ b/src/components/createLocaleContext.js @@ -0,0 +1,122 @@ +import React, {createContext} from 'react'; +import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; +import lodashGet from 'lodash/get'; + +import ONYXKEYS from '../ONYXKEYS'; +import * as Localize from '../libs/Localize'; +import DateUtils from '../libs/DateUtils'; +import * as NumberFormatUtils from '../libs/NumberFormatUtils'; +import * as LocaleDigitUtils from '../libs/LocaleDigitUtils'; +import CONST from '../CONST'; +import compose from '../libs/compose'; +import withCurrentUserPersonalDetails from './withCurrentUserPersonalDetails'; +import * as LocalePhoneNumber from '../libs/LocalePhoneNumber'; + +const LocaleContext = createContext(null); + +const localeProviderPropTypes = { + /** The user's preferred locale e.g. 'en', 'es-ES' */ + preferredLocale: PropTypes.string, + + /** Actual content wrapped by this component */ + children: PropTypes.node.isRequired, + + /** The current user's personalDetails */ + currentUserPersonalDetails: PropTypes.shape({ + /** Timezone of the current user */ + timezone: PropTypes.shape({ + /** Value of the selected timezone */ + selected: PropTypes.string, + }), + }), +}; + +const localeProviderDefaultProps = { + preferredLocale: CONST.LOCALES.DEFAULT, + currentUserPersonalDetails: {}, +}; + +function LocaleContextProvider({children, currentUserPersonalDetails, preferredLocale}) { + const selectedTimezone = lodashGet(currentUserPersonalDetails, 'timezone.selected'); + + /** + * @param {String} phrase + * @param {Object} [variables] + * @returns {String} + */ + const translate = (phrase, variables) => Localize.translate(preferredLocale, phrase, variables); + + /** + * @param {Number} number + * @param {Intl.NumberFormatOptions} options + * @returns {String} + */ + const numberFormat = (number, options) => NumberFormatUtils.format(preferredLocale, number, options); + + /** + * @param {String} datetime + * @returns {String} + */ + const datetimeToRelative = (datetime) => DateUtils.datetimeToRelative(preferredLocale, datetime); + + /** + * @param {String} datetime - ISO-formatted datetime string + * @param {Boolean} [includeTimezone] + * @param {Boolean} isLowercase + * @returns {String} + */ + const datetimeToCalendarTime = (datetime, includeTimezone, isLowercase = false) => + DateUtils.datetimeToCalendarTime(preferredLocale, datetime, includeTimezone, selectedTimezone, isLowercase); + + /** + * @param {String} phoneNumber + * @returns {String} + */ + const formatPhoneNumber = (phoneNumber) => LocalePhoneNumber.formatPhoneNumber(phoneNumber); + + /** + * @param {String} digit + * @returns {String} + */ + const toLocaleDigit = (digit) => LocaleDigitUtils.toLocaleDigit(preferredLocale, digit); + + /** + * @param {String} localeDigit + * @returns {String} + */ + const fromLocaleDigit = (localeDigit) => LocaleDigitUtils.fromLocaleDigit(preferredLocale, localeDigit); + + /** + * The context this component exposes to child components + * @returns {object} translation util functions and locale + */ + const getContextValue = () => ({ + translate, + numberFormat, + datetimeToRelative, + datetimeToCalendarTime, + formatPhoneNumber, + toLocaleDigit, + fromLocaleDigit, + preferredLocale, + }); + + return {children}; +} + +LocaleContextProvider.propTypes = localeProviderPropTypes; +LocaleContextProvider.defaultProps = localeProviderDefaultProps; + +const Provider = compose( + withCurrentUserPersonalDetails, + withOnyx({ + preferredLocale: { + key: ONYXKEYS.NVP_PREFERRED_LOCALE, + }, + }), +)(LocaleContextProvider); + +Provider.displayName = 'withOnyx(LocaleContextProvider)'; + +export {Provider as LocaleContextProvider, LocaleContext}; diff --git a/src/components/withLocalize.js b/src/components/withLocalize.js index f133980f96d5..f717b822f6ee 100755 --- a/src/components/withLocalize.js +++ b/src/components/withLocalize.js @@ -1,20 +1,7 @@ -import React, {createContext, forwardRef} from 'react'; +import React, {forwardRef} from 'react'; import PropTypes from 'prop-types'; -import {withOnyx} from 'react-native-onyx'; -import lodashGet from 'lodash/get'; - +import {LocaleContext} from './createLocaleContext'; import getComponentDisplayName from '../libs/getComponentDisplayName'; -import ONYXKEYS from '../ONYXKEYS'; -import * as Localize from '../libs/Localize'; -import DateUtils from '../libs/DateUtils'; -import * as NumberFormatUtils from '../libs/NumberFormatUtils'; -import * as LocaleDigitUtils from '../libs/LocaleDigitUtils'; -import CONST from '../CONST'; -import compose from '../libs/compose'; -import withCurrentUserPersonalDetails from './withCurrentUserPersonalDetails'; -import * as LocalePhoneNumber from '../libs/LocalePhoneNumber'; - -const LocaleContext = createContext(null); const withLocalizePropTypes = { /** Returns translated string for given locale and phrase */ @@ -40,110 +27,6 @@ const withLocalizePropTypes = { toLocaleDigit: PropTypes.func.isRequired, }; -const localeProviderPropTypes = { - /** The user's preferred locale e.g. 'en', 'es-ES' */ - preferredLocale: PropTypes.string, - - /** Actual content wrapped by this component */ - children: PropTypes.node.isRequired, - - /** The current user's personalDetails */ - currentUserPersonalDetails: PropTypes.shape({ - /** Timezone of the current user */ - timezone: PropTypes.shape({ - /** Value of the selected timezone */ - selected: PropTypes.string, - }), - }), -}; - -const localeProviderDefaultProps = { - preferredLocale: CONST.LOCALES.DEFAULT, - currentUserPersonalDetails: {}, -}; - -function LocaleContextProvider({children, currentUserPersonalDetails, preferredLocale}) { - const selectedTimezone = lodashGet(currentUserPersonalDetails, 'timezone.selected'); - - /** - * @param {String} phrase - * @param {Object} [variables] - * @returns {String} - */ - const translate = (phrase, variables) => Localize.translate(preferredLocale, phrase, variables); - - /** - * @param {Number} number - * @param {Intl.NumberFormatOptions} options - * @returns {String} - */ - const numberFormat = (number, options) => NumberFormatUtils.format(preferredLocale, number, options); - - /** - * @param {String} datetime - * @returns {String} - */ - const datetimeToRelative = (datetime) => DateUtils.datetimeToRelative(preferredLocale, datetime); - - /** - * @param {String} datetime - ISO-formatted datetime string - * @param {Boolean} [includeTimezone] - * @param {Boolean} isLowercase - * @returns {String} - */ - const datetimeToCalendarTime = (datetime, includeTimezone, isLowercase = false) => - DateUtils.datetimeToCalendarTime(preferredLocale, datetime, includeTimezone, selectedTimezone, isLowercase); - - /** - * @param {String} phoneNumber - * @returns {String} - */ - const formatPhoneNumber = (phoneNumber) => LocalePhoneNumber.formatPhoneNumber(phoneNumber); - - /** - * @param {String} digit - * @returns {String} - */ - const toLocaleDigit = (digit) => LocaleDigitUtils.toLocaleDigit(preferredLocale, digit); - - /** - * @param {String} localeDigit - * @returns {String} - */ - const fromLocaleDigit = (localeDigit) => LocaleDigitUtils.fromLocaleDigit(preferredLocale, localeDigit); - - /** - * The context this component exposes to child components - * @returns {object} translation util functions and locale - */ - const getContextValue = () => ({ - translate, - numberFormat, - datetimeToRelative, - datetimeToCalendarTime, - formatPhoneNumber, - toLocaleDigit, - fromLocaleDigit, - preferredLocale, - }); - - return {children}; -} - -LocaleContextProvider.propTypes = localeProviderPropTypes; -LocaleContextProvider.defaultProps = localeProviderDefaultProps; - -const Provider = compose( - withCurrentUserPersonalDetails, - withOnyx({ - preferredLocale: { - key: ONYXKEYS.NVP_PREFERRED_LOCALE, - }, - }), -)(LocaleContextProvider); - -Provider.displayName = 'withOnyx(LocaleContextProvider)'; - export default function withLocalize(WrappedComponent) { const WithLocalize = forwardRef((props, ref) => ( @@ -164,4 +47,4 @@ export default function withLocalize(WrappedComponent) { return WithLocalize; } -export {withLocalizePropTypes, Provider as LocaleContextProvider, LocaleContext}; +export {withLocalizePropTypes} \ No newline at end of file diff --git a/src/hooks/useLocalize.js b/src/hooks/useLocalize.js index 9ad5048729bd..f0a18758e0e9 100644 --- a/src/hooks/useLocalize.js +++ b/src/hooks/useLocalize.js @@ -1,5 +1,5 @@ import {useContext} from 'react'; -import {LocaleContext} from '../components/withLocalize'; +import {LocaleContext} from '../components/createLocaleContext'; export default function useLocalize() { return useContext(LocaleContext); diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js index 43090cf024e2..e38e6d50d519 100644 --- a/tests/utils/LHNTestUtils.js +++ b/tests/utils/LHNTestUtils.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {render} from '@testing-library/react-native'; import ComposeProviders from '../../src/components/ComposeProviders'; import OnyxProvider from '../../src/components/OnyxProvider'; -import {LocaleContextProvider} from '../../src/components/withLocalize'; +import {LocaleContextProvider} from '../../src/components/createLocaleContext'; import SidebarLinksData from '../../src/pages/home/sidebar/SidebarLinksData'; import {EnvironmentProvider} from '../../src/components/withEnvironment'; import CONST from '../../src/CONST'; From a4f1f064767020732d1b8ea57f9159f073c7c92b Mon Sep 17 00:00:00 2001 From: Maciej Dobosz Date: Wed, 6 Sep 2023 16:40:42 +0200 Subject: [PATCH 039/101] Missing semicolon --- src/components/withLocalize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/withLocalize.js b/src/components/withLocalize.js index f717b822f6ee..4687a2f9fe7f 100755 --- a/src/components/withLocalize.js +++ b/src/components/withLocalize.js @@ -47,4 +47,4 @@ export default function withLocalize(WrappedComponent) { return WithLocalize; } -export {withLocalizePropTypes} \ No newline at end of file +export {withLocalizePropTypes}; From f9144ed064807b0d5945c93d4b4bb45150352678 Mon Sep 17 00:00:00 2001 From: Oscar Franco Date: Tue, 12 Sep 2023 15:38:44 +0200 Subject: [PATCH 040/101] Fix main index import --- src/libs/E2E/reactNativeLaunchingTest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/E2E/reactNativeLaunchingTest.js b/src/libs/E2E/reactNativeLaunchingTest.js index 6836e9c6c296..13183c1044db 100644 --- a/src/libs/E2E/reactNativeLaunchingTest.js +++ b/src/libs/E2E/reactNativeLaunchingTest.js @@ -65,5 +65,5 @@ E2EClient.getTestConfig() // start the usual app Performance.markStart('regularAppStart'); -import '../../../appIndex'; +import '../../../index'; Performance.markEnd('regularAppStart'); From fd3c662cf8ef13758a52239db421ee8bfc7b2ae8 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 15 Sep 2023 10:14:34 -1000 Subject: [PATCH 041/101] Fix import --- src/libs/actions/QueuedOnyxUpdates.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/QueuedOnyxUpdates.js b/src/libs/actions/QueuedOnyxUpdates.js index bd83e7db3c01..d8e80613406e 100644 --- a/src/libs/actions/QueuedOnyxUpdates.js +++ b/src/libs/actions/QueuedOnyxUpdates.js @@ -1,5 +1,6 @@ -// In this file we manage a queue of Onyx updates while the SequentialQueue is processing. There are functions to get the updates and clear the queue after saving the updates. +import Onyx from 'react-native-onyx'; +// In this file we manage a queue of Onyx updates while the SequentialQueue is processing. There are functions to get the updates and clear the queue after saving the updates. let queuedOnyxUpdates = []; /** From b9df62987ccdd8047624fd49ba4104e6ff0267a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 19 Sep 2023 13:31:23 +0200 Subject: [PATCH 042/101] fix shell script --- scripts/shellUtils.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/shellUtils.sh b/scripts/shellUtils.sh index c6d21e9f14e1..4c9e2febc34d 100644 --- a/scripts/shellUtils.sh +++ b/scripts/shellUtils.sh @@ -72,13 +72,15 @@ get_abs_path() { done # Remove any trailing '/' - abs_path=$(echo "$abs_path" | sed 's:/*$::') + while [[ $abs_path == */ ]]; do + abs_path=${abs_path%/} + done # Special case for root [ -z "$abs_path" ] && abs_path="/" # Special case to remove any starting '//' when the input path was absolute - abs_path=$(echo "$abs_path" | sed 's:^//:/:') + abs_path=${abs_path/#\/\//\/} echo "$abs_path" -} +} \ No newline at end of file From 6a327f1ad1e80bf3c8238638687cfcecbe20aa11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Tue, 19 Sep 2023 16:37:41 +0200 Subject: [PATCH 043/101] added delete account error handling and delete modal visiblity fixx --- .../Contacts/ContactMethodDetailsPage.js | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index a0091e5c184b..62aac934afe6 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -230,6 +230,7 @@ class ContactMethodDetailsPage extends Component { const isDefaultContactMethod = this.props.session.email === loginData.partnerUserID; const hasMagicCodeBeenSent = lodashGet(this.props.loginList, [contactMethod, 'validateCodeSent'], false); const isFailedAddContactMethod = Boolean(lodashGet(loginData, 'errorFields.addedLogin')); + const isFailedRemovedContactMethod = !!lodashGet(loginData, 'errorFields.deletedLogin'); return ( this.validateCodeFormRef.current && this.validateCodeFormRef.current.focus()}> @@ -245,7 +246,7 @@ class ContactMethodDetailsPage extends Component { prompt={this.props.translate('contacts.removeAreYouSure')} confirmText={this.props.translate('common.yesContinue')} cancelText={this.props.translate('common.cancel')} - isVisible={this.state.isDeleteModalOpen} + isVisible={this.state.isDeleteModalOpen && !isDefaultContactMethod} danger /> {isFailedAddContactMethod && ( @@ -284,14 +285,25 @@ class ContactMethodDetailsPage extends Component { ) : null} {isDefaultContactMethod ? ( - User.clearContactMethodErrors(contactMethod, 'defaultLogin')} - > - {this.props.translate('contacts.yourDefaultContactMethod')} - + <> + User.clearContactMethodErrors(contactMethod, 'defaultLogin')} + > + {this.props.translate('contacts.yourDefaultContactMethod')} + + {isFailedRemovedContactMethod && ( + User.clearContactMethodErrors(contactMethod, 'deletedLogin')} + > + <> + + )} + ) : ( Date: Wed, 20 Sep 2023 14:54:22 +0200 Subject: [PATCH 044/101] feat: add React memo --- .storybook/preview.js | 2 +- src/App.js | 2 +- src/components/LocaleContextProvider.js | 127 ++++++++++++++++++++++++ src/components/createLocaleContext.js | 122 ----------------------- src/components/withLocalize.js | 2 +- src/hooks/useLocalize.js | 2 +- tests/utils/LHNTestUtils.js | 2 +- 7 files changed, 132 insertions(+), 127 deletions(-) create mode 100644 src/components/LocaleContextProvider.js delete mode 100644 src/components/createLocaleContext.js diff --git a/.storybook/preview.js b/.storybook/preview.js index 37e2e95bce4e..a989960794f2 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -6,7 +6,7 @@ import './fonts.css'; import ComposeProviders from '../src/components/ComposeProviders'; import HTMLEngineProvider from '../src/components/HTMLEngineProvider'; import OnyxProvider from '../src/components/OnyxProvider'; -import {LocaleContextProvider} from '../src/components/createLocaleContext'; +import {LocaleContextProvider} from '../src/components/LocaleContextProvider'; import {KeyboardStateProvider} from '../src/components/withKeyboardState'; import {EnvironmentProvider} from '../src/components/withEnvironment'; import {WindowDimensionsProvider} from '../src/components/withWindowDimensions'; diff --git a/src/App.js b/src/App.js index 301c518b9490..1d2e07345c24 100644 --- a/src/App.js +++ b/src/App.js @@ -9,7 +9,7 @@ import {PickerStateProvider} from 'react-native-picker-select'; import CustomStatusBar from './components/CustomStatusBar'; import ErrorBoundary from './components/ErrorBoundary'; import Expensify from './Expensify'; -import {LocaleContextProvider} from './components/createLocaleContext'; +import {LocaleContextProvider} from './components/LocaleContextProvider'; import OnyxProvider from './components/OnyxProvider'; import HTMLEngineProvider from './components/HTMLEngineProvider'; import PopoverContextProvider from './components/PopoverProvider'; diff --git a/src/components/LocaleContextProvider.js b/src/components/LocaleContextProvider.js new file mode 100644 index 000000000000..fc6dca4a092e --- /dev/null +++ b/src/components/LocaleContextProvider.js @@ -0,0 +1,127 @@ +import React, {createContext} from 'react'; +import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; +import lodashGet from 'lodash/get'; + +import ONYXKEYS from '../ONYXKEYS'; +import * as Localize from '../libs/Localize'; +import DateUtils from '../libs/DateUtils'; +import * as NumberFormatUtils from '../libs/NumberFormatUtils'; +import * as LocaleDigitUtils from '../libs/LocaleDigitUtils'; +import CONST from '../CONST'; +import compose from '../libs/compose'; +import withCurrentUserPersonalDetails from './withCurrentUserPersonalDetails'; +import * as LocalePhoneNumber from '../libs/LocalePhoneNumber'; + +const LocaleContext = createContext(null); + +const localeProviderPropTypes = { + /** The user's preferred locale e.g. 'en', 'es-ES' */ + preferredLocale: PropTypes.string, + + /** Actual content wrapped by this component */ + children: PropTypes.node.isRequired, + + /** The current user's personalDetails */ + currentUserPersonalDetails: PropTypes.shape({ + /** Timezone of the current user */ + timezone: PropTypes.shape({ + /** Value of the selected timezone */ + selected: PropTypes.string, + }), + }), +}; + +const localeProviderDefaultProps = { + preferredLocale: CONST.LOCALES.DEFAULT, + currentUserPersonalDetails: {}, +}; + +const LocaleContextProvider = React.memo( + ({children, currentUserPersonalDetails, preferredLocale}) => { + const selectedTimezone = lodashGet(currentUserPersonalDetails, 'timezone.selected'); + + /** + * @param {String} phrase + * @param {Object} [variables] + * @returns {String} + */ + const translate = (phrase, variables) => Localize.translate(preferredLocale, phrase, variables); + + /** + * @param {Number} number + * @param {Intl.NumberFormatOptions} options + * @returns {String} + */ + const numberFormat = (number, options) => NumberFormatUtils.format(preferredLocale, number, options); + + /** + * @param {String} datetime + * @returns {String} + */ + const datetimeToRelative = (datetime) => DateUtils.datetimeToRelative(preferredLocale, datetime); + + /** + * @param {String} datetime - ISO-formatted datetime string + * @param {Boolean} [includeTimezone] + * @param {Boolean} isLowercase + * @returns {String} + */ + const datetimeToCalendarTime = (datetime, includeTimezone, isLowercase = false) => + DateUtils.datetimeToCalendarTime(preferredLocale, datetime, includeTimezone, selectedTimezone, isLowercase); + + /** + * @param {String} phoneNumber + * @returns {String} + */ + const formatPhoneNumber = (phoneNumber) => LocalePhoneNumber.formatPhoneNumber(phoneNumber); + + /** + * @param {String} digit + * @returns {String} + */ + const toLocaleDigit = (digit) => LocaleDigitUtils.toLocaleDigit(preferredLocale, digit); + + /** + * @param {String} localeDigit + * @returns {String} + */ + const fromLocaleDigit = (localeDigit) => LocaleDigitUtils.fromLocaleDigit(preferredLocale, localeDigit); + + /** + * The context this component exposes to child components + * @returns {object} translation util functions and locale + */ + const getContextValue = () => ({ + translate, + numberFormat, + datetimeToRelative, + datetimeToCalendarTime, + formatPhoneNumber, + toLocaleDigit, + fromLocaleDigit, + preferredLocale, + }); + + return {children}; + }, + (prevProps, nextProps) => + nextProps.preferredLocale === prevProps.preferredLocale && + lodashGet(nextProps, 'currentUserPersonalDetails.timezone.selected') === lodashGet(prevProps, 'currentUserPersonalDetails.timezone.selected'), +); + +LocaleContextProvider.propTypes = localeProviderPropTypes; +LocaleContextProvider.defaultProps = localeProviderDefaultProps; + +const Provider = compose( + withCurrentUserPersonalDetails, + withOnyx({ + preferredLocale: { + key: ONYXKEYS.NVP_PREFERRED_LOCALE, + }, + }), +)(LocaleContextProvider); + +Provider.displayName = 'withOnyx(LocaleContextProvider)'; + +export {Provider as LocaleContextProvider, LocaleContext}; diff --git a/src/components/createLocaleContext.js b/src/components/createLocaleContext.js deleted file mode 100644 index be5bb9904b6a..000000000000 --- a/src/components/createLocaleContext.js +++ /dev/null @@ -1,122 +0,0 @@ -import React, {createContext} from 'react'; -import PropTypes from 'prop-types'; -import {withOnyx} from 'react-native-onyx'; -import lodashGet from 'lodash/get'; - -import ONYXKEYS from '../ONYXKEYS'; -import * as Localize from '../libs/Localize'; -import DateUtils from '../libs/DateUtils'; -import * as NumberFormatUtils from '../libs/NumberFormatUtils'; -import * as LocaleDigitUtils from '../libs/LocaleDigitUtils'; -import CONST from '../CONST'; -import compose from '../libs/compose'; -import withCurrentUserPersonalDetails from './withCurrentUserPersonalDetails'; -import * as LocalePhoneNumber from '../libs/LocalePhoneNumber'; - -const LocaleContext = createContext(null); - -const localeProviderPropTypes = { - /** The user's preferred locale e.g. 'en', 'es-ES' */ - preferredLocale: PropTypes.string, - - /** Actual content wrapped by this component */ - children: PropTypes.node.isRequired, - - /** The current user's personalDetails */ - currentUserPersonalDetails: PropTypes.shape({ - /** Timezone of the current user */ - timezone: PropTypes.shape({ - /** Value of the selected timezone */ - selected: PropTypes.string, - }), - }), -}; - -const localeProviderDefaultProps = { - preferredLocale: CONST.LOCALES.DEFAULT, - currentUserPersonalDetails: {}, -}; - -function LocaleContextProvider({children, currentUserPersonalDetails, preferredLocale}) { - const selectedTimezone = lodashGet(currentUserPersonalDetails, 'timezone.selected'); - - /** - * @param {String} phrase - * @param {Object} [variables] - * @returns {String} - */ - const translate = (phrase, variables) => Localize.translate(preferredLocale, phrase, variables); - - /** - * @param {Number} number - * @param {Intl.NumberFormatOptions} options - * @returns {String} - */ - const numberFormat = (number, options) => NumberFormatUtils.format(preferredLocale, number, options); - - /** - * @param {String} datetime - * @returns {String} - */ - const datetimeToRelative = (datetime) => DateUtils.datetimeToRelative(preferredLocale, datetime); - - /** - * @param {String} datetime - ISO-formatted datetime string - * @param {Boolean} [includeTimezone] - * @param {Boolean} isLowercase - * @returns {String} - */ - const datetimeToCalendarTime = (datetime, includeTimezone, isLowercase = false) => - DateUtils.datetimeToCalendarTime(preferredLocale, datetime, includeTimezone, selectedTimezone, isLowercase); - - /** - * @param {String} phoneNumber - * @returns {String} - */ - const formatPhoneNumber = (phoneNumber) => LocalePhoneNumber.formatPhoneNumber(phoneNumber); - - /** - * @param {String} digit - * @returns {String} - */ - const toLocaleDigit = (digit) => LocaleDigitUtils.toLocaleDigit(preferredLocale, digit); - - /** - * @param {String} localeDigit - * @returns {String} - */ - const fromLocaleDigit = (localeDigit) => LocaleDigitUtils.fromLocaleDigit(preferredLocale, localeDigit); - - /** - * The context this component exposes to child components - * @returns {object} translation util functions and locale - */ - const getContextValue = () => ({ - translate, - numberFormat, - datetimeToRelative, - datetimeToCalendarTime, - formatPhoneNumber, - toLocaleDigit, - fromLocaleDigit, - preferredLocale, - }); - - return {children}; -} - -LocaleContextProvider.propTypes = localeProviderPropTypes; -LocaleContextProvider.defaultProps = localeProviderDefaultProps; - -const Provider = compose( - withCurrentUserPersonalDetails, - withOnyx({ - preferredLocale: { - key: ONYXKEYS.NVP_PREFERRED_LOCALE, - }, - }), -)(LocaleContextProvider); - -Provider.displayName = 'withOnyx(LocaleContextProvider)'; - -export {Provider as LocaleContextProvider, LocaleContext}; diff --git a/src/components/withLocalize.js b/src/components/withLocalize.js index 4687a2f9fe7f..9daa0ffcebf6 100755 --- a/src/components/withLocalize.js +++ b/src/components/withLocalize.js @@ -1,6 +1,6 @@ import React, {forwardRef} from 'react'; import PropTypes from 'prop-types'; -import {LocaleContext} from './createLocaleContext'; +import {LocaleContext} from './LocaleContextProvider'; import getComponentDisplayName from '../libs/getComponentDisplayName'; const withLocalizePropTypes = { diff --git a/src/hooks/useLocalize.js b/src/hooks/useLocalize.js index f0a18758e0e9..7f7a610fca8b 100644 --- a/src/hooks/useLocalize.js +++ b/src/hooks/useLocalize.js @@ -1,5 +1,5 @@ import {useContext} from 'react'; -import {LocaleContext} from '../components/createLocaleContext'; +import {LocaleContext} from '../components/LocaleContextProvider'; export default function useLocalize() { return useContext(LocaleContext); diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js index e38e6d50d519..7cb69b23a578 100644 --- a/tests/utils/LHNTestUtils.js +++ b/tests/utils/LHNTestUtils.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {render} from '@testing-library/react-native'; import ComposeProviders from '../../src/components/ComposeProviders'; import OnyxProvider from '../../src/components/OnyxProvider'; -import {LocaleContextProvider} from '../../src/components/createLocaleContext'; +import {LocaleContextProvider} from '../../src/components/LocaleContextProvider'; import SidebarLinksData from '../../src/pages/home/sidebar/SidebarLinksData'; import {EnvironmentProvider} from '../../src/components/withEnvironment'; import CONST from '../../src/CONST'; From ddd63b5a135397a06f0cb1fd77b35f6f2ab3d1a5 Mon Sep 17 00:00:00 2001 From: lukemorawski <134388952+lukemorawski@users.noreply.github.com> Date: Wed, 20 Sep 2023 17:56:20 +0200 Subject: [PATCH 045/101] bool coercion by Boolean casting Co-authored-by: Michael (Mykhailo) Kravchenko --- src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index 62aac934afe6..d3c212bae8e9 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -230,7 +230,7 @@ class ContactMethodDetailsPage extends Component { const isDefaultContactMethod = this.props.session.email === loginData.partnerUserID; const hasMagicCodeBeenSent = lodashGet(this.props.loginList, [contactMethod, 'validateCodeSent'], false); const isFailedAddContactMethod = Boolean(lodashGet(loginData, 'errorFields.addedLogin')); - const isFailedRemovedContactMethod = !!lodashGet(loginData, 'errorFields.deletedLogin'); + const isFailedRemovedContactMethod = Boolean(lodashGet(loginData, 'errorFields.deletedLogin')); return ( this.validateCodeFormRef.current && this.validateCodeFormRef.current.focus()}> From d0cb1551b409f2c10cf9ea321aa442fa2756c58f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Wed, 20 Sep 2023 18:50:01 +0200 Subject: [PATCH 046/101] cleaner way of presenting default contact delete error --- .../Contacts/ContactMethodDetailsPage.js | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index d3c212bae8e9..2d9fb75cc983 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -285,25 +285,14 @@ class ContactMethodDetailsPage extends Component { ) : null} {isDefaultContactMethod ? ( - <> - User.clearContactMethodErrors(contactMethod, 'defaultLogin')} - > - {this.props.translate('contacts.yourDefaultContactMethod')} - - {isFailedRemovedContactMethod && ( - User.clearContactMethodErrors(contactMethod, 'deletedLogin')} - > - <> - - )} - + User.clearContactMethodErrors(contactMethod, isFailedRemovedContactMethod ? 'deletedLogin' : 'defaultLogin')} + > + {this.props.translate('contacts.yourDefaultContactMethod')} + ) : ( Date: Thu, 21 Sep 2023 09:36:28 +0200 Subject: [PATCH 047/101] add baseline building back + fix app path --- .../composite/buildAndroidAPK/action.yml | 4 +- .github/workflows/e2ePerformanceTests.yml | 55 +++++++++++++++++-- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/.github/actions/composite/buildAndroidAPK/action.yml b/.github/actions/composite/buildAndroidAPK/action.yml index 819234df0bc3..fc280ab2a223 100644 --- a/.github/actions/composite/buildAndroidAPK/action.yml +++ b/.github/actions/composite/buildAndroidAPK/action.yml @@ -13,7 +13,7 @@ runs: - uses: ruby/setup-ruby@eae47962baca661befdfd24e4d6c34ade04858f7 with: - ruby-version: '2.7' + ruby-version: "2.7" bundler-cache: true - uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef @@ -26,4 +26,4 @@ runs: uses: actions/upload-artifact@65d862660abb392b8c4a3d1195a2108db131dd05 with: name: ${{ inputs.ARTIFACT_NAME }} - path: android/app/build/outputs/apk/e2eRelease/app-e2eRelease.apk + path: android/app/build/outputs/apk/e2e/release/app-e2e-release.apk diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 35612eadbbae..10ca2420ed9d 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -16,6 +16,45 @@ on: required: true jobs: + buildBaseline: + runs-on: ubuntu-latest-xl + name: Build apk from latest release as a baseline + outputs: + VERSION: ${{ steps.getMostRecentRelease.outputs.VERSION }} + steps: + - uses: actions/checkout@v3 + + - name: Get most recent release version + id: getMostRecentRelease + run: echo "VERSION=$(gh release list --limit 1 | awk '{ print $1 }')" >> "$GITHUB_OUTPUT" + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Check if there's an existing artifact for this baseline + id: checkForExistingArtifact + uses: xSAVIKx/artifact-exists-action@3c5206b1411c0d2fc0840f56b7140646933d9d6a + with: + name: baseline-apk-${{ steps.getMostRecentRelease.outputs.VERSION }} + + - name: Skip build if there's already an existing artifact for the baseline + if: ${{ fromJSON(steps.checkForExistingArtifact.outputs.exists) }} + run: echo 'APK for baseline ${{ steps.getMostRecentRelease.outputs.VERSION }} already exists, reusing existing build' + + - name: Checkout "Baseline" commit (last release) + if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }} + run: | + git fetch origin tag ${{ steps.getMostRecentRelease.outputs.VERSION }} --no-tags --depth=1 + git switch --detach ${{ steps.getMostRecentRelease.outputs.VERSION }} + + - name: Configure MapBox SDK + run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} + + - name: Build APK + if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }} + uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main + with: + ARTIFACT_NAME: baseline-apk-${{ steps.getMostRecentRelease.outputs.VERSION }} + buildDelta: runs-on: ubuntu-latest-xl name: Build apk from delta ref @@ -89,6 +128,17 @@ jobs: - name: Make zip directory for everything to send to AWS Device Farm run: mkdir zip + - name: Download baseline APK + uses: actions/download-artifact@e9ef242655d12993efdcda9058dee2db83a2cb9b + id: downloadBaselineAPK + with: + name: baseline-apk-${{ needs.buildBaseline.outputs.VERSION }} + path: zip + + # The downloaded artifact will be a file named "app-e2e-release.apk" so we have to rename it + - name: Rename baseline APK + run: mv "${{steps.downloadBaselineAPK.outputs.download-path}}/app-e2e-release.apk" "${{steps.downloadBaselineAPK.outputs.download-path}}/app-e2eRelease-baseline.apk" + - name: Download delta APK uses: actions/download-artifact@e9ef242655d12993efdcda9058dee2db83a2cb9b id: downloadDeltaAPK @@ -97,10 +147,7 @@ jobs: path: zip - name: Rename delta APK - run: mv "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease.apk" "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease-compare.apk" - - - name: Copy Delta APK as compare for testing - run: mv "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease-compare.apk" "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease-baseline.apk" + run: mv "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2e-release.apk" "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease-compare.apk" - name: Copy e2e code into zip folder run: cp -r tests/e2e zip From 475d75ce4a8e08598c3f7820cd9fe015c35eb158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 21 Sep 2023 09:48:28 +0200 Subject: [PATCH 048/101] aws job depend on buildBaseline --- .github/workflows/e2ePerformanceTests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 10ca2420ed9d..bf30cc3ce213 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -120,7 +120,7 @@ jobs: runTestsInAWS: runs-on: ubuntu-latest - needs: [buildDelta] + needs: [buildBaseline, buildDelta] name: Run E2E tests in AWS device farm steps: - uses: actions/checkout@v3 From ca47840818c82d39a49d7edcf2a51b691070dafe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 21 Sep 2023 10:14:50 +0200 Subject: [PATCH 049/101] --allow-unrelated-histories --- .github/workflows/e2ePerformanceTests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index bf30cc3ce213..f7f1e5fc7ac7 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -96,7 +96,7 @@ jobs: if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} id: getMergeCommitShaIfUnmergedPR run: | - git merge --no-commit ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} + git merge --allow-unrelated-histories --no-commit ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} git checkout ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} env: GITHUB_TOKEN: ${{ github.token }} From d646cdfb1780eb57eb0753ca2cfd493facd08a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 21 Sep 2023 10:37:07 +0200 Subject: [PATCH 050/101] use absolute path to entry file --- fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index dac53193fdc6..b1babadd8f6b 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,7 +17,7 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"] = File.expand_path("../src/libs/E2E/reactNativeLaunchingTest.js", Dir.pwd) ENV["E2E_TESTING"]="true" gradle( From 1daca9d5d311ad8253ab2e226dbad1d7609fed06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 21 Sep 2023 12:04:31 +0200 Subject: [PATCH 051/101] dev: check for file --- fastlane/Fastfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index b1babadd8f6b..3e11d57a9529 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -20,6 +20,13 @@ platform :android do ENV["ENTRY_FILE"] = File.expand_path("../src/libs/E2E/reactNativeLaunchingTest.js", Dir.pwd) ENV["E2E_TESTING"]="true" + # Test if the entry file exists, otherwise fail early. If its there, log that we are good to proceed + if !File.file?(ENV["ENTRY_FILE"]) + UI.user_error!("E2E entry file not found at #{ENV["ENTRY_FILE"]}") + else + UI.success("E2E entry file found at #{ENV["ENTRY_FILE"]}") + end + gradle( project_dir: './android', task: ':app:assemble', From 3b31e1e43d4a16a2928a4358a7ef0dbb3e0ec2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 21 Sep 2023 12:14:10 +0200 Subject: [PATCH 052/101] dev: are the files there? --- .github/workflows/e2ePerformanceTests.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index f7f1e5fc7ac7..4d6c92a63389 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -113,6 +113,12 @@ jobs: - name: Configure MapBox SDK run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} + - name: List files + run: ls -la + + - name: List files src/ + run: ls -la src/ + - name: Build APK uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main with: From c0794bd8df65871d7fde7f0b507ea8e329065a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 21 Sep 2023 12:22:13 +0200 Subject: [PATCH 053/101] invoke command manually --- .github/actions/composite/buildAndroidAPK/action.yml | 2 +- .github/workflows/e2ePerformanceTests.yml | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/actions/composite/buildAndroidAPK/action.yml b/.github/actions/composite/buildAndroidAPK/action.yml index fc280ab2a223..8cc88e7af679 100644 --- a/.github/actions/composite/buildAndroidAPK/action.yml +++ b/.github/actions/composite/buildAndroidAPK/action.yml @@ -19,7 +19,7 @@ runs: - uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef - name: Build APK - run: npm run android-build-e2e + run: cd android && ENTRY_FILE="../src/libs/E2E/reactNativeLaunchingTest.js" ENVFILE="../tests/e2e/.env.e2e" E2E_TESTING=true ./gradlew :app:assembleE2eRelease shell: bash - name: Upload APK diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 4d6c92a63389..f7f1e5fc7ac7 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -113,12 +113,6 @@ jobs: - name: Configure MapBox SDK run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} - - name: List files - run: ls -la - - - name: List files src/ - run: ls -la src/ - - name: Build APK uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main with: From 6d1f82ff77f539160aa5eb3f72637bd26a6b5f33 Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Thu, 21 Sep 2023 13:51:07 +0200 Subject: [PATCH 054/101] fix: dont memo the whole function --- src/components/LocaleContextProvider.js | 132 ++++++++++++------------ 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/src/components/LocaleContextProvider.js b/src/components/LocaleContextProvider.js index fc6dca4a092e..767a23ba123a 100644 --- a/src/components/LocaleContextProvider.js +++ b/src/components/LocaleContextProvider.js @@ -1,4 +1,4 @@ -import React, {createContext} from 'react'; +import React, {createContext, useMemo} from 'react'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; import lodashGet from 'lodash/get'; @@ -37,62 +37,66 @@ const localeProviderDefaultProps = { currentUserPersonalDetails: {}, }; -const LocaleContextProvider = React.memo( - ({children, currentUserPersonalDetails, preferredLocale}) => { - const selectedTimezone = lodashGet(currentUserPersonalDetails, 'timezone.selected'); - - /** - * @param {String} phrase - * @param {Object} [variables] - * @returns {String} - */ - const translate = (phrase, variables) => Localize.translate(preferredLocale, phrase, variables); - - /** - * @param {Number} number - * @param {Intl.NumberFormatOptions} options - * @returns {String} - */ - const numberFormat = (number, options) => NumberFormatUtils.format(preferredLocale, number, options); - - /** - * @param {String} datetime - * @returns {String} - */ - const datetimeToRelative = (datetime) => DateUtils.datetimeToRelative(preferredLocale, datetime); - - /** - * @param {String} datetime - ISO-formatted datetime string - * @param {Boolean} [includeTimezone] - * @param {Boolean} isLowercase - * @returns {String} - */ - const datetimeToCalendarTime = (datetime, includeTimezone, isLowercase = false) => - DateUtils.datetimeToCalendarTime(preferredLocale, datetime, includeTimezone, selectedTimezone, isLowercase); - - /** - * @param {String} phoneNumber - * @returns {String} - */ - const formatPhoneNumber = (phoneNumber) => LocalePhoneNumber.formatPhoneNumber(phoneNumber); - - /** - * @param {String} digit - * @returns {String} - */ - const toLocaleDigit = (digit) => LocaleDigitUtils.toLocaleDigit(preferredLocale, digit); - - /** - * @param {String} localeDigit - * @returns {String} - */ - const fromLocaleDigit = (localeDigit) => LocaleDigitUtils.fromLocaleDigit(preferredLocale, localeDigit); - - /** - * The context this component exposes to child components - * @returns {object} translation util functions and locale - */ - const getContextValue = () => ({ +function LocaleContextProvider({children, currentUserPersonalDetails, preferredLocale}) { + const selectedTimezone = useMemo(() => lodashGet(currentUserPersonalDetails, 'timezone.selected'), [currentUserPersonalDetails]); + + /** + * @param {String} phrase + * @param {Object} [variables] + * @returns {String} + */ + const translate = useMemo(() => (phrase, variables) => Localize.translate(preferredLocale, phrase, variables), [preferredLocale]); + + /** + * @param {Number} number + * @param {Intl.NumberFormatOptions} options + * @returns {String} + */ + const numberFormat = useMemo(() => (number, options) => NumberFormatUtils.format(preferredLocale, number, options), [preferredLocale]); + + /** + * @param {String} datetime + * @returns {String} + */ + const datetimeToRelative = useMemo(() => (datetime) => DateUtils.datetimeToRelative(preferredLocale, datetime), [preferredLocale]); + + /** + * @param {String} datetime - ISO-formatted datetime string + * @param {Boolean} [includeTimezone] + * @param {Boolean} isLowercase + * @returns {String} + */ + const datetimeToCalendarTime = useMemo( + () => + (datetime, includeTimezone, isLowercase = false) => + DateUtils.datetimeToCalendarTime(preferredLocale, datetime, includeTimezone, selectedTimezone, isLowercase), + [preferredLocale, selectedTimezone], + ); + + /** + * @param {String} phoneNumber + * @returns {String} + */ + const formatPhoneNumber = useMemo(() => (phoneNumber) => LocalePhoneNumber.formatPhoneNumber(phoneNumber), []); + + /** + * @param {String} digit + * @returns {String} + */ + const toLocaleDigit = useMemo(() => (digit) => LocaleDigitUtils.toLocaleDigit(preferredLocale, digit), [preferredLocale]); + + /** + * @param {String} localeDigit + * @returns {String} + */ + const fromLocaleDigit = useMemo(() => (localeDigit) => LocaleDigitUtils.fromLocaleDigit(preferredLocale, localeDigit), [preferredLocale]); + + /** + * The context this component exposes to child components + * @returns {object} translation util functions and locale + */ + const contextValue = useMemo( + () => ({ translate, numberFormat, datetimeToRelative, @@ -101,14 +105,12 @@ const LocaleContextProvider = React.memo( toLocaleDigit, fromLocaleDigit, preferredLocale, - }); - - return {children}; - }, - (prevProps, nextProps) => - nextProps.preferredLocale === prevProps.preferredLocale && - lodashGet(nextProps, 'currentUserPersonalDetails.timezone.selected') === lodashGet(prevProps, 'currentUserPersonalDetails.timezone.selected'), -); + }), + [translate, numberFormat, datetimeToRelative, datetimeToCalendarTime, formatPhoneNumber, toLocaleDigit, fromLocaleDigit, preferredLocale], + ); + + return {children}; +} LocaleContextProvider.propTypes = localeProviderPropTypes; LocaleContextProvider.defaultProps = localeProviderDefaultProps; From b216223d8d38f75b2240eccec9e01bb5f8cd631c Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Thu, 21 Sep 2023 15:05:30 +0200 Subject: [PATCH 055/101] fix: easier impl --- src/components/LocaleContextProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/LocaleContextProvider.js b/src/components/LocaleContextProvider.js index 767a23ba123a..5afd0f4e3c75 100644 --- a/src/components/LocaleContextProvider.js +++ b/src/components/LocaleContextProvider.js @@ -77,7 +77,7 @@ function LocaleContextProvider({children, currentUserPersonalDetails, preferredL * @param {String} phoneNumber * @returns {String} */ - const formatPhoneNumber = useMemo(() => (phoneNumber) => LocalePhoneNumber.formatPhoneNumber(phoneNumber), []); + const formatPhoneNumber = LocalePhoneNumber.formatPhoneNumber; /** * @param {String} digit From 25d9c0a46439f39695b472c62f5796c22eb758cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 22 Sep 2023 12:32:24 +0200 Subject: [PATCH 056/101] revert change --- fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 3e11d57a9529..332a54aa14f7 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,7 +17,7 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"] = File.expand_path("../src/libs/E2E/reactNativeLaunchingTest.js", Dir.pwd) + ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" # Test if the entry file exists, otherwise fail early. If its there, log that we are good to proceed From 8e25f3dbdca6097a7d231ffeb90f54b3646e2665 Mon Sep 17 00:00:00 2001 From: Oscar Franco Date: Fri, 22 Sep 2023 12:46:57 +0200 Subject: [PATCH 057/101] Test a different path for entry file --- fastlane/Fastfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 332a54aa14f7..eced35198c95 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,11 +17,11 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="../src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" # Test if the entry file exists, otherwise fail early. If its there, log that we are good to proceed - if !File.file?(ENV["ENTRY_FILE"]) + if !File.exists?(ENV["ENTRY_FILE"]) UI.user_error!("E2E entry file not found at #{ENV["ENTRY_FILE"]}") else UI.success("E2E entry file found at #{ENV["ENTRY_FILE"]}") From 86d74905d3d44eb536f01fca811419fb843e28d0 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Mon, 25 Sep 2023 12:59:05 +0800 Subject: [PATCH 058/101] Add tmate --- .github/workflows/e2ePerformanceTests.yml | 10 ++++++++++ fastlane/Fastfile | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index f7f1e5fc7ac7..791c2e8ff075 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -49,6 +49,11 @@ jobs: - name: Configure MapBox SDK run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: true + - name: Build APK if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }} uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main @@ -113,6 +118,11 @@ jobs: - name: Configure MapBox SDK run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: true + - name: Build APK uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main with: diff --git a/fastlane/Fastfile b/fastlane/Fastfile index eced35198c95..8dd4875db833 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,7 +17,7 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="../src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="/src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" # Test if the entry file exists, otherwise fail early. If its there, log that we are good to proceed From 905b1806722eba78f9bf7f50a9871e444118778d Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Mon, 25 Sep 2023 13:15:31 +0800 Subject: [PATCH 059/101] Adjust tests --- .../composite/buildAndroidAPK/action.yml | 2 +- .github/workflows/e2ePerformanceTests.yml | 22 ++++++++++--------- fastlane/Fastfile | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.github/actions/composite/buildAndroidAPK/action.yml b/.github/actions/composite/buildAndroidAPK/action.yml index 8cc88e7af679..fc280ab2a223 100644 --- a/.github/actions/composite/buildAndroidAPK/action.yml +++ b/.github/actions/composite/buildAndroidAPK/action.yml @@ -19,7 +19,7 @@ runs: - uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef - name: Build APK - run: cd android && ENTRY_FILE="../src/libs/E2E/reactNativeLaunchingTest.js" ENVFILE="../tests/e2e/.env.e2e" E2E_TESTING=true ./gradlew :app:assembleE2eRelease + run: npm run android-build-e2e shell: bash - name: Upload APK diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 791c2e8ff075..5dbef071c720 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -49,17 +49,18 @@ jobs: - name: Configure MapBox SDK run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} - - name: Setup tmate session - uses: mxschmitt/action-tmate@v3 - with: - limit-access-to-actor: true - - name: Build APK if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }} uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main with: ARTIFACT_NAME: baseline-apk-${{ steps.getMostRecentRelease.outputs.VERSION }} + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: true + buildDelta: runs-on: ubuntu-latest-xl name: Build apk from delta ref @@ -118,16 +119,17 @@ jobs: - name: Configure MapBox SDK run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} - - name: Setup tmate session - uses: mxschmitt/action-tmate@v3 - with: - limit-access-to-actor: true - - name: Build APK uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main with: ARTIFACT_NAME: delta-apk-${{ steps.getDeltaRef.outputs.DELTA_REF }} + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: true + runTestsInAWS: runs-on: ubuntu-latest needs: [buildBaseline, buildDelta] diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 8dd4875db833..a5e4245269a8 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,7 +17,7 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="/src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" # Test if the entry file exists, otherwise fail early. If its there, log that we are good to proceed From e9038576d89105783abfb9c68a84b5868e126cf3 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Mon, 25 Sep 2023 13:40:48 +0800 Subject: [PATCH 060/101] Remove tmate, adjust file path --- .github/workflows/e2ePerformanceTests.yml | 12 ------------ fastlane/Fastfile | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 5dbef071c720..f7f1e5fc7ac7 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -55,12 +55,6 @@ jobs: with: ARTIFACT_NAME: baseline-apk-${{ steps.getMostRecentRelease.outputs.VERSION }} - - name: Setup tmate session - if: ${{ failure() }} - uses: mxschmitt/action-tmate@v3 - with: - limit-access-to-actor: true - buildDelta: runs-on: ubuntu-latest-xl name: Build apk from delta ref @@ -124,12 +118,6 @@ jobs: with: ARTIFACT_NAME: delta-apk-${{ steps.getDeltaRef.outputs.DELTA_REF }} - - name: Setup tmate session - if: ${{ failure() }} - uses: mxschmitt/action-tmate@v3 - with: - limit-access-to-actor: true - runTestsInAWS: runs-on: ubuntu-latest needs: [buildBaseline, buildDelta] diff --git a/fastlane/Fastfile b/fastlane/Fastfile index a5e4245269a8..eced35198c95 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,7 +17,7 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="../src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" # Test if the entry file exists, otherwise fail early. If its there, log that we are good to proceed From 7f8fc198028b08bbf90c8b9c8fb2643ce60a0bea Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Mon, 25 Sep 2023 14:16:25 +0800 Subject: [PATCH 061/101] Add more debugging --- fastlane/Fastfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index eced35198c95..9926f60d9cae 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,11 +17,12 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="../src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" - # Test if the entry file exists, otherwise fail early. If its there, log that we are good to proceed - if !File.exists?(ENV["ENTRY_FILE"]) + UI.success("Building E2E APK #{ENV["ENTRY_FILE"]}") + + if !File.exist?(ENV["ENTRY_FILE"]) UI.user_error!("E2E entry file not found at #{ENV["ENTRY_FILE"]}") else UI.success("E2E entry file found at #{ENV["ENTRY_FILE"]}") From e3bc7ad37df31422b7c405a3fc60a0acfbea25d3 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Mon, 25 Sep 2023 14:17:28 +0800 Subject: [PATCH 062/101] Add tmate back in --- .github/workflows/e2ePerformanceTests.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index f7f1e5fc7ac7..5dbef071c720 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -55,6 +55,12 @@ jobs: with: ARTIFACT_NAME: baseline-apk-${{ steps.getMostRecentRelease.outputs.VERSION }} + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: true + buildDelta: runs-on: ubuntu-latest-xl name: Build apk from delta ref @@ -118,6 +124,12 @@ jobs: with: ARTIFACT_NAME: delta-apk-${{ steps.getDeltaRef.outputs.DELTA_REF }} + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: true + runTestsInAWS: runs-on: ubuntu-latest needs: [buildBaseline, buildDelta] From c18e19bda3421bf16a41bff7dbffada3c704d935 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Mon, 25 Sep 2023 15:03:15 +0800 Subject: [PATCH 063/101] Remove file check --- fastlane/Fastfile | 8 -------- 1 file changed, 8 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 9926f60d9cae..dac53193fdc6 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -20,14 +20,6 @@ platform :android do ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" - UI.success("Building E2E APK #{ENV["ENTRY_FILE"]}") - - if !File.exist?(ENV["ENTRY_FILE"]) - UI.user_error!("E2E entry file not found at #{ENV["ENTRY_FILE"]}") - else - UI.success("E2E entry file found at #{ENV["ENTRY_FILE"]}") - end - gradle( project_dir: './android', task: ':app:assemble', From 50f6401e0a6004e539280809bfc48ea25a65a9c1 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Mon, 25 Sep 2023 15:34:41 +0800 Subject: [PATCH 064/101] Checkout test branch --- .github/workflows/e2ePerformanceTests.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 5dbef071c720..587cba13ebe6 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -43,8 +43,13 @@ jobs: - name: Checkout "Baseline" commit (last release) if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }} run: | - git fetch origin tag ${{ steps.getMostRecentRelease.outputs.VERSION }} --no-tags --depth=1 - git switch --detach ${{ steps.getMostRecentRelease.outputs.VERSION }} + git fetch origin andrew-fix-e2e-fork + git checkout andrew-fix-e2e-fork + +# TODO: Uncomment before merging +# run: | +# git fetch origin tag ${{ steps.getMostRecentRelease.outputs.VERSION }} --no-tags --depth=1 +# git switch --detach ${{ steps.getMostRecentRelease.outputs.VERSION }} - name: Configure MapBox SDK run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} From 049cccda0f2e05e78552f55524212e72adf3816c Mon Sep 17 00:00:00 2001 From: Nam Le Date: Mon, 25 Sep 2023 17:03:02 +0700 Subject: [PATCH 065/101] update get contract method from url when open deep link --- src/CONST.ts | 2 ++ .../Contacts/ContactMethodDetailsPage.js | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 3a198aca2c8c..e3da90c3428c 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1252,6 +1252,8 @@ const CONST = { DATE_TIME_FORMAT: /^\d{2}-\d{2} \d{2}:\d{2} [AP]M$/, ATTACHMENT_ROUTE: /\/r\/(\d*)\/attachment/, ILLEGAL_FILENAME_CHARACTERS: /\/|<|>|\*|"|:|\?|\\|\|/g, + + ENCODE_PERCENT_CHARACTER: /%(25)+/g, }, PRONOUNS: { diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index b8c817350a38..79d5f96aaefb 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -25,6 +25,7 @@ import ValidateCodeForm from './ValidateCodeForm'; import ROUTES from '../../../../ROUTES'; import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator'; import FullPageNotFoundView from '../../../../components/BlockingViews/FullPageNotFoundView'; +import CONST from '../../../../CONST'; const propTypes = { /* Onyx Props */ @@ -131,7 +132,22 @@ class ContactMethodDetailsPage extends Component { * @returns {string} */ getContactMethod() { - return decodeURIComponent(lodashGet(this.props.route, 'params.contactMethod')); + const contactMethod = lodashGet(this.props.route, 'params.contactMethod'); + + // We find the number of times the url is encoded based on the last % sign and remove them. + const lastPercentIndex = contactMethod.lastIndexOf('%'); + const encodePercents = contactMethod.substring(lastPercentIndex).match(new RegExp('25', 'g')); + let numberEncodePercents = encodePercents ? encodePercents.length : 0; + const beforeAtSign = contactMethod.substring(0, lastPercentIndex).replace(CONST.REGEX.ENCODE_PERCENT_CHARACTER, (match) => { + if (numberEncodePercents > 0) { + numberEncodePercents--; + return '%'; + } + return match; + }); + const afterAtSign = contactMethod.substring(lastPercentIndex).replace(CONST.REGEX.ENCODE_PERCENT_CHARACTER, '%'); + + return decodeURIComponent(beforeAtSign + afterAtSign); } /** From 82e45e999032362051ca71740c6b6e63e4fbc436 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Tue, 26 Sep 2023 11:30:52 +0900 Subject: [PATCH 066/101] Use workflow from my PR --- .github/workflows/e2ePerformanceTests.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 587cba13ebe6..405e0a5b4a59 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -56,7 +56,9 @@ jobs: - name: Build APK if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }} - uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main + # TODO: Change back before merging: + #uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main + uses: Expensify/App/.github/actions/composite/buildAndroidAPK@andrew-fix-e2e-fork with: ARTIFACT_NAME: baseline-apk-${{ steps.getMostRecentRelease.outputs.VERSION }} @@ -125,7 +127,9 @@ jobs: run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} - name: Build APK - uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main + # TODO: Change back before merging: + #uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main + uses: Expensify/App/.github/actions/composite/buildAndroidAPK@andrew-fix-e2e-fork with: ARTIFACT_NAME: delta-apk-${{ steps.getDeltaRef.outputs.DELTA_REF }} From b769d37337b95369a7cf6b498640c38bc5235803 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Tue, 26 Sep 2023 12:56:52 +0900 Subject: [PATCH 067/101] Remove testing todos --- .github/workflows/e2ePerformanceTests.yml | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 405e0a5b4a59..c69c2882e3d0 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -43,22 +43,15 @@ jobs: - name: Checkout "Baseline" commit (last release) if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }} run: | - git fetch origin andrew-fix-e2e-fork - git checkout andrew-fix-e2e-fork - -# TODO: Uncomment before merging -# run: | -# git fetch origin tag ${{ steps.getMostRecentRelease.outputs.VERSION }} --no-tags --depth=1 -# git switch --detach ${{ steps.getMostRecentRelease.outputs.VERSION }} + git fetch origin tag ${{ steps.getMostRecentRelease.outputs.VERSION }} --no-tags --depth=1 + git switch --detach ${{ steps.getMostRecentRelease.outputs.VERSION }} - name: Configure MapBox SDK run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} - name: Build APK if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }} - # TODO: Change back before merging: - #uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main - uses: Expensify/App/.github/actions/composite/buildAndroidAPK@andrew-fix-e2e-fork + uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main with: ARTIFACT_NAME: baseline-apk-${{ steps.getMostRecentRelease.outputs.VERSION }} @@ -127,18 +120,10 @@ jobs: run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} - name: Build APK - # TODO: Change back before merging: - #uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main - uses: Expensify/App/.github/actions/composite/buildAndroidAPK@andrew-fix-e2e-fork + uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main with: ARTIFACT_NAME: delta-apk-${{ steps.getDeltaRef.outputs.DELTA_REF }} - - name: Setup tmate session - if: ${{ failure() }} - uses: mxschmitt/action-tmate@v3 - with: - limit-access-to-actor: true - runTestsInAWS: runs-on: ubuntu-latest needs: [buildBaseline, buildDelta] From 7539d7be8acf1f8296e94515f7391ec98f808f49 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Tue, 26 Sep 2023 13:04:24 +0900 Subject: [PATCH 068/101] Remove more debugging code --- .github/workflows/e2ePerformanceTests.yml | 6 ------ tests/e2e/config.local.js | 6 ++---- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index c69c2882e3d0..f7f1e5fc7ac7 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -55,12 +55,6 @@ jobs: with: ARTIFACT_NAME: baseline-apk-${{ steps.getMostRecentRelease.outputs.VERSION }} - - name: Setup tmate session - if: ${{ failure() }} - uses: mxschmitt/action-tmate@v3 - with: - limit-access-to-actor: true - buildDelta: runs-on: ubuntu-latest-xl name: Build apk from delta ref diff --git a/tests/e2e/config.local.js b/tests/e2e/config.local.js index 97ccdc91312b..0c38c3f1056f 100644 --- a/tests/e2e/config.local.js +++ b/tests/e2e/config.local.js @@ -4,9 +4,7 @@ module.exports = { WARM_UP_RUNS: 1, RUNS: 8, APP_PATHS: { - // baseline: './android/app/build/outputs/apk/e2e/release/app-e2e-release.apk', - baseline: './android/app/build/outputs/apk/development/debug/app-development-debug.apk', - // compare: './android/app/build/outputs/apk/e2e/release/app-e2e-release.apk', - compare: './android/app/build/outputs/apk/development/debug/app-development-debug.apk', + baseline: './android/app/build/outputs/apk/e2e/release/app-e2e-release.apk', + compare: './android/app/build/outputs/apk/e2e/release/app-e2e-release.apk', }, }; From 917c29263b00c12c7b0548e4132ee2796de5d9d9 Mon Sep 17 00:00:00 2001 From: Manan Date: Tue, 26 Sep 2023 10:53:18 +0530 Subject: [PATCH 069/101] Fix Green drag and drop area --- src/pages/EditRequestReceiptPage.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/EditRequestReceiptPage.js b/src/pages/EditRequestReceiptPage.js index f45085a052e9..c5dd69624159 100644 --- a/src/pages/EditRequestReceiptPage.js +++ b/src/pages/EditRequestReceiptPage.js @@ -37,11 +37,11 @@ function EditRequestReceiptPage({route, transactionID}) { shouldEnableMaxHeight testID={EditRequestReceiptPage.displayName} > - + Date: Tue, 26 Sep 2023 14:51:54 +0900 Subject: [PATCH 070/101] Remove one other todo we confirmed works --- tests/e2e/testRunner.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/e2e/testRunner.js b/tests/e2e/testRunner.js index d945f693ea25..2a5aee78715f 100644 --- a/tests/e2e/testRunner.js +++ b/tests/e2e/testRunner.js @@ -117,7 +117,6 @@ const runTestsOnBranch = async (baselineOrCompare, branch) => { const tempDir = `${config.OUTPUT_DIR}/temp`; const tempBundlePath = `${tempDir}/index.android.bundle`; await execAsync(`rm -rf ${tempDir} && mkdir ${tempDir}`); - // TODO: test if that breaks support for the env file await execAsync(`E2E_TESTING=true npx react-native bundle --platform android --dev false --entry-file ${config.ENTRY_FILE} --bundle-output ${tempBundlePath}`); // Repackage the existing native app with the new bundle From 958e489e74bf64cb75112bb450ab335746ba52cd Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Tue, 26 Sep 2023 09:41:33 +0200 Subject: [PATCH 071/101] refactor: migrated EnablePaymentsPage to function component --- .../EnablePayments/EnablePaymentsPage.js | 123 +++++++++--------- 1 file changed, 58 insertions(+), 65 deletions(-) diff --git a/src/pages/EnablePayments/EnablePaymentsPage.js b/src/pages/EnablePayments/EnablePaymentsPage.js index 064f9371e46a..4b0210e9ec71 100644 --- a/src/pages/EnablePayments/EnablePaymentsPage.js +++ b/src/pages/EnablePayments/EnablePaymentsPage.js @@ -1,5 +1,5 @@ import _ from 'underscore'; -import React from 'react'; +import React, {useEffect} from 'react'; import {withOnyx} from 'react-native-onyx'; import ScreenWrapper from '../../components/ScreenWrapper'; import * as Wallet from '../../libs/actions/Wallet'; @@ -7,8 +7,6 @@ import ONYXKEYS from '../../ONYXKEYS'; import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator'; import CONST from '../../CONST'; import userWalletPropTypes from './userWalletPropTypes'; -import {withNetwork} from '../../components/OnyxProvider'; -import networkPropTypes from '../../components/networkPropTypes'; // Steps import OnfidoStep from './OnfidoStep'; @@ -17,94 +15,89 @@ import TermsStep from './TermsStep'; import ActivateStep from './ActivateStep'; import HeaderWithBackButton from '../../components/HeaderWithBackButton'; import FailedKYC from './FailedKYC'; -import compose from '../../libs/compose'; -import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import Navigation from '../../libs/Navigation/Navigation'; import ROUTES from '../../ROUTES'; +import useLocalize from '../../hooks/useLocalize'; +import useNetwork from '../../hooks/useNetwork'; +import usePrevious from '../../hooks/usePrevious'; const propTypes = { - /** Information about the network from Onyx */ - network: networkPropTypes.isRequired, - /** The user's wallet */ userWallet: userWalletPropTypes, - - ...withLocalizePropTypes, }; const defaultProps = { userWallet: {}, }; -class EnablePaymentsPage extends React.Component { - componentDidMount() { - Wallet.openEnablePaymentsPage(); - } +function EnablePaymentsPage({userWallet}) { + const {translate} = useLocalize(); + const {isOffline} = useNetwork(); - componentDidUpdate(prevProps) { - if (!prevProps.network.isOffline || this.props.network.isOffline) { + useEffect(() => { + if (isOffline) { return; } Wallet.openEnablePaymentsPage(); - } + }, [isOffline]); - render() { - if (_.isEmpty(this.props.userWallet)) { - return ; - } - - return ( - - {() => { - if (this.props.userWallet.errorCode === CONST.WALLET.ERROR.KYC) { - return ( - <> - Navigation.goBack(ROUTES.SETTINGS_WALLET)} - /> - - - ); - } - - if (this.props.userWallet.shouldShowWalletActivationSuccess) { - return ; - } - - const currentStep = this.props.userWallet.currentStep || CONST.WALLET.STEP.ADDITIONAL_DETAILS; + if (_.isEmpty(userWallet)) { + return ; + } + return ( + + {() => { + if (userWallet.errorCode === CONST.WALLET.ERROR.KYC) { return ( <> - {(currentStep === CONST.WALLET.STEP.ADDITIONAL_DETAILS || currentStep === CONST.WALLET.STEP.ADDITIONAL_DETAILS_KBA) && } - {currentStep === CONST.WALLET.STEP.ONFIDO && } - {currentStep === CONST.WALLET.STEP.TERMS && } - {currentStep === CONST.WALLET.STEP.ACTIVATE && } + Navigation.goBack(ROUTES.SETTINGS_WALLET)} + /> + ); - }} - - ); - } + } + + if (userWallet.shouldShowWalletActivationSuccess) { + return ; + } + + const currentStep = userWallet.currentStep || CONST.WALLET.STEP.ADDITIONAL_DETAILS; + + switch (currentStep) { + case CONST.WALLET.STEP.ADDITIONAL_DETAILS: + case CONST.WALLET.STEP.ADDITIONAL_DETAILS_KBA: + return ; + case CONST.WALLET.STEP.ONFIDO: + return ; + case CONST.WALLET.STEP.TERMS: + return ; + case CONST.WALLET.STEP.ACTIVATE: + return ; + default: + return null; + } + }} + + ); } +EnablePaymentsPage.displayName = 'EnablePaymentsPage'; EnablePaymentsPage.propTypes = propTypes; EnablePaymentsPage.defaultProps = defaultProps; -export default compose( - withLocalize, - withOnyx({ - userWallet: { - key: ONYXKEYS.USER_WALLET, +export default withOnyx({ + userWallet: { + key: ONYXKEYS.USER_WALLET, - // We want to refresh the wallet each time the user attempts to activate the wallet so we won't use the - // stored values here. - initWithStoredValues: false, - }, - }), - withNetwork(), -)(EnablePaymentsPage); + // We want to refresh the wallet each time the user attempts to activate the wallet so we won't use the + // stored values here. + initWithStoredValues: false, + }, +})(EnablePaymentsPage); From 37a2c5e6d52199d0590236eb709d2a78731d381f Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Tue, 26 Sep 2023 09:41:57 +0200 Subject: [PATCH 072/101] refactor: migrated EnablePaymentsPage to function component --- src/pages/EnablePayments/EnablePaymentsPage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/EnablePayments/EnablePaymentsPage.js b/src/pages/EnablePayments/EnablePaymentsPage.js index 4b0210e9ec71..773dfe8b5df7 100644 --- a/src/pages/EnablePayments/EnablePaymentsPage.js +++ b/src/pages/EnablePayments/EnablePaymentsPage.js @@ -19,7 +19,6 @@ import Navigation from '../../libs/Navigation/Navigation'; import ROUTES from '../../ROUTES'; import useLocalize from '../../hooks/useLocalize'; import useNetwork from '../../hooks/useNetwork'; -import usePrevious from '../../hooks/usePrevious'; const propTypes = { /** The user's wallet */ From 11c04869e9d546100d60936d44b5a2601bb16102 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Tue, 26 Sep 2023 19:20:25 +0200 Subject: [PATCH 073/101] Fix Split Bill - Number keeps on changing its initials --- .../MoneyRequestParticipantsSelector.js | 27 +++---------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js index 170ee042bffa..4b2eaf183596 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js @@ -143,7 +143,10 @@ function MoneyRequestParticipantsSelector({ if (newChatOptions.userToInvite && !OptionsListUtils.isCurrentUser(newChatOptions.userToInvite)) { newSections.push({ undefined, - data: [newChatOptions.userToInvite], + data: _.map([newChatOptions.userToInvite], (participant) => { + const isPolicyExpenseChat = lodashGet(participant, 'isPolicyExpenseChat', false); + return isPolicyExpenseChat ? OptionsListUtils.getPolicyExpenseReportOption(participant) : OptionsListUtils.getParticipantsOption(participant, personalDetails); + }), shouldShow: true, indexOffset, }); @@ -201,28 +204,6 @@ function MoneyRequestParticipantsSelector({ } onAddParticipants(newSelectedOptions); - - const chatOptions = OptionsListUtils.getFilteredOptions( - reports, - personalDetails, - betas, - isOptionInList ? searchTerm : '', - newSelectedOptions, - CONST.EXPENSIFY_EMAILS, - - // If we are using this component in the "Request money" flow then we pass the includeOwnedWorkspaceChats argument so that the current user - // sees the option to request money from their admin on their own Workspace Chat. - iouType === CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, - - // We don't want to include any P2P options like personal details or reports that are not workspace chats for certain features. - !isDistanceRequest, - ); - - setNewChatOptions({ - recentReports: chatOptions.recentReports, - personalDetails: chatOptions.personalDetails, - userToInvite: chatOptions.userToInvite, - }); }, [participants, onAddParticipants, reports, personalDetails, betas, searchTerm, iouType, isDistanceRequest], ); From c8baa3c7c1deffa3e95247d876623c0b0d8a06bd Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 26 Sep 2023 23:07:03 +0530 Subject: [PATCH 074/101] fix: subcategories for policy and domain settings --- .../expensify-classic/policy-and-domain-settings/Admins.md | 5 ----- .../policy-and-domain-settings/Domain-Admins.md | 5 ----- .../policy-and-domain-settings/Domain-Members.md | 5 ----- .../expensify-classic/policy-and-domain-settings/Overview.md | 5 ----- .../expensify-classic/policy-and-domain-settings/Reports.md | 5 ----- .../expensify-classic/policy-and-domain-settings/Trips.md | 5 ----- .../policy-and-domain-settings/reports/Currency.md | 5 +++++ .../reports/Report-Fields-And-Titles.md | 5 +++++ .../policy-and-domain-settings/reports/Scheduled-Submit.md | 5 +++++ 9 files changed, 15 insertions(+), 30 deletions(-) delete mode 100644 docs/articles/expensify-classic/policy-and-domain-settings/Admins.md delete mode 100644 docs/articles/expensify-classic/policy-and-domain-settings/Domain-Admins.md delete mode 100644 docs/articles/expensify-classic/policy-and-domain-settings/Domain-Members.md delete mode 100644 docs/articles/expensify-classic/policy-and-domain-settings/Overview.md delete mode 100644 docs/articles/expensify-classic/policy-and-domain-settings/Reports.md delete mode 100644 docs/articles/expensify-classic/policy-and-domain-settings/Trips.md create mode 100644 docs/articles/expensify-classic/policy-and-domain-settings/reports/Currency.md create mode 100644 docs/articles/expensify-classic/policy-and-domain-settings/reports/Report-Fields-And-Titles.md create mode 100644 docs/articles/expensify-classic/policy-and-domain-settings/reports/Scheduled-Submit.md diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Admins.md b/docs/articles/expensify-classic/policy-and-domain-settings/Admins.md deleted file mode 100644 index cea96cfe2057..000000000000 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Admins.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Admins -description: Admins ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Admins.md b/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Admins.md deleted file mode 100644 index 3ee1c8656b4b..000000000000 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Admins.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Members.md b/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Members.md deleted file mode 100644 index 3ee1c8656b4b..000000000000 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Members.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Overview.md b/docs/articles/expensify-classic/policy-and-domain-settings/Overview.md deleted file mode 100644 index 3ee1c8656b4b..000000000000 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Overview.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Reports.md b/docs/articles/expensify-classic/policy-and-domain-settings/Reports.md deleted file mode 100644 index 3ee1c8656b4b..000000000000 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Reports.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Trips.md b/docs/articles/expensify-classic/policy-and-domain-settings/Trips.md deleted file mode 100644 index 3ee1c8656b4b..000000000000 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Trips.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/reports/Currency.md b/docs/articles/expensify-classic/policy-and-domain-settings/reports/Currency.md new file mode 100644 index 000000000000..e5c9096fa610 --- /dev/null +++ b/docs/articles/expensify-classic/policy-and-domain-settings/reports/Currency.md @@ -0,0 +1,5 @@ +--- +title: Currency +description: Currency +--- +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/reports/Report-Fields-And-Titles.md b/docs/articles/expensify-classic/policy-and-domain-settings/reports/Report-Fields-And-Titles.md new file mode 100644 index 000000000000..47b96f495a1c --- /dev/null +++ b/docs/articles/expensify-classic/policy-and-domain-settings/reports/Report-Fields-And-Titles.md @@ -0,0 +1,5 @@ +--- +title: Report Fields & Titles +description: Report Fields & Titles +--- +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/reports/Scheduled-Submit.md b/docs/articles/expensify-classic/policy-and-domain-settings/reports/Scheduled-Submit.md new file mode 100644 index 000000000000..78471e6c3906 --- /dev/null +++ b/docs/articles/expensify-classic/policy-and-domain-settings/reports/Scheduled-Submit.md @@ -0,0 +1,5 @@ +--- +title: Scheduled Submit +description: Scheduled Submit +--- +## Resource Coming Soon! From 126a7562eeae28258e4d2a0722004241a0db0048 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 26 Sep 2023 23:08:06 +0530 Subject: [PATCH 075/101] add section for Reports --- .../hubs/policy-and-domain-settings/reports.html | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/expensify-classic/hubs/policy-and-domain-settings/reports.html diff --git a/docs/expensify-classic/hubs/policy-and-domain-settings/reports.html b/docs/expensify-classic/hubs/policy-and-domain-settings/reports.html new file mode 100644 index 000000000000..86641ee60b7d --- /dev/null +++ b/docs/expensify-classic/hubs/policy-and-domain-settings/reports.html @@ -0,0 +1,5 @@ +--- +layout: default +--- + +{% include section.html %} From 3b06da5cb56375c6de73bb6a1c509a485abf0813 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Tue, 26 Sep 2023 19:44:03 +0200 Subject: [PATCH 076/101] Update fix --- .../MoneyRequestParticipantsSelector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js index 4b2eaf183596..05b206ce4147 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js @@ -205,7 +205,7 @@ function MoneyRequestParticipantsSelector({ onAddParticipants(newSelectedOptions); }, - [participants, onAddParticipants, reports, personalDetails, betas, searchTerm, iouType, isDistanceRequest], + [participants, onAddParticipants], ); const headerMessage = OptionsListUtils.getHeaderMessage( From 21263f16ab32f23499e5a31e9141abb47a86304d Mon Sep 17 00:00:00 2001 From: Matt Moore <46995600+muttmuure@users.noreply.github.com> Date: Wed, 27 Sep 2023 15:01:53 +0800 Subject: [PATCH 077/101] Update Vacation-Delegate.md --- .../Vacation-Delegate.md | 54 +++++++++++++++++-- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate.md b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate.md index e107734216f5..7c21b12a83e1 100644 --- a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate.md +++ b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate.md @@ -1,8 +1,54 @@ --- -title: Coming Soon -description: Coming Soon +title: Vacation Delegate +description: In Expensify, a vacation delegate is someone you choose to act on your behalf when you're on vacation or taking personal time off. --- -## Resource Coming Soon! + +# Overview + +A delegate is someone who can handle approving expense reports for you, which is especially useful when you're out of the office! + +In Expensify, a **Vacation Delegate** is someone you choose to act on your behalf when you're on vacation or taking personal time off. They will approve expense reports just like you would, and everything moves forward as usual afterward. + +The system keeps a detailed audit trail, showing exactly when your delegate stepped in to approve a report for you. And if your delegate also goes on vacation, they can have their own delegate, so reports keep getting approved. + +By using this feature, you ensure that all reports get the approvals they need, even when you're not around. + +# How to use Vacation Delegate + +If you're planning to take some time off, you can use the **Vacation Delegate** feature to assign someone to approve expense reports for you. The reports will continue on their usual path as if you had approved them yourself. + +## Set a Vacation Delegate for yourself + +1. Go to the Expensify website (note: you can't do this from the mobile app). +2. Navigate to **Settings > Your Account > Account Details** and scroll down to find **Vacation Delegate**. +3. Enter the email address of the person you're designating as your delegate and click **Set Delegate**. + +Voila! You've set a vacation delegate. Any reports that usually come to you will now go to your delegate instead. When you return, you can easily remove the delegate by clicking a link at the top of the Expensify homepage. + +## Setting a Vacation Delegate as a Domain Admin + +1. Head to **Settings > Domains > [Your Domain Name] > Domain Members > Edit Settings** +2. Enter the delegate's email address and click **Save.** + +Your delegate's actions will be noted in the history and comments of each report they approve, so you can keep track of what happened while you were away. + +# Deep Dive + +## An audit trail of delegate actions + +The system records every action your vacation delegate takes on your behalf in the **Report History and Comments**. So, you can see when they approved an expense report for you. + +# FAQs + +## Why can't my Vacation Delegate reimburse reports that they approve? + +If your **Vacation Delegate** also needs to reimburse reports on your behalf whilst you're away, they'll also need access to the reimbursement account. + +If they do not have access to the reimbursement account used on your workspace, they won’t have the option to reimburse reports, even as your **Vacation Delegate**. + +## What if my Vacation Delegate is also on vacation? + +Don't worry, your delegate can also pick their own **Vacation Delegate**. This way, expense reports continue to get approved even if multiple people are away. + -Kayak.md Lyft.md TrainLine.md TravelPerk.md Trip Actions.md TripCatcher.md Uber.md \ No newline at end of file From e37a9cc28ecafc51b3631a021d144fb3b4755d28 Mon Sep 17 00:00:00 2001 From: staszekscp Date: Wed, 27 Sep 2023 11:51:42 +0200 Subject: [PATCH 078/101] fix error validation --- src/components/Form/FormProvider.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Form/FormProvider.js b/src/components/Form/FormProvider.js index 408f8c2c2b7f..68291de55fb2 100644 --- a/src/components/Form/FormProvider.js +++ b/src/components/Form/FormProvider.js @@ -108,6 +108,7 @@ function FormProvider({validate, shouldValidateOnBlur, shouldValidateOnChange, c (values) => { const validateErrors = validate(values); setErrors(validateErrors); + return validateErrors; }, [validate], ); From 2c01ca128dcb21d0479f39b54caad352d7255098 Mon Sep 17 00:00:00 2001 From: Hans Date: Thu, 28 Sep 2023 10:20:08 +0700 Subject: [PATCH 079/101] add linking config for search --- .well-known/apple-app-site-association | 4 ++++ android/app/src/main/AndroidManifest.xml | 2 ++ 2 files changed, 6 insertions(+) diff --git a/.well-known/apple-app-site-association b/.well-known/apple-app-site-association index a9e2b0383691..d6da0232f2fc 100644 --- a/.well-known/apple-app-site-association +++ b/.well-known/apple-app-site-association @@ -75,6 +75,10 @@ { "/": "/teachersunite/*", "comment": "Teachers Unite!" + }, + { + "/": "/search/*", + "comment": "Search" } ] } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 8d69c62bfd1f..dc135fa9834e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -67,6 +67,7 @@ + @@ -83,6 +84,7 @@ + From 24fb4c899dcc1c52123ea0703a722c13594b011c Mon Sep 17 00:00:00 2001 From: situchan Date: Thu, 28 Sep 2023 11:57:02 +0600 Subject: [PATCH 080/101] fix crash on room name validation --- src/libs/ValidationUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index 80b15690ac46..b94c240b6e92 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -314,8 +314,8 @@ function isReservedRoomName(roomName: string): boolean { /** * Checks if the room name already exists. */ -function isExistingRoomName(roomName: string, reports: Report[], policyID: string): boolean { - return reports.some((report) => report && report.policyID === policyID && report.reportName === roomName); +function isExistingRoomName(roomName: string, reports: Record, policyID: string): boolean { + return Object.values(reports).some((report) => report && report.policyID === policyID && report.reportName === roomName); } /** From d0adf804ee6268ba193c03c5904d3ad469003f3d Mon Sep 17 00:00:00 2001 From: situchan Date: Thu, 28 Sep 2023 12:15:53 +0600 Subject: [PATCH 081/101] recheck From 290a38363e81501762e5d899c61abd7de68de429 Mon Sep 17 00:00:00 2001 From: Jason Li <30815269+jliexpensify@users.noreply.github.com> Date: Thu, 28 Sep 2023 17:36:24 +1000 Subject: [PATCH 082/101] Update Merge-Expenses.md --- .../get-paid-back/expenses/Merge-Expenses.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/articles/expensify-classic/get-paid-back/expenses/Merge-Expenses.md b/docs/articles/expensify-classic/get-paid-back/expenses/Merge-Expenses.md index bfbc0773768c..a8444b98c951 100644 --- a/docs/articles/expensify-classic/get-paid-back/expenses/Merge-Expenses.md +++ b/docs/articles/expensify-classic/get-paid-back/expenses/Merge-Expenses.md @@ -14,7 +14,7 @@ Keep in mind: 1. Merging expenses cannot be undone. 2. You can only merge two expenses at a time. 3. You can merge a cash expense with a credit card expense, or two cash expenses - but not two credit card expenses. -4. In order to merge, both expenses will need to be in an Open or Unreported state. +4. In order to merge, both expenses will need to be in a Personal or Draft status. # How to merge expenses on the web app To merge two expenses from the Expenses page: @@ -41,11 +41,12 @@ If the expenses exist on two different reports, you will be asked which report y ## Can you merge expenses across different reports? -You cannot merge expenses across different reports. Expenses will only merge if they are on the same report. If you have expenses across different reports that you wish to merge, you’ll need to move both expenses onto the same report (and ensure they are in the Open status) in order to merge them. +You cannot merge expenses across different reports. Expenses will only merge if they are on the same report. If you have expenses across different reports that you wish to merge, you’ll need to move both expenses onto the same report (and ensure they are in the Draft status) in order to merge them. ## Can you merge expenses across different accounts? You cannot merge expenses across two separate accounts. You will need to choose one submitter and transfer the expense information to that user's account in order to merge the expense. + ## Can you merge expenses with different currencies? Yes, you can merge expenses with different currencies. The conversion amount will be based on the daily exchange rate for the date of the transaction, as long as the converted rates are within +/- 5%. If the currencies are the same, then the amounts must be an exact match to merge. From 645086d91bab73e29619d5024dd982af4cca342d Mon Sep 17 00:00:00 2001 From: Jason Li <30815269+jliexpensify@users.noreply.github.com> Date: Thu, 28 Sep 2023 17:44:14 +1000 Subject: [PATCH 083/101] Update Create-Expenses.md Made verbiage changes --- .../get-paid-back/expenses/Create-Expenses.md | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/docs/articles/expensify-classic/get-paid-back/expenses/Create-Expenses.md b/docs/articles/expensify-classic/get-paid-back/expenses/Create-Expenses.md index e565e59dc754..f078c46a8f1d 100644 --- a/docs/articles/expensify-classic/get-paid-back/expenses/Create-Expenses.md +++ b/docs/articles/expensify-classic/get-paid-back/expenses/Create-Expenses.md @@ -48,11 +48,11 @@ You can also create a number of future 'placeholder' expenses for your recurring # How to Edit Bulk Expenses Editing expenses in bulk will allow you to apply the same coding across multiple expenses and is a web-only feature. To bulk edit expenses: Go to the Expenses page. -To narrow down your selection, use the filters (e.g. "Merchant" and "Open") to find the specific expenses you want to edit. +To narrow down your selection, use the filters (e.g. "Merchant" and "Draft") to find the specific expenses you want to edit. Select all the expenses you want to edit. Click on the **Edit Multiple** button at the top of the page. # How to Edit Expenses on a Report -If you’d like to edit expenses within an Open report: +If you’d like to edit expenses within a Draft report: 1. Click on the Report containing all the expenses. 2. Click on **Details**. @@ -61,8 +61,8 @@ If you’d like to edit expenses within an Open report: If you've already submitted your report, you'll need to Retract it or have it Unapproved first before you can edit the expenses. - # FAQ + ## Does Expensify account for duplicates? Yes, Expensify will account for duplicates. Expensify works behind the scenes to identify duplicate expenses before they are submitted, warning employees when they exist. If a duplicate expense is submitted, the same warning will be shown to the approver responsible for reviewing the report. @@ -71,6 +71,7 @@ If two expenses are SmartScanned on the same day for the same amount, they will The expenses were split from a single expense, The expenses were imported from a credit card, or Matching email receipts sent to receipts@expensify.com were received with different timestamps. + ## How do I resolve a duplicate expense? If Concierge has let you know it's flagged a receipt as a duplicate, scanning the receipt again will trigger the same duplicate flagging.Users have the ability to resolve duplicates by either deleting the duplicated transactions, merging them, or ignoring them (if they are legitimately separate expenses of the same date and amount). @@ -88,12 +89,13 @@ Click the **Undelete** button and you're all set. You’ll find the expense on y ## What are the different Expense statuses? There are a number of different expense statuses in Expensify: -1. **Unreported**: Unreported expenses are not yet part of a report (and therefore unsubmitted) and are not viewable by anyone but the expense creator/owner. -2. **Open**: Open expenses are on a report that's still in progress, and are unsubmitted. Your Policy Admin will be able to view them, making it a collaborative step toward reimbursement. +1. **Personal**: Personal expenses are not yet part of a report (and therefore unsubmitted) and are not viewable by anyone but the expense creator/owner. +2. **Draft**: Draft expenses are seen as still in progress, and are unsubmitted. Your Policy Admin will be able to view them, making it a collaborative step toward reimbursement. 3. **Processing**: Processing expenses are submitted, but waiting for approval. 4. **Approved**: If it's a non-reimbursable expense, the workflow is complete at this point. If it's a reimbursable expense, you're one step closer to getting paid. 5. **Reimbursed**: Reimbursed expenses are fully settled. You can check the Report Comments to see when you'll get paid. 6. **Closed**: Sometimes an expense accidentally ends up on your Individual Policy, falling into the Closed status. You’ll need to reopen the report and change the Policy by clicking on the **Details** tab in order to resubmit your report. + ## What are Violations? Violations represent errors or discrepancies that Expensify has picked up and need to be corrected before a report can be successfully submitted. The one exception is when an expense comment is added, it will override the violation - as the user is providing a valid reason for submission. @@ -103,6 +105,7 @@ To enable or configure violations according to your policy, go to **Settings > P You can spot violations by the exclamation marks (!) attached to expenses. Hovering over the symbol will provide a brief description and you can find more detailed information below the list of expenses. The two types of violations are: **Red**: These indicate violations directly tied to your report's Policy settings. They are clear rule violations that must be addressed before submission. **Yellow**: Concierge will highlight items that require attention but may not necessarily need corrective action. For example, if a receipt was SmartScanned and then the amount was modified, we’ll bring it to your attention so that it can be manually reviewed. + ## How to Track Attendees Attendee tracking makes it easy to track shared expenses and maintain transparency in your group spending. @@ -116,9 +119,10 @@ External attendees are considered users outside your group policy or domain. To 1. Click or tap the **Attendee** field within your expense. 2. Type in the individual's name or email address. 3. Tap **Add** to include the attendee. -You can continue adding more attendees or save the Expense. +4. You can continue adding more attendees or save the Expense. + To remove an attendee from an expense: -Open the expense. -Click or tap the **Attendees** field to display the list of attendees. -From the list, de-select the attendees you'd like to remove from the expense. +1. Open the expense. +2. Click or tap the **Attendees** field to display the list of attendees. +3. From the list, de-select the attendees you'd like to remove from the expense. From ca027b4c33b1276528afd76ec7d6bde747f9a4bd Mon Sep 17 00:00:00 2001 From: Jason Li <30815269+jliexpensify@users.noreply.github.com> Date: Thu, 28 Sep 2023 19:19:04 +1000 Subject: [PATCH 084/101] Update Create-Expenses.md Made a few revisions again --- .../get-paid-back/expenses/Create-Expenses.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/articles/expensify-classic/get-paid-back/expenses/Create-Expenses.md b/docs/articles/expensify-classic/get-paid-back/expenses/Create-Expenses.md index f078c46a8f1d..7fa714189542 100644 --- a/docs/articles/expensify-classic/get-paid-back/expenses/Create-Expenses.md +++ b/docs/articles/expensify-classic/get-paid-back/expenses/Create-Expenses.md @@ -90,7 +90,7 @@ Click the **Undelete** button and you're all set. You’ll find the expense on y There are a number of different expense statuses in Expensify: 1. **Personal**: Personal expenses are not yet part of a report (and therefore unsubmitted) and are not viewable by anyone but the expense creator/owner. -2. **Draft**: Draft expenses are seen as still in progress, and are unsubmitted. Your Policy Admin will be able to view them, making it a collaborative step toward reimbursement. +2. **Draft**: Draft expenses are seen as still in progress, and are unsubmitted. Your Policy Admin will be able to view them, making this a collaborative step toward reimbursement. 3. **Processing**: Processing expenses are submitted, but waiting for approval. 4. **Approved**: If it's a non-reimbursable expense, the workflow is complete at this point. If it's a reimbursable expense, you're one step closer to getting paid. 5. **Reimbursed**: Reimbursed expenses are fully settled. You can check the Report Comments to see when you'll get paid. @@ -103,8 +103,8 @@ Violations represent errors or discrepancies that Expensify has picked up and ne To enable or configure violations according to your policy, go to **Settings > Policies > _Policy Name_ > Expenses > Expense Violations**. Keep in mind that Expensify includes certain system mandatory violations that can't be disabled, even if your policy has violations turned off. You can spot violations by the exclamation marks (!) attached to expenses. Hovering over the symbol will provide a brief description and you can find more detailed information below the list of expenses. The two types of violations are: -**Red**: These indicate violations directly tied to your report's Policy settings. They are clear rule violations that must be addressed before submission. -**Yellow**: Concierge will highlight items that require attention but may not necessarily need corrective action. For example, if a receipt was SmartScanned and then the amount was modified, we’ll bring it to your attention so that it can be manually reviewed. +1. **Red**: These indicate violations directly tied to your report's Policy settings. They are clear rule violations that must be addressed before submission. +2. **Yellow**: Concierge will highlight items that require attention but may not necessarily need corrective action. For example, if a receipt was SmartScanned and then the amount was modified, we’ll bring it to your attention so that it can be manually reviewed. ## How to Track Attendees From 02b5eef105349053f4f8adef55d9b9d85289a820 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Thu, 28 Sep 2023 17:23:54 +0800 Subject: [PATCH 085/101] Update ONYXKEYS.ts Remove unused import --- src/ONYXKEYS.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 14db8d2ab0c2..7a0def596774 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -1,5 +1,4 @@ import {ValueOf} from 'type-fest'; -import {OnyxUpdate} from 'react-native-onyx'; import DeepValueOf from './types/utils/DeepValueOf'; import * as OnyxTypes from './types/onyx'; import CONST from './CONST'; From f5b12d2c4c5010939a7e75c0c9eb3427db1d373b Mon Sep 17 00:00:00 2001 From: Maciej Dobosz Date: Thu, 28 Sep 2023 13:37:09 +0200 Subject: [PATCH 086/101] Return function instead of direct value --- src/components/LocaleContextProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/LocaleContextProvider.js b/src/components/LocaleContextProvider.js index f2525c5e3524..b8838f253e74 100644 --- a/src/components/LocaleContextProvider.js +++ b/src/components/LocaleContextProvider.js @@ -76,7 +76,7 @@ function LocaleContextProvider({children, currentUserPersonalDetails, preferredL /** * Updates date-fns internal locale to the user preferredLocale */ - const updateLocale = useMemo(() => DateUtils.setLocale(preferredLocale), [preferredLocale]); + const updateLocale = useMemo(() => () => DateUtils.setLocale(preferredLocale), [preferredLocale]); /** * @param {String} phoneNumber From ee568ee965e9c17cd1e7e9dd096c14ba039c800e Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 28 Sep 2023 20:39:21 +0700 Subject: [PATCH 087/101] fix: status emoji is overlap in report action item --- src/styles/styles.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/styles/styles.js b/src/styles/styles.js index 56868f930735..cef87c531972 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -3674,6 +3674,7 @@ const styles = (theme) => ({ borderRadius: variables.componentBorderRadiusLarge, }, userReportStatusEmoji: { + flexShrink: 0, fontSize: variables.fontSizeNormal, marginRight: 4, }, From 1db6def8f71355499dcbc8a9138b9b412d1f4895 Mon Sep 17 00:00:00 2001 From: maddylewis <38016013+maddylewis@users.noreply.github.com> Date: Thu, 28 Sep 2023 12:49:23 -0400 Subject: [PATCH 088/101] Update User-Roles.md minor formatting updates --- .../User-Roles.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/articles/expensify-classic/manage-employees-and-report-approvals/User-Roles.md b/docs/articles/expensify-classic/manage-employees-and-report-approvals/User-Roles.md index a65dc378a793..65238457f1a9 100644 --- a/docs/articles/expensify-classic/manage-employees-and-report-approvals/User-Roles.md +++ b/docs/articles/expensify-classic/manage-employees-and-report-approvals/User-Roles.md @@ -9,34 +9,34 @@ This guide is for those who are part of a **Group Workspace**. Each member has a role that defines what they can see and do in the workspace. Most members will have the role of "Employee." -# How to Manage User Roles +# How to manage user roles -To find and edit the roles of group workspace members, go to **Settings > Workspaces > Group > [Your Specific Workspace Name] > Members > Workspace Members** +To find and edit the roles of group workspace members, go to **Settings > Workspaces > Group > _[Workspace Name]_ > Members > Workspace Members** Here you'll see the list of members in your group workspace. To change their roles, click **Settings** next to the member’s name and choose the role that the member needs. Next, let’s go over the various user roles that are available on a group workspace. -## The Employee Role +### The Employee Role - **What can they do:** Employees can only see their own expense reports or reports that have been submitted to or shared with them. They can't change settings or invite new users. - **Who is it for:** Regular employees who only need to manage their own expenses, or managers who are reviewing expense reports for a few users but don’t need global visibility. - **Approvers:** Members who approve expenses can either be Employees, Admins, or Workspace Auditors, depending on how much control they need. - **Billable:** Employees are billable actors if they take actions on a report on your Group Workspace (including **SmartScanning** a receipt). -## Workspace Admin Role +### Workspace Admin Role - **What can they do:** Admins have full control. They can change settings, invite members, and view all reports. They can also process reimbursements if they have access to the company’s account. - **Billing Owners:** Billing owners are Admins by default. **Workspace Admins** are assigned by the owner or another admin. - **Billable:** Yes, if they perform actions like changing settings or inviting users. Just viewing reports is not billable. -## Workspace Auditor Role +### Workspace Auditor Role - **What can they do:** Workspace Auditors can see all reports, make comments, and export them. They can also mark reports as reimbursed if they're the final approver. - **Who is it for:** Accountants, bookkeepers, and internal or external audit agents who need to view but not edit workspace settings. - **Billable:** Yes, if they perform any actions like commenting or exporting a report. Viewing alone doesn't incur a charge. -## Technical Contact +### Technical Contact - **What can they do:** In case of connection issues, alerts go to the billing owner by default. You can set a technical contact if you want alerts to go to an IT administrator instead. - **How to set one:** Go to **Settings > Workspaces > Group > [Workspace Name] > Connections > Technical Contact**. From 3b2dc326a52127b6e5552b81c9f14e5e2c5a8126 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 28 Sep 2023 18:31:23 +0000 Subject: [PATCH 089/101] Update version to 1.3.75-0 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 4 ++-- ios/NewExpensifyTests/Info.plist | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 4c5311ffea20..b63b41077169 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -90,8 +90,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001037403 - versionName "1.3.74-3" + versionCode 1001037500 + versionName "1.3.75-0" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 73e22053eda1..90683ca8e085 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.3.74 + 1.3.75 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 1.3.74.3 + 1.3.75.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 5e7f02699579..60a57f3bec42 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.3.74 + 1.3.75 CFBundleSignature ???? CFBundleVersion - 1.3.74.3 + 1.3.75.0 diff --git a/package-lock.json b/package-lock.json index 42755b09f8b6..bc94fb780a1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.74-3", + "version": "1.3.75-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.74-3", + "version": "1.3.75-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 3b88d603ba52..f7f385f7620c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.74-3", + "version": "1.3.75-0", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 56bd89936047530a0390f1d73e6718daeb4a0957 Mon Sep 17 00:00:00 2001 From: maddylewis <38016013+maddylewis@users.noreply.github.com> Date: Thu, 28 Sep 2023 15:40:12 -0400 Subject: [PATCH 090/101] Update and rename Account-Access.md to Account-Details.md updated title of subcategory --- .../expensify-classic/account-settings/Account-Access.md | 5 ----- .../expensify-classic/account-settings/Account-Details.md | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 docs/articles/expensify-classic/account-settings/Account-Access.md create mode 100644 docs/articles/expensify-classic/account-settings/Account-Details.md diff --git a/docs/articles/expensify-classic/account-settings/Account-Access.md b/docs/articles/expensify-classic/account-settings/Account-Access.md deleted file mode 100644 index b3126201715f..000000000000 --- a/docs/articles/expensify-classic/account-settings/Account-Access.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Account Access -description: Account Access ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/account-settings/Account-Details.md b/docs/articles/expensify-classic/account-settings/Account-Details.md new file mode 100644 index 000000000000..46a6c6ba0c25 --- /dev/null +++ b/docs/articles/expensify-classic/account-settings/Account-Details.md @@ -0,0 +1,5 @@ +--- +title: Account Details +description: Account Details +--- +## Resource Coming Soon! From 905bdcc06d074e328c614a0d9917a4ddb124202d Mon Sep 17 00:00:00 2001 From: Lauren Schurr <33293730+lschurr@users.noreply.github.com> Date: Fri, 29 Sep 2023 04:50:30 +0000 Subject: [PATCH 091/101] Update Scheduled-Submit.md --- .../reports/Scheduled-Submit.md | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/reports/Scheduled-Submit.md b/docs/articles/expensify-classic/policy-and-domain-settings/reports/Scheduled-Submit.md index 78471e6c3906..a6f474faa77b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/reports/Scheduled-Submit.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/reports/Scheduled-Submit.md @@ -1,5 +1,37 @@ --- title: Scheduled Submit -description: Scheduled Submit --- -## Resource Coming Soon! +# Overview + +Scheduled Submit reduces the delay between the time an employee creates an expense to when it is submitted to the admin. This gives admins significantly faster visibility into employee spend. Without Scheduled Submit enabled, expenses can be left Unreported giving workspace admins no visibility into employee spend. + +The biggest delay in expense management is the time it takes for an employee to actually submit the expense after it is incurred. Scheduled Submit allows you to automatically collect employee expenses on a schedule of your choosing without delaying the process while you wait for employees to submit them. + +It works like this: Employee expenses are automatically gathered onto a report. If there is not an existing report, a new one will be created. This report is submitted automatically at the cadence you choose (daily, weekly, monthly, twice month, by trip). + +# How to enable Scheduled Submit + +**For workspace admins**: To enable Scheduled Submit on your group workspace, follow **Settings > Workspaces > Group > *[Workspace Name]* > Reports > Scheduled Submit**. From there, toggle Scheduled Submit to Enabled. Then, choose your desired frequency from the dropdown menu. +For individuals or employees: To enable Scheduled Submit on your individual workspace, follow **Settings > Workspaces > Individual > *[Workspace Name]* > Reports > Scheduled Submit**. From there, toggle Scheduled Submit to Enabled. Then, choose your desired frequency from the dropdown menu. + +## Scheduled Submit frequency options + +**Daily**: Each night, expenses without violations will be submitted. Expenses with violations will remain on an open report until the violations are corrected, after which they will be submitted in the evening (PDT). + +**Weekly**: Expenses that are free of violations will be submitted on a weekly basis. However, expenses with violations will be held in a new open report and combined with any new expenses. They will then be submitted at the end of the following weekly cycle, specifically on Sunday evening (PDT). + +**Twice a month**: Expenses that are violation-free will be submitted on both the 15th and the last day of each month, in the evening (PDT). Expenses with violations will not be submitted, but moved on to a new open report so the employee can resolve the violations and then will be submitted at the conclusion of the next cycle. + +**Monthly**: Expenses that are free from violations will be submitted on a monthly basis. Expenses with violations will be held back and moved to a new Open report so the violations can be resolved, and they will be submitted on the evening (PDT) of the specified date. + +**By trip**: Expenses are grouped by trip. This is calculated by grouping all expenses together that occur in a similar time frame. If two full days pass without any new expenses being created, the trip report will be submitted on the evening of the second day. Any expenses generated after this submission will initiate a new trip report. Please note that the "2-day" period refers to a date-based interval, not a 48-hour time frame. + +**Manually**: An open report will be created, and expenses will be added to it automatically. However, it's important to note that the report will not be submitted automatically; manual submission of reports will be required.This is a great option for automatically gathering all an employee’s expenses on a report for the employee’s convenience, but they will still need to review and submit the report. + +# Deep Dive + +## Schedule Submit Override +If Scheduled Submit is disabled at the group workspace level or configured the frequency as "Manually," the individual workspace settings of a user will take precedence and be applied. This means an employee can still set up Scheduled Submit for themselves even if the admin has not enabled it. We highly recommend Scheduled Submit as it helps put your expenses on auto-pilot! + +## Personal Card Transactions +Personal card transactions are handled differently compared to other expenses. If a user has added a card through Settings > Account > Credit Card Import, they need to make sure it is set as non-reimbursable and transactions must be automatically merged with a SmartScanned receipt. If transactions are set to come in as reimbursable or they aren’t merged with a SmartScanned receipt, Scheduled Submit settings will not apply. From 095801ff7cc87070b03379aaec8023c34e846689 Mon Sep 17 00:00:00 2001 From: Lauren Schurr <33293730+lschurr@users.noreply.github.com> Date: Fri, 29 Sep 2023 05:12:38 +0000 Subject: [PATCH 092/101] Update Scheduled-Submit.md --- .../policy-and-domain-settings/reports/Scheduled-Submit.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/reports/Scheduled-Submit.md b/docs/articles/expensify-classic/policy-and-domain-settings/reports/Scheduled-Submit.md index a6f474faa77b..c05df92bbbff 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/reports/Scheduled-Submit.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/reports/Scheduled-Submit.md @@ -1,5 +1,6 @@ --- title: Scheduled Submit +description: How to use the Scheduled Submit feature --- # Overview From 712d92aa0e5bb6a4c9e674c8881a3e45ab314bfd Mon Sep 17 00:00:00 2001 From: Cole Eason Date: Fri, 29 Sep 2023 13:30:59 +0800 Subject: [PATCH 093/101] Add conditional wallet terms based on program ID --- src/CONST.ts | 1 + src/languages/en.ts | 4 +++- src/languages/types.ts | 3 +++ src/pages/EnablePayments/EnablePaymentsPage.js | 2 +- .../EnablePayments/TermsPage/ShortTermsForm.js | 16 ++++++++++++++-- src/pages/EnablePayments/TermsStep.js | 7 ++++++- src/pages/EnablePayments/userWalletPropTypes.js | 3 +++ src/types/onyx/UserWallet.ts | 3 +++ 8 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index dbe47c6ed1a7..068b1f6507cb 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -992,6 +992,7 @@ const CONST = { STATEMENT: 'STATEMENT_NAVIGATE', CONCIERGE: 'CONCIERGE_NAVIGATE', }, + MTL_WALLET_PROGRAM_ID : '760', }, PLAID: { diff --git a/src/languages/en.ts b/src/languages/en.ts index 9c49e2907702..8395854a4000 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -73,8 +73,10 @@ import type { RequestedAmountMessageParams, TagSelectionParams, TranslationBase, + WalletProgramParams, } from './types'; import * as ReportActionsUtils from '../libs/ReportActionsUtils'; +import walletTermsPropTypes from '../pages/EnablePayments/walletTermsPropTypes'; type StateValue = { stateISO: string; @@ -1170,7 +1172,7 @@ export default { electronicFundsWithdrawal: 'Electronic funds withdrawal', standard: 'Standard', shortTermsForm: { - expensifyPaymentsAccount: 'The Expensify Wallet is issued by The Bancorp Bank.', + expensifyPaymentsAccount: ({ walletProgram }: WalletProgramParams) => `The Expensify Wallet is issued by ${walletProgram}.`, perPurchase: 'Per purchase', atmWithdrawal: 'ATM withdrawal', cashReload: 'Cash reload', diff --git a/src/languages/types.ts b/src/languages/types.ts index 70bf2e4cae3d..330973bd5e08 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -194,6 +194,8 @@ type FormattedMaxLengthParams = {formattedMaxLength: string}; type TagSelectionParams = {tagName: string}; +type WalletProgramParams = { walletProgram: string }; + /* Translation Object types */ // eslint-disable-next-line @typescript-eslint/no-explicit-any type TranslationBaseValue = string | string[] | ((...args: any[]) => string); @@ -307,4 +309,5 @@ export type { RemovedTheRequestParams, FormattedMaxLengthParams, TagSelectionParams, + WalletProgramParams, }; diff --git a/src/pages/EnablePayments/EnablePaymentsPage.js b/src/pages/EnablePayments/EnablePaymentsPage.js index 773dfe8b5df7..f7ef2a174208 100644 --- a/src/pages/EnablePayments/EnablePaymentsPage.js +++ b/src/pages/EnablePayments/EnablePaymentsPage.js @@ -76,7 +76,7 @@ function EnablePaymentsPage({userWallet}) { case CONST.WALLET.STEP.ONFIDO: return ; case CONST.WALLET.STEP.TERMS: - return ; + return ; case CONST.WALLET.STEP.ACTIVATE: return ; default: diff --git a/src/pages/EnablePayments/TermsPage/ShortTermsForm.js b/src/pages/EnablePayments/TermsPage/ShortTermsForm.js index a6f685fcb562..adf164ea7e3c 100644 --- a/src/pages/EnablePayments/TermsPage/ShortTermsForm.js +++ b/src/pages/EnablePayments/TermsPage/ShortTermsForm.js @@ -5,11 +5,21 @@ import Text from '../../../components/Text'; import * as Localize from '../../../libs/Localize'; import CONST from '../../../CONST'; import TextLink from '../../../components/TextLink'; +import userWalletPropTypes from '../userWalletPropTypes'; -function ShortTermsForm() { +const propTypes = { + /** The user's wallet */ + userWallet: userWalletPropTypes, +}; + +const defaultProps = { + userWallet: {}, +}; + +function ShortTermsForm(props) { return ( <> - {Localize.translateLocal('termsStep.shortTermsForm.expensifyPaymentsAccount')} + {Localize.translateLocal('termsStep.shortTermsForm.expensifyPaymentsAccount', { walletProgram: props.userWallet.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID ? 'Expensify Payments' : 'The Bancorp Bank'})} @@ -132,6 +142,8 @@ function ShortTermsForm() { ); } +ShortTermsForm.propTypes = propTypes; +ShortTermsForm.defaultProps = defaultProps; ShortTermsForm.displayName = 'ShortTermsForm'; export default ShortTermsForm; diff --git a/src/pages/EnablePayments/TermsStep.js b/src/pages/EnablePayments/TermsStep.js index e96d93dc4de9..3194ea637a7d 100644 --- a/src/pages/EnablePayments/TermsStep.js +++ b/src/pages/EnablePayments/TermsStep.js @@ -15,8 +15,12 @@ import LongTermsForm from './TermsPage/LongTermsForm'; import FormAlertWithSubmitButton from '../../components/FormAlertWithSubmitButton'; import walletTermsPropTypes from './walletTermsPropTypes'; import * as ErrorUtils from '../../libs/ErrorUtils'; +import userWalletPropTypes from './userWalletPropTypes'; const propTypes = { + /** The user's wallet */ + userWallet: userWalletPropTypes, + /** Comes from Onyx. Information about the terms for the wallet */ walletTerms: walletTermsPropTypes, @@ -24,6 +28,7 @@ const propTypes = { }; const defaultProps = { + userWallet: {}, walletTerms: {}, }; @@ -59,7 +64,7 @@ function TermsStep(props) { style={styles.flex1} contentContainerStyle={styles.ph5} > - + Date: Fri, 29 Sep 2023 13:48:48 +0800 Subject: [PATCH 094/101] Fix lint checks --- src/languages/en.ts | 1 - src/languages/es.ts | 3 ++- src/pages/EnablePayments/TermsStep.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 8395854a4000..ecfb131d68b3 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -76,7 +76,6 @@ import type { WalletProgramParams, } from './types'; import * as ReportActionsUtils from '../libs/ReportActionsUtils'; -import walletTermsPropTypes from '../pages/EnablePayments/walletTermsPropTypes'; type StateValue = { stateISO: string; diff --git a/src/languages/es.ts b/src/languages/es.ts index 2be3f9e96265..08817bb84b6a 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -73,6 +73,7 @@ import type { RequestedAmountMessageParams, TagSelectionParams, EnglishTranslation, + WalletProgramParams, } from './types'; /* eslint-disable max-len */ @@ -1187,7 +1188,7 @@ export default { electronicFundsWithdrawal: 'Retiro electrónico de fondos', standard: 'Estándar', shortTermsForm: { - expensifyPaymentsAccount: 'La billetera Expensify es emitida por The Bancorp Bank.', + expensifyPaymentsAccount: ({ walletProgram }: WalletProgramParams) => `La billetera Expensify es emitida por ${walletProgram}.`, perPurchase: 'Por compra', atmWithdrawal: 'Retiro de cajero automático', cashReload: 'Recarga de efectivo', diff --git a/src/pages/EnablePayments/TermsStep.js b/src/pages/EnablePayments/TermsStep.js index 3194ea637a7d..39f4826ec0b2 100644 --- a/src/pages/EnablePayments/TermsStep.js +++ b/src/pages/EnablePayments/TermsStep.js @@ -64,7 +64,7 @@ function TermsStep(props) { style={styles.flex1} contentContainerStyle={styles.ph5} > - + Date: Fri, 29 Sep 2023 13:55:28 +0800 Subject: [PATCH 095/101] prettier fixes --- src/CONST.ts | 2 +- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- src/languages/types.ts | 2 +- src/pages/EnablePayments/TermsPage/ShortTermsForm.js | 6 +++++- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 068b1f6507cb..f1d717f697cc 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -992,7 +992,7 @@ const CONST = { STATEMENT: 'STATEMENT_NAVIGATE', CONCIERGE: 'CONCIERGE_NAVIGATE', }, - MTL_WALLET_PROGRAM_ID : '760', + MTL_WALLET_PROGRAM_ID: '760', }, PLAID: { diff --git a/src/languages/en.ts b/src/languages/en.ts index ecfb131d68b3..db08b5484ddf 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1171,7 +1171,7 @@ export default { electronicFundsWithdrawal: 'Electronic funds withdrawal', standard: 'Standard', shortTermsForm: { - expensifyPaymentsAccount: ({ walletProgram }: WalletProgramParams) => `The Expensify Wallet is issued by ${walletProgram}.`, + expensifyPaymentsAccount: ({walletProgram}: WalletProgramParams) => `The Expensify Wallet is issued by ${walletProgram}.`, perPurchase: 'Per purchase', atmWithdrawal: 'ATM withdrawal', cashReload: 'Cash reload', diff --git a/src/languages/es.ts b/src/languages/es.ts index 08817bb84b6a..4b5623aef268 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1188,7 +1188,7 @@ export default { electronicFundsWithdrawal: 'Retiro electrónico de fondos', standard: 'Estándar', shortTermsForm: { - expensifyPaymentsAccount: ({ walletProgram }: WalletProgramParams) => `La billetera Expensify es emitida por ${walletProgram}.`, + expensifyPaymentsAccount: ({walletProgram}: WalletProgramParams) => `La billetera Expensify es emitida por ${walletProgram}.`, perPurchase: 'Por compra', atmWithdrawal: 'Retiro de cajero automático', cashReload: 'Recarga de efectivo', diff --git a/src/languages/types.ts b/src/languages/types.ts index 330973bd5e08..52f2df8b3765 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -194,7 +194,7 @@ type FormattedMaxLengthParams = {formattedMaxLength: string}; type TagSelectionParams = {tagName: string}; -type WalletProgramParams = { walletProgram: string }; +type WalletProgramParams = {walletProgram: string}; /* Translation Object types */ // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/src/pages/EnablePayments/TermsPage/ShortTermsForm.js b/src/pages/EnablePayments/TermsPage/ShortTermsForm.js index adf164ea7e3c..4c3bfb7eaf61 100644 --- a/src/pages/EnablePayments/TermsPage/ShortTermsForm.js +++ b/src/pages/EnablePayments/TermsPage/ShortTermsForm.js @@ -19,7 +19,11 @@ const defaultProps = { function ShortTermsForm(props) { return ( <> - {Localize.translateLocal('termsStep.shortTermsForm.expensifyPaymentsAccount', { walletProgram: props.userWallet.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID ? 'Expensify Payments' : 'The Bancorp Bank'})} + + {Localize.translateLocal('termsStep.shortTermsForm.expensifyPaymentsAccount', { + walletProgram: props.userWallet.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID ? 'Expensify Payments' : 'The Bancorp Bank', + })} + From 828456b9d118526aa1768c1e12a54f45f2ddf204 Mon Sep 17 00:00:00 2001 From: Cole Eason Date: Fri, 29 Sep 2023 14:20:12 +0800 Subject: [PATCH 096/101] Use a constant for bank names --- src/CONST.ts | 4 ++++ src/languages/en.ts | 8 ++++---- src/languages/es.ts | 8 ++++---- src/pages/EnablePayments/TermsPage/ShortTermsForm.js | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index f1d717f697cc..0d671bbba260 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -993,6 +993,10 @@ const CONST = { CONCIERGE: 'CONCIERGE_NAVIGATE', }, MTL_WALLET_PROGRAM_ID: '760', + PROGRAM_ISSUERS: { + EXPENSIFY_PAYMENTS: 'Expensify Payments LLC', + BANCORP_BANK: 'The Bancorp Bank' + } }, PLAID: { diff --git a/src/languages/en.ts b/src/languages/en.ts index db08b5484ddf..f16097aa03d1 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -910,7 +910,7 @@ export default { phrase2: 'Terms of Service', phrase3: 'and', phrase4: 'Privacy', - phrase5: 'Money transmission is provided by Expensify Payments LLC (NMLS ID:2017010) pursuant to its', + phrase5: `Money transmission is provided by ${CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS} (NMLS ID:2017010) pursuant to its`, phrase6: 'licenses', }, validateCodeForm: { @@ -1213,10 +1213,10 @@ export default { 'several minutes. The fee is 1.5% of the transfer amount (with a minimum fee of $0.25).', fdicInsuranceBancorp: 'Your funds are eligible for FDIC insurance. Your funds will be held at or ' + - 'transferred to The Bancorp Bank, an FDIC-insured institution. Once there, your funds are insured up ' + - 'to $250,000 by the FDIC in the event The Bancorp Bank fails. See', + `transferred to ${CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK}, an FDIC-insured institution. Once there, your funds are insured up ` + + `to $250,000 by the FDIC in the event ${CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK} fails. See`, fdicInsuranceBancorp2: 'for details.', - contactExpensifyPayments: 'Contact Expensify Payments by calling +1 833-400-0904, by email at', + contactExpensifyPayments: `Contact ${CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS} by calling +1 833-400-0904, by email at`, contactExpensifyPayments2: 'or sign in at', generalInformation: 'For general information about prepaid accounts, visit', generalInformation2: 'If you have a complaint about a prepaid account, call the Consumer Financial Protection Bureau at 1-855-411-2372 or visit', diff --git a/src/languages/es.ts b/src/languages/es.ts index 4b5623aef268..3860c34f6ef1 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -906,7 +906,7 @@ export default { phrase2: 'Términos de Servicio', phrase3: 'y', phrase4: 'Privacidad', - phrase5: 'El envío de dinero es brindado por Expensify Payments LLC (NMLS ID:2017010) de conformidad con sus', + phrase5: `El envío de dinero es brindado por ${CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS} (NMLS ID:2017010) de conformidad con sus`, phrase6: 'licencias', }, validateCodeForm: { @@ -1231,10 +1231,10 @@ export default { 'transferencia (con una tarifa mínima de $ 0.25). ', fdicInsuranceBancorp: 'Sus fondos son elegibles para el seguro de la FDIC. Sus fondos se mantendrán en o ' + - 'transferido a The Bancorp Bank, una institución asegurada por la FDIC. Una vez allí, sus fondos ' + - 'están asegurados a $ 250,000 por la FDIC en caso de que The Bancorp Bank quiebre. Ver', + `transferido a ${CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK}, una institución asegurada por la FDIC. Una vez allí, sus fondos ` + + `están asegurados a $ 250,000 por la FDIC en caso de que ${CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK} quiebre. Ver`, fdicInsuranceBancorp2: 'para detalles.', - contactExpensifyPayments: 'Comuníquese con Expensify Payments llamando al + 1833-400-0904, por correoelectrónico a', + contactExpensifyPayments: `Comuníquese con ${CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS} llamando al + 1833-400-0904, por correoelectrónico a`, contactExpensifyPayments2: 'o inicie sesión en', generalInformation: 'Para obtener información general sobre cuentas prepagas, visite', generalInformation2: 'Si tiene una queja sobre una cuenta prepaga, llame al Consumer Financial Oficina de Protección al 1-855-411-2372 o visite', diff --git a/src/pages/EnablePayments/TermsPage/ShortTermsForm.js b/src/pages/EnablePayments/TermsPage/ShortTermsForm.js index 4c3bfb7eaf61..8bc4e9a9d80a 100644 --- a/src/pages/EnablePayments/TermsPage/ShortTermsForm.js +++ b/src/pages/EnablePayments/TermsPage/ShortTermsForm.js @@ -21,7 +21,7 @@ function ShortTermsForm(props) { <> {Localize.translateLocal('termsStep.shortTermsForm.expensifyPaymentsAccount', { - walletProgram: props.userWallet.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID ? 'Expensify Payments' : 'The Bancorp Bank', + walletProgram: props.userWallet.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID ? CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS : CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK, })} From f3939746e50fcb2a7c20fb428f84d7794387efbd Mon Sep 17 00:00:00 2001 From: Cole Eason Date: Fri, 29 Sep 2023 14:29:17 +0800 Subject: [PATCH 097/101] Run prettier --- src/CONST.ts | 4 ++-- src/pages/EnablePayments/TermsPage/ShortTermsForm.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 0d671bbba260..bd91137ae946 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -995,8 +995,8 @@ const CONST = { MTL_WALLET_PROGRAM_ID: '760', PROGRAM_ISSUERS: { EXPENSIFY_PAYMENTS: 'Expensify Payments LLC', - BANCORP_BANK: 'The Bancorp Bank' - } + BANCORP_BANK: 'The Bancorp Bank', + }, }, PLAID: { diff --git a/src/pages/EnablePayments/TermsPage/ShortTermsForm.js b/src/pages/EnablePayments/TermsPage/ShortTermsForm.js index 8bc4e9a9d80a..1b693add95b7 100644 --- a/src/pages/EnablePayments/TermsPage/ShortTermsForm.js +++ b/src/pages/EnablePayments/TermsPage/ShortTermsForm.js @@ -21,7 +21,8 @@ function ShortTermsForm(props) { <> {Localize.translateLocal('termsStep.shortTermsForm.expensifyPaymentsAccount', { - walletProgram: props.userWallet.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID ? CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS : CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK, + walletProgram: + props.userWallet.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID ? CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS : CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK, })} From aabf9326cd0fda6a49990f5e48be1fea7fcfbf21 Mon Sep 17 00:00:00 2001 From: Oscar Franco Date: Fri, 29 Sep 2023 08:54:12 +0200 Subject: [PATCH 098/101] Bump onyx --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 42755b09f8b6..c3a162feaf9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -90,7 +90,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "1.0.94", + "react-native-onyx": "1.0.96", "react-native-pager-view": "^6.2.0", "react-native-pdf": "^6.7.1", "react-native-performance": "^5.1.0", @@ -41204,9 +41204,9 @@ } }, "node_modules/react-native-onyx": { - "version": "1.0.94", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.94.tgz", - "integrity": "sha512-Xoh9LTdoCNLQjyeLB6HkBwyf5ipkSjnETLVijSIWKnecbZS8/fQehUuGz+yEk9I0xVEn43IhmnkQ+yqQvV9vEg==", + "version": "1.0.96", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.96.tgz", + "integrity": "sha512-7NQ+Ujj9uCGUMDeShpz1uO6f3ezeol2ZnCgX1pg5WzrFVB1RCqt3Z7cv9lYFHCbYYJwIKkqCYQT2Yb3ROyO1sw==", "dependencies": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", @@ -77269,9 +77269,9 @@ } }, "react-native-onyx": { - "version": "1.0.94", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.94.tgz", - "integrity": "sha512-Xoh9LTdoCNLQjyeLB6HkBwyf5ipkSjnETLVijSIWKnecbZS8/fQehUuGz+yEk9I0xVEn43IhmnkQ+yqQvV9vEg==", + "version": "1.0.96", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.96.tgz", + "integrity": "sha512-7NQ+Ujj9uCGUMDeShpz1uO6f3ezeol2ZnCgX1pg5WzrFVB1RCqt3Z7cv9lYFHCbYYJwIKkqCYQT2Yb3ROyO1sw==", "requires": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", diff --git a/package.json b/package.json index 3b88d603ba52..818651e68c9c 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "1.0.94", + "react-native-onyx": "1.0.96", "react-native-pager-view": "^6.2.0", "react-native-pdf": "^6.7.1", "react-native-performance": "^5.1.0", From 4208f74c8dd15b33df60c4104efaf681f4e159c1 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 29 Sep 2023 08:27:46 +0000 Subject: [PATCH 099/101] Update version to 1.3.75-1 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index b63b41077169..eda17666897c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -90,8 +90,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001037500 - versionName "1.3.75-0" + versionCode 1001037501 + versionName "1.3.75-1" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 90683ca8e085..33efc448a258 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.3.75.0 + 1.3.75.1 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 60a57f3bec42..3300535c05fd 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.3.75.0 + 1.3.75.1 diff --git a/package-lock.json b/package-lock.json index bc94fb780a1b..149951a1c81d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.75-0", + "version": "1.3.75-1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.75-0", + "version": "1.3.75-1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index f7f385f7620c..c323c6468fa5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.75-0", + "version": "1.3.75-1", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From ded9e98b14631d87f4c72dd97e7c676cf778b4ea Mon Sep 17 00:00:00 2001 From: Oscar Franco Date: Fri, 29 Sep 2023 10:35:06 +0200 Subject: [PATCH 100/101] Bump onyx --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 17ed03e4d529..b4907d3c3a56 100644 --- a/package-lock.json +++ b/package-lock.json @@ -90,7 +90,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "1.0.96", + "react-native-onyx": "1.0.97", "react-native-pager-view": "^6.2.0", "react-native-pdf": "^6.7.1", "react-native-performance": "^5.1.0", @@ -41204,9 +41204,9 @@ } }, "node_modules/react-native-onyx": { - "version": "1.0.96", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.96.tgz", - "integrity": "sha512-7NQ+Ujj9uCGUMDeShpz1uO6f3ezeol2ZnCgX1pg5WzrFVB1RCqt3Z7cv9lYFHCbYYJwIKkqCYQT2Yb3ROyO1sw==", + "version": "1.0.97", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.97.tgz", + "integrity": "sha512-6w4pp9Ktm4lQ6jIS+ZASQ5tYwRU1lt751yxfddvmN646XZefj4iDvC7uQaUnAgg1xL52dEV5RZWaI3sQ3e9AGQ==", "dependencies": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", @@ -77269,9 +77269,9 @@ } }, "react-native-onyx": { - "version": "1.0.96", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.96.tgz", - "integrity": "sha512-7NQ+Ujj9uCGUMDeShpz1uO6f3ezeol2ZnCgX1pg5WzrFVB1RCqt3Z7cv9lYFHCbYYJwIKkqCYQT2Yb3ROyO1sw==", + "version": "1.0.97", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.97.tgz", + "integrity": "sha512-6w4pp9Ktm4lQ6jIS+ZASQ5tYwRU1lt751yxfddvmN646XZefj4iDvC7uQaUnAgg1xL52dEV5RZWaI3sQ3e9AGQ==", "requires": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", diff --git a/package.json b/package.json index 0d088c0c7401..e173dffda25c 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "1.0.96", + "react-native-onyx": "1.0.97", "react-native-pager-view": "^6.2.0", "react-native-pdf": "^6.7.1", "react-native-performance": "^5.1.0", From a555ddbc015f2286a49e67a0833195d243c99f1c Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 29 Sep 2023 09:55:54 +0000 Subject: [PATCH 101/101] Update version to 1.3.75-2 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index eda17666897c..f0eddd6085bc 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -90,8 +90,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001037501 - versionName "1.3.75-1" + versionCode 1001037502 + versionName "1.3.75-2" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 33efc448a258..8536b4da82b5 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.3.75.1 + 1.3.75.2 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 3300535c05fd..802ee97145ae 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.3.75.1 + 1.3.75.2 diff --git a/package-lock.json b/package-lock.json index 3f67d7d95342..97b6f6ea7b38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.75-1", + "version": "1.3.75-2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.75-1", + "version": "1.3.75-2", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 75f8df58fc48..8804c2002a10 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.75-1", + "version": "1.3.75-2", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",