Repository navigation
[Insights] Stop plotting future periods and future-dated expenses on Spend, also don't show months with no data on Compliance - #106514
Conversation
|
Hey, I noticed you changed If you want to automatically generate translations for other locales, an Expensify employee will have to:
Alternatively, if you are an external contributor, you can run the translation script locally with your own OpenAI API key. To learn more, try running: npx bun ./scripts/generateTranslations.ts --helpTypically, you'd want to translate only what you changed by running |
🦜 Polyglot Parrot! 🦜Squawk! Looks like you added some shiny new English strings. Allow me to parrot them back to you in other tongues: View the translation diffdiff --git a/src/languages/de.ts b/src/languages/de.ts
index d4075d6b..98277c64 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -1258,6 +1258,8 @@ const translations: TranslationDeepObject<typeof en> = {
viewAll: 'Alle anzeigen',
topExpenses: 'Top-Ausgaben',
noExpensesInRange: 'Keine Ausgaben in diesem Bereich',
+ futureExpensesNotShown: (amount: string) => `Nicht angezeigt: ${amount} in zukünftigen Ausgaben.`,
+ violationsTrackedFrom: (date: string) => `Verstöße werden ab dem ${date} erfasst.`,
},
allSettingsScreen: {
subscription: 'Abonnement',
diff --git a/src/languages/el.ts b/src/languages/el.ts
index ba409a10..43e0ed0b 100644
--- a/src/languages/el.ts
+++ b/src/languages/el.ts
@@ -1304,6 +1304,8 @@ const translations: TranslationDeepObject<typeof en> = {
viewAll: 'Προβολή όλων',
topExpenses: 'Κορυφαίες δαπάνες',
noExpensesInRange: 'Δεν υπάρχουν δαπάνες σε αυτό το εύρος',
+ futureExpensesNotShown: (amount: string) => `Δεν εμφανίζονται: ${amount} σε μελλοντικές δαπάνες.`,
+ violationsTrackedFrom: (date: string) => `Οι παραβάσεις παρακολουθούνται από ${date}.`,
},
allSettingsScreen: {
subscription: 'Συνδρομή',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 37fdf70e..a52daa93 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1252,6 +1252,8 @@ const translations: TranslationDeepObject<typeof en> = {
viewAll: 'Ver todo',
topExpenses: 'Gastos principales',
noExpensesInRange: 'No hay gastos en este intervalo',
+ futureExpensesNotShown: (amount: string) => `No se muestran: ${amount} en gastos futuros.`,
+ violationsTrackedFrom: (date: string) => `Las infracciones se registran desde el ${date}.`,
},
allSettingsScreen: {
subscription: 'Suscripcion',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index d487a103..54ef0511 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -1265,6 +1265,8 @@ const translations: TranslationDeepObject<typeof en> = {
viewAll: 'Tout afficher',
topExpenses: 'Dépenses principales',
noExpensesInRange: 'Aucune dépense dans cette plage',
+ futureExpensesNotShown: (amount: string) => `Non affiché : ${amount} en dépenses futures.`,
+ violationsTrackedFrom: (date: string) => `Les violations sont suivies à partir du ${date}.`,
},
allSettingsScreen: {
subscription: 'Abonnement',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 79c3e93c..ae61a06a 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -1261,6 +1261,8 @@ const translations: TranslationDeepObject<typeof en> = {
viewAll: 'Vedi tutto',
topExpenses: 'Spese principali',
noExpensesInRange: 'Nessuna spesa in questo intervallo',
+ futureExpensesNotShown: (amount: string) => `Non mostrato: ${amount} in spese future.`,
+ violationsTrackedFrom: (date: string) => `Le violazioni vengono tracciate a partire dal ${date}.`,
},
allSettingsScreen: {
subscription: 'Abbonamento',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 2eaad98e..3310d11d 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -1246,6 +1246,8 @@ const translations: TranslationDeepObject<typeof en> = {
viewAll: 'すべて表示',
topExpenses: '上位の経費',
noExpensesInRange: 'この範囲内に経費はありません',
+ futureExpensesNotShown: (amount: string) => `非表示:将来の経費に${amount}あります。`,
+ violationsTrackedFrom: (date: string) => `違反は${date}から追跡されます。`,
},
allSettingsScreen: {
subscription: 'サブスクリプション',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index fc4e7c40..a41fa1f9 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -1257,6 +1257,8 @@ const translations: TranslationDeepObject<typeof en> = {
viewAll: 'Alles bekijken',
topExpenses: 'Belangrijkste uitgaven',
noExpensesInRange: 'Geen uitgaven in dit bereik',
+ futureExpensesNotShown: (amount: string) => `Niet weergegeven: ${amount} aan toekomstige uitgaven.`,
+ violationsTrackedFrom: (date: string) => `Overtredingen worden bijgehouden vanaf ${date}.`,
},
allSettingsScreen: {
subscription: 'Abonnement',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index df6e36b5..257810e0 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -1284,6 +1284,8 @@ const translations: TranslationDeepObject<typeof en> = {
viewAll: 'Zobacz wszystko',
topExpenses: 'Najwyższe wydatki',
noExpensesInRange: 'Brak wydatków w tym zakresie',
+ futureExpensesNotShown: (amount: string) => `Nie pokazano: ${amount} w przyszłych wydatkach.`,
+ violationsTrackedFrom: (date: string) => `Naruszenia są śledzone od ${date}.`,
},
allSettingsScreen: {
subscription: 'Subskrypcja',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index eb282b53..a967c815 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -1260,6 +1260,8 @@ const translations: TranslationDeepObject<typeof en> = {
viewAll: 'Ver tudo',
topExpenses: 'Maiores despesas',
noExpensesInRange: 'Nenhuma despesa nesse intervalo',
+ futureExpensesNotShown: (amount: string) => `Não mostrado: ${amount} em despesas futuras.`,
+ violationsTrackedFrom: (date: string) => `Violações são registradas a partir de ${date}.`,
},
allSettingsScreen: {
subscription: 'Assinatura',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 981594ba..07d665fa 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -1207,6 +1207,8 @@ const translations: TranslationDeepObject<typeof en> = {
viewAll: '查看全部',
topExpenses: '最高花费',
noExpensesInRange: '此范围内没有报销费用',
+ futureExpensesNotShown: (amount: string) => `未显示:未来报销金额 ${amount}。`,
+ violationsTrackedFrom: (date: string) => `从 ${date} 起开始记录违规情况。`,
},
allSettingsScreen: {
subscription: '订阅',
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
|
🚧 JmillsExpensify has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
I just took the adhoc for a spin. Looking great so far, though the future-dated expenses notice didn't seem to work for me. The total it showed on the Insight didn't match the number that I saw on the Spend page. |
…ghts-Plotted-Periods # Conflicts: # src/pages/Insights/insightsQueries.ts # src/types/onyx/InsightsDashboard.ts # src/types/onyx/index.ts
… Home widget change
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
@JmillsExpensify I pushed a few changes and I think everything should line up now, with two exceptions. The Compliance average isn't covered yet and the Home widget will get these changes in a follow-up, since it needs proper syncing between the |
|
@MelvinBot withdraw the review request from @daledah |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ed4148065c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (!from && !to) { | ||
| return {}; | ||
| } | ||
| return {[FILTER_KEYS.DATE_RANGE]: getRangeQueryValue(from, to)}; |
There was a problem hiding this comment.
Retain the untouched side of custom date ranges
When a custom range needs only an upper cap (for example Oct 1–31 with asOfDate Oct 8), buildFilterFormValues has already supplied one DATE_RANGE, but this return overwrites it with date<=2026-10-08 because from is undefined; View on Spend and ranking-chart Details then include every older expense. The symmetric trackedFrom-only case drops the original end too, so construct the replacement from the later original/tracking start and the earlier original/last day rather than omitting unchanged bounds.
Useful? React with 👍 / 👎.
| /> | ||
| asOfDate={asOfDate} | ||
| > | ||
| {!!asOfDate && !!futureExpenses?.count && ( |
There was a problem hiding this comment.
Keep exclusion notes reachable for empty dashboards
When the selected Spend range contains only expenses after asOfDate, all graph snapshots have no counted rows, so getDashboardState resolves EMPTY/NO_EXPENSES and the stand-in branch returns before this InsightsChartWidget and its note child are mounted. The same happens for a Compliance range wholly before trackedFrom, leaving users with a generic empty state and no View link or tracking-start explanation; render these notes in the stand-in path or avoid the stand-in when excluded data explains the empty result.
Useful? React with 👍 / 👎.
|
Withdrew the review request from |
| {...buildFilterFormValues(filters, true, chart.dateFilterKey), has: chart.has, groupBy: chart.groupBy ?? getQueryGroupBy(filters), view: chart.view, compare}, | ||
| { | ||
| ...buildFilterFormValues(filters, true, chart.dateFilterKey), | ||
| ...(!!lastDay && isExpenseDateChart && buildDataDaysFormValues(filters.date, lastDay, chart.trackedFrom)), |
There was a problem hiding this comment.
With a stored range of Oct 1 – Dec 31 (today Nov 13), "View on Spend" opens with just date<=2026-11-13, so the list goes back to Dec 2024:
Screen.Recording.2026-11-13.at.15.07.51.mov
There was a problem hiding this comment.
Looks like the stopping-at-today tests only use presets. Maybe add a custom range that runs past today, and one that starts before Jun 1? Either one would've caught the range losing an end.
Explanation of Change
Stops Spend over time at today. The current line ends at the period that contains today. With
Compare: Previous periodthe compared line runs through the whole date range, which drops the rule from #105150 that ended the chart at the compared period's last expense.This monthoffers onlyDay,This quarteronlyWeekandThis yearWeekandMonth, since other groupings would plot one or two mostly partial points.GetInsightsleaves out expenses dated afterasOfDateand returns them infutureExpenses, shown asNot shown: $X in future expenses. View. The charts, CSV export and Details panel take today fromasOfDate(getInsightsLastDay), so they stop on the same day as the data. Home is unchanged. On Compliance, Violations over time leaves out buckets before Jun 1, 2026 (CONST.INSIGHTS.VIOLATIONS_TRACKED_FROM) and showsViolations are tracked from Jun 1, 2026.when the range or compared period starts earlier, as agreed in #105266. Date range and note code is extracted intogetInsightsDateRangeandInsightsChartNote, with no change in behavior.Note
Both notes sit below the chart, matching the design mock in the issue. The issue text says "below its header and above the plot".
Note
The Insights widget on Home gets these changes in a follow-up.
Warning
The Compare: Average line on Violations over time is computed over the whole date range, including the months before Jun 1, 2026.
The average comes from
GetInsights, which counts the months with no recorded violations as zero, so forThis yearit reads lower than the tracked months alone. Needs a backend change.Fixed Issues
$ #105790
$ #102809
Tests
Precondition: account with the
insightsCompliancebeta that is an admin of a Control workspace. The workspace has violations recorded after Jun 1, 2026 and expenses in the current month, some of them dated after today.This monthand Group by toDay. Verify Spend over time ends at today and draws nothing, not even $0, for later days.Not shown: <amount> in future expenses. Viewshows below the chart. PressViewand verify Spend opens with expenses dated after today through the end of the month, in the dashboard's workspaces.Previous periodand verify the previous month's line runs through the whole month while the current line stops at today.This monthoffers onlyDay,This quarteronlyWeekandThis yearWeekandMonth. VerifyLast monthstill offersWeek.Weekselected onLast month, switch Date toThis monthand verify the pill showsDay.This yearand Group by toMonth. Verify Violations over time starts at June andViolations are tracked from Jun 1, 2026.shows below the chart.Previous periodand verify no compared line is drawn and the note still shows.Last 30 dayswith Compare off and verify the note is hidden.Offline tests
This month, then go offline.QA Steps
Same as tests
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
Screen.Recording.2026-11-12.at.19.40.31.mov