Skip to content

Commit d5262c6

Browse files
committed
Merge branch 'main' into fixComposerNotVisible
2 parents 695aea2 + f094ea5 commit d5262c6

425 files changed

Lines changed: 8131 additions & 4664 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Is Contributor+
2+
description: Check whether a GitHub user is a member of the Expensify/contributor-plus team. Sets IS_CPLUS=true when the user is a member, IS_CPLUS=false otherwise.
3+
4+
inputs:
5+
USERNAME:
6+
description: The GitHub login of the user to check.
7+
required: true
8+
OS_BOTIFY_TOKEN:
9+
description: OSBotify token. Needed to read team memberships (the default GITHUB_TOKEN lacks the read:org scope).
10+
required: true
11+
12+
outputs:
13+
IS_CPLUS:
14+
description: "'true' if the user is a member of Expensify/contributor-plus, 'false' otherwise."
15+
value: ${{ steps.check.outputs.IS_CPLUS }}
16+
17+
runs:
18+
using: composite
19+
steps:
20+
- name: Check Contributor+ membership
21+
id: check
22+
shell: bash
23+
env:
24+
GH_TOKEN: ${{ inputs.OS_BOTIFY_TOKEN }}
25+
USERNAME: ${{ inputs.USERNAME }}
26+
run: |
27+
if gh api "/orgs/Expensify/teams/contributor-plus/memberships/$USERNAME" --silent; then
28+
echo "::notice::✅ $USERNAME is a Contributor+ member"
29+
echo "IS_CPLUS=true" >> "$GITHUB_OUTPUT"
30+
else
31+
echo "::notice::$USERNAME is not a Contributor+ member"
32+
echo "IS_CPLUS=false" >> "$GITHUB_OUTPUT"
33+
fi

.github/workflows/claude-review.yml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,50 @@ permissions:
77
on:
88
pull_request_target:
99
types: [opened, ready_for_review]
10+
pull_request_review:
11+
types: [submitted]
1012

1113
concurrency:
1214
group: claude-review-${{ github.event.pull_request.html_url }}
1315
cancel-in-progress: true
1416

1517
jobs:
1618
validate:
19+
if: github.event_name == 'pull_request_target'
1720
uses: ./.github/workflows/contributorValidationGate.yml
1821
with:
1922
PR_NUMBER: ${{ github.event.pull_request.number }}
2023
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
2124
AUTHOR_ASSOCIATION: ${{ github.event.pull_request.author_association }}
2225

26+
checkCPlusApproval:
27+
if: github.event_name == 'pull_request_review' && github.event.review.state == 'approved'
28+
runs-on: blacksmith-2vcpu-ubuntu-2404
29+
outputs:
30+
IS_CPLUS: ${{ steps.check.outputs.IS_CPLUS }}
31+
steps:
32+
- name: Checkout repository
33+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
34+
with:
35+
fetch-depth: 1
36+
37+
- name: Check Contributor+ membership
38+
id: check
39+
uses: ./.github/actions/composite/isContributorPlus
40+
with:
41+
USERNAME: ${{ github.event.review.user.login }}
42+
OS_BOTIFY_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
43+
2344
review:
24-
needs: [validate]
45+
needs: [validate, checkCPlusApproval]
2546
if: |
26-
needs.validate.outputs.IS_AUTHORIZED == 'true'
47+
!cancelled()
2748
&& github.event.pull_request.draft != true
2849
&& !contains(github.event.pull_request.title, 'Revert')
50+
&& (
51+
(github.event_name == 'pull_request_target' && needs.validate.outputs.IS_AUTHORIZED == 'true')
52+
|| (github.event_name == 'pull_request_review' && needs.checkCPlusApproval.outputs.IS_CPLUS == 'true')
53+
)
2954
runs-on: blacksmith-2vcpu-ubuntu-2404
3055
env:
3156
PR_NUMBER: ${{ github.event.pull_request.number }}

.github/workflows/test.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ jobs:
3131
- name: Setup Node
3232
uses: ./.github/actions/composite/setupNode
3333

34-
- name: Get number of CPU cores
35-
id: cpu-cores
36-
uses: SimenB/github-actions-cpu-cores@31e91de0f8654375a21e8e83078be625380e2b18
37-
3834
- name: Cache Jest cache
3935
id: cache-jest-cache
4036
# v5.0.1

Mobile-Expensify

android/app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ android {
111111
minSdkVersion rootProject.ext.minSdkVersion
112112
targetSdkVersion rootProject.ext.targetSdkVersion
113113
multiDexEnabled rootProject.ext.multiDexEnabled
114-
versionCode 1009036103
115-
versionName "9.3.61-3"
114+
versionCode 1009036201
115+
versionName "9.3.62-1"
116116
// Supported language variants must be declared here to avoid from being removed during the compilation.
117117
// This also helps us to not include unnecessary language variants in the APK.
118118
resConfigs "en", "es"
Lines changed: 1 addition & 0 deletions
Loading

babel.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ const metro = {
130130
production: {
131131
plugins: [['transform-remove-console', {exclude: ['error', 'warn']}]],
132132
},
133+
test: {
134+
plugins: ['@babel/plugin-transform-dynamic-import'],
135+
},
133136
},
134137
};
135138

contributingGuides/PERFORMANCE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ Since our codebase is very complex, it results in a large DOM tree rendered for
282282

283283
One of the most common issues is related to modals, popovers, and tooltips — elements that may appear on the screen. The problem is that they are usually present in the DOM tree even when initially invisible. Because of this, the initial render time of a screen may increase, ultimately slowing down the app.
284284

285-
The solution is better control of invisible elements, making sure they are not included in the first render. This can be done, e.g., by a simple `return null`, smart usage of `lazy loading`, the `useTransition` hook, or the `<Deferred />` component.
285+
The solution is better control of invisible elements, making sure they are not included in the first render. This can be done, e.g., by a simple `return null`, smart usage of `lazy loading`, the `useTransition` hook, or the [`<NavigationDeferredMount />`](/src/components/NavigationDeferredMount.tsx) component. `<NavigationDeferredMount />` gates a heavy subtree behind navigation transition completion via `TransitionTracker`, rendering a cheap `placeholder` until the nav animation has finished, then mounting its `children` inside `startTransition` — ideal for heavy subtrees (e.g. report headers, page-level secondary actions) mounted during navigation transitions that pull many `useOnyx` subscriptions or heavy hooks but don't need to be interactive on first render.
286286

287287
Another issue worth mentioning is unnecessary code execution, especially for elements that are never shown on a specific platform. In theory, we separate the logic between platforms by using index.tsx/index.native.tsx files, but sometimes platform-specific logic may slip in, causing unnecessary execution. For example, this may happen when logic specific to a wide layout (applicable only for web) is included.
288288

@@ -294,6 +294,7 @@ Examples:
294294
- [PopoverWithMeasuredContent optimization for mobile](https://github.com/Expensify/App/pull/68223) - returns early to avoid unnecessary calculations
295295
- [Reduce confirm modal initial render count](https://github.com/Expensify/App/pull/67518) - returns early to reduce first load cost
296296
- [Do not render PopoverMenu until it gets opened](https://github.com/Expensify/App/pull/67877) - adds a wrapper to control if `PopoverMenu` should be rendered
297+
- [Defer mount of MoneyReportHeaderSecondaryActions](https://github.com/Expensify/App/pull/88522) - introduces `NavigationDeferredMount` and uses it to defer the "More" dropdown subtree (20+ `useOnyx` subscriptions) until the navigation transition completes
297298

298299
# Proposing Performance Improvements
299300

contributingGuides/STYLE.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -571,9 +571,7 @@ When you change the function id argument type to allow `undefined`, check if it
571571
572572
```diff
573573
function MoneyRequestView({report, shouldShowAnimatedBackground, readonly = false, updatedTransaction, isFromReviewDuplicates = false}: MoneyRequestViewProps) {
574-
const [parentReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, {
575-
canEvict: false,
576-
});
574+
const [parentReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`);
577575
- const parentReportAction = parentReportActions?.[report?.parentReportActionID ?? '-1'];
578576
+ const parentReportAction = parentReportActions?.[report?.parentReportActionID];
579577
```

contributingGuides/philosophies/ONYX-DATA-MANAGEMENT.md

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,7 @@ Different platforms come with varying storage capacities and Onyx has a way to g
3535

3636
**To flag a key as safe for removal:**
3737
- Add the key to the `evictableKeys` option in `Onyx.init(options)`
38-
- Implement `canEvict` in the Onyx config for each component subscribing to a key
39-
- The key will only be deleted when all subscribers return `true` for `canEvict`
40-
41-
Example:
42-
```js
43-
Onyx.init({
44-
evictableKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
45-
});
46-
47-
const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, {canEvict: !isActiveReport});
48-
```
38+
- A least recently accessed key will only be deleted when an Onyx operation retries after failing.
4939

5040
## Onyx Derived Values
5141

0 commit comments

Comments
 (0)