Skip to content

Commit dc3daaa

Browse files
committed
Merge branch 'main' into chore/user-avatar-for-single-avatar-usages
2 parents 5342cf3 + 1025e4d commit dc3daaa

550 files changed

Lines changed: 25561 additions & 5176 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.

.github/actions/javascript/isDeployChecklistLocked/index.js

Lines changed: 17 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -13031,24 +13031,6 @@ function ReportHistoryStore(API, PubSub) {
1303113031
* @returns {Object[]}
1303213032
*/
1303313033
const filterHiddenActions = (historyItems) => historyItems.filter((historyItem) => historyItem.shouldShow);
13034-
/**
13035-
* Merges history items into the cache and creates it if it doesn't yet exist.
13036-
*
13037-
* @param {Number} reportID
13038-
* @param {Object[]} newHistory
13039-
*/
13040-
function mergeItems(reportID, newHistory) {
13041-
if (newHistory.length === 0) {
13042-
return;
13043-
}
13044-
const newCache = newHistory.reverse().reduce((prev, curr) => {
13045-
if (!prev.some((item) => item.sequenceNumber === curr.sequenceNumber)) {
13046-
prev.unshift(curr);
13047-
}
13048-
return prev;
13049-
}, store.cache[reportID] || []);
13050-
store.cache[reportID] = newCache.sort((a, b) => b.sequenceNumber - a.sequenceNumber);
13051-
}
1305213034
/**
1305313035
* Merges history items into the cache and creates it if it doesn't yet exist.
1305413036
*
@@ -13086,51 +13068,38 @@ function ReportHistoryStore(API, PubSub) {
1308613068
store.cache[reportID] = newCache.sort((a, b) => b.reportActionTimestamp - a.reportActionTimestamp);
1308713069
}
1308813070
/**
13089-
* Gets the history.
13071+
* Gets the history. This flow does not depend on the deprecated sequence number in report actions.
1309013072
*
1309113073
* @param {Number} reportID
1309213074
* @param {Boolean} ignoreCache
1309313075
* @returns {Deferred}
1309413076
*/
13095-
function get(reportID, ignoreCache) {
13077+
function getFlatHistory(reportID, ignoreCache) {
1309613078
const promise = new simply_deferred_1.Deferred();
1309713079
if (ignoreCache) {
1309813080
delete store.cache[reportID];
1309913081
}
13100-
const cachedHistory = store.cache[reportID] || [];
13101-
const firstHistoryItem = cachedHistory[0] || {};
1310213082
store.API.Report_GetHistory({
1310313083
reportID,
13104-
offset: firstHistoryItem.sequenceNumber || 0,
1310513084
})
1310613085
.done((recentHistory) => {
13107-
mergeItems(reportID, recentHistory);
13086+
mergeHistoryByReportActionID(reportID, recentHistory);
1310813087
promise.resolve(store.cache[reportID]);
1310913088
})
1311013089
.fail(promise.reject);
1311113090
return promise;
1311213091
}
1311313092
/**
13114-
* Gets the history. This flow does not depend on the deprecated sequence number in report actions.
13093+
* Gets the history.
13094+
*
13095+
* @deprecated use getFlatHistory instead.
1311513096
*
1311613097
* @param {Number} reportID
1311713098
* @param {Boolean} ignoreCache
1311813099
* @returns {Deferred}
1311913100
*/
13120-
function getFlatHistory(reportID, ignoreCache) {
13121-
const promise = new simply_deferred_1.Deferred();
13122-
if (ignoreCache) {
13123-
delete store.cache[reportID];
13124-
}
13125-
store.API.Report_GetHistory({
13126-
reportID,
13127-
})
13128-
.done((recentHistory) => {
13129-
mergeHistoryByReportActionID(reportID, recentHistory);
13130-
promise.resolve(store.cache[reportID]);
13131-
})
13132-
.fail(promise.reject);
13133-
return promise;
13101+
function get(reportID, ignoreCache) {
13102+
return getFlatHistory(reportID, ignoreCache);
1313413103
}
1313513104
/**
1313613105
* Gets the history from the cache if it exists. Otherwise fully loads the history.
@@ -13147,6 +13116,15 @@ function ReportHistoryStore(API, PubSub) {
1314713116
return promise.resolve(cachedHistory);
1314813117
}
1314913118
return {
13119+
/**
13120+
* Gets the history.
13121+
*
13122+
* @deprecated use getFlatHistory instead.
13123+
*
13124+
* @param {Number} reportID
13125+
* @param {Boolean} ignoreCache
13126+
* @returns {Deferred}
13127+
*/
1315013128
get: (reportID, ignoreCache = false) => {
1315113129
const promise = new simply_deferred_1.Deferred();
1315213130
get(reportID, ignoreCache)
@@ -13165,22 +13143,6 @@ function ReportHistoryStore(API, PubSub) {
1316513143
.fail(promise.reject);
1316613144
return promise;
1316713145
},
13168-
insertIntoCache: (reportID, reportAction) => {
13169-
const promise = new simply_deferred_1.Deferred();
13170-
getFromCache(reportID)
13171-
.done((cachedHistory) => {
13172-
const sequenceNumber = reportAction.sequenceNumber;
13173-
if (cachedHistory.length >= sequenceNumber) {
13174-
mergeItems(reportID, [reportAction]);
13175-
return promise.resolve(filterHiddenActions(store.cache[reportID]));
13176-
}
13177-
get(reportID)
13178-
.done((reportHistory) => promise.resolve(filterHiddenActions(reportHistory)))
13179-
.fail(promise.reject);
13180-
})
13181-
.fail(promise.reject);
13182-
return promise;
13183-
},
1318413146
insertIntoCacheByActionID: (reportID, reportAction) => {
1318513147
const promise = new simply_deferred_1.Deferred();
1318613148
getFromCache(reportID)

.github/workflows/lint.yml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,32 @@ jobs:
3333
- name: Setup Node
3434
uses: ./.github/actions/composite/setupNode
3535

36-
- name: Remove E/App version from package-lock.json
36+
# Extract only the lint-affecting dependencies: eslint packages, the parser chain
37+
# (espree/acorn) whose bumps can silently change parse results, plus
38+
# typescript/ts-api-utils since a TS bump can change type-aware lint results.
39+
# The cache key hashes this slice so a cold full re-lint happens only when
40+
# the lint config or a lint dependency changes -- not on every dep bump.
41+
- name: Extract lint-related deps from package-lock.json
3742
shell: bash
38-
run: jq 'del(.version, .packages[""].version)' package-lock.json > normalized-package-lock.json
43+
run: |
44+
jq '{packages: (.packages | to_entries | map(select(.key | test("eslint|espree|acorn|^node_modules/(typescript|ts-api-utils)$"))) | from_entries)}' package-lock.json > lint-deps-lock.json
45+
46+
# The setupNode sticky disk persists all of node_modules between runs, including
47+
# node_modules/.cache/eslint. Clear it so the restore step below is the only cache
48+
# source -- a restore miss doesn't delete pre-existing files, so without this a
49+
# config change would silently reuse the stale cache carried over by the disk.
50+
- name: Clear ESLint cache carried over by the node_modules sticky disk
51+
shell: bash
52+
run: rm -rf node_modules/.cache/eslint
3953

4054
- name: Restore ESLint cache
4155
# v5.0.1
4256
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb
4357
with:
4458
path: node_modules/.cache/eslint
45-
key: ${{ runner.os }}-eslint-${{ hashFiles('eslint.config.mjs', 'config/eslint/**', 'normalized-package-lock.json') }}-${{ github.sha }}
59+
key: ${{ runner.os }}-eslint-${{ hashFiles('eslint.config.mjs', 'config/eslint/**', 'lint-deps-lock.json') }}-${{ github.sha }}
4660
restore-keys: |
47-
${{ runner.os }}-eslint-${{ hashFiles('eslint.config.mjs', 'config/eslint/**', 'normalized-package-lock.json') }}-
48-
${{ runner.os }}-eslint-
61+
${{ runner.os }}-eslint-${{ hashFiles('eslint.config.mjs', 'config/eslint/**', 'lint-deps-lock.json') }}-
4962
5063
# ESLint's cache doesn't track cross-file TypeScript dependencies, which can cause stale errors.
5164
# If lint fails, we clear the cache and retry to rule out false positives.
@@ -69,7 +82,7 @@ jobs:
6982
if: always()
7083
with:
7184
path: node_modules/.cache/eslint
72-
key: ${{ runner.os }}-eslint-${{ hashFiles('eslint.config.mjs', 'config/eslint/**', 'normalized-package-lock.json') }}-${{ github.sha }}
85+
key: ${{ runner.os }}-eslint-${{ hashFiles('eslint.config.mjs', 'config/eslint/**', 'lint-deps-lock.json') }}-${{ github.sha }}
7386

7487
# If lint tightened the seatbelt baseline (i.e. fewer baselined errors than last time),
7588
# commit the updated TSV back to `main` as OSBotify. Only runs under `workflow_call`

CLAUDE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,13 @@ Major action categories:
157157
- `Search.ts`: Search operations
158158
- `Travel.ts`: Travel features
159159

160+
### Reading Onyx data (`useOnyx` vs `Onyx.connectWithoutView`)
161+
There are only two ways to read Onyx data:
162+
1. **`useOnyx`** (`@hooks/useOnyx`) — the default for anything a component renders.
163+
2. **`Onyx.connectWithoutView`** — only for non-render logic (module-level state in actions/libraries) that genuinely can't use `useOnyx`.
164+
165+
Before either, prefer a **pure function** that receives the data as parameters: it does not read Onyx itself — the caller reads (with `useOnyx` or `Onyx.connectWithoutView`) and passes the data in. Do not add a new `Onyx.connectWithoutView` by copying existing usage — justify each one on its own with a comment explaining why it is needed. Using it in a component for performance requires `@frontend-performance` approval on Slack (link it in the PR description). See [Onyx Data Management](contributingGuides/philosophies/ONYX-DATA-MANAGEMENT.md#reading-onyx-data-useonyx-vs-onyxconnectwithoutview).
166+
160167
## Build & Deployment
161168

162169
### CI/CD Workflows

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 1009044800
115-
versionName "9.4.48-0"
114+
versionCode 1009045000
115+
versionName "9.4.50-0"
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"

assets/images/july26-promo.png

48.5 KB
Loading

config/eslint/eslint.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ const config = defineConfig([
746746
'web/snippets/gib.js',
747747
// Generated language files - excluded from ESLint but still type-checked
748748
'src/languages/de.ts',
749+
'src/languages/el.ts',
749750
'src/languages/es.ts',
750751
'src/languages/fr.ts',
751752
'src/languages/it.ts',

0 commit comments

Comments
 (0)