[Payment due @thelullabyy] Add itemized receipt changelog support and fix manual approval threshold bug#88065
Conversation
…old bug - Add UPDATE_MAX_EXPENSE_AMOUNT_NO_ITEMIZED_RECEIPT action type to CONST.ts - Add oldMaxExpenseAmountNoItemizedReceipt and newMaxExpenseAmountNoItemizedReceipt fields to OriginalMessage.ts - Add getPolicyChangeLogMaxExpenseAmountNoItemizedReceiptMessage function in ReportActionsUtils.ts - Add dispatch branches in PolicyChangeLogContent.tsx, ContextMenuActions.tsx, ReportNameUtils.ts, and SidebarUtils.ts - Add English, Spanish, and other language translations for set/changed/removed itemized receipt required amount - Fix getUpdatedManualApprovalThresholdMessage: check typeof newLimit instead of checking oldLimit twice - Add unit tests for the new itemized receipt message function Co-authored-by: Daniel Gale-Rosen <dangrous@users.noreply.github.com> Co-authored-by: thelullabyy <thelullabyy@users.noreply.github.com>
|
🤖 This PR replaces #87532 which had a corrupted git history (orphan branch). The same changes have been applied on top of current Key conflict resolution: All checks pass: prettier, typecheck (tsgo), and the code compiles cleanly. Please close #87532 and mark this PR as "Ready for review" when ready. |
🦜 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 e71d1dd7..24a778de 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -7314,9 +7314,9 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
setReceiptRequiredAmount: (newValue: string) => `Belegpflichtigen Betrag auf „${newValue}“ festlegen`,
changedReceiptRequiredAmount: (oldValue: string, newValue: string) => `Belegpflichtbetrag auf „${newValue}“ geändert (zuvor „${oldValue}“)`,
removedReceiptRequiredAmount: (oldValue: string) => `Belegpflichtigen Betrag entfernt (zuvor „${oldValue}”)`,
- setItemizedReceiptRequiredAmount: (newValue: string) => `Betrag für Pflicht zur Einzelauflistung auf „${newValue}” festgelegt`,
- changedItemizedReceiptRequiredAmount: (oldValue: string, newValue: string) => `erforderlichen Betrag des aufgeschlüsselten Belegs auf „${newValue}” geändert (zuvor „${oldValue}”)`,
- removedItemizedReceiptRequiredAmount: (oldValue: string) => `Betrag für obligatorische Einzelpostenbelege entfernt (zuvor „${oldValue}”)`,
+ setItemizedReceiptRequiredAmount: (newValue: string) => `festgelegten Betrag für erforderliche Einzelbelege auf „${newValue}“ setzen`,
+ changedItemizedReceiptRequiredAmount: (oldValue: string, newValue: string) => `Betrag für erforderlichen Einzelbeleg auf „${newValue}“ geändert (zuvor „${oldValue}“)`,
+ removedItemizedReceiptRequiredAmount: (oldValue: string) => `Betrag für erforderlichen Einzelbeleg entfernt (zuvor „${oldValue}“)`,
setMaxExpenseAmount: (newValue: string) => `maximalen Ausgabenbetrag auf „${newValue}“ festlegen`,
changedMaxExpenseAmount: (oldValue: string, newValue: string) => `hat den maximalen Ausgabenbetrag auf „${newValue}“ geändert (zuvor „${oldValue}“)`,
removedMaxExpenseAmount: (oldValue: string) => `maximale Ausgabenhöhe entfernt (zuvor „${oldValue}“)`,
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 7e4d3e84..3605dd36 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -5534,7 +5534,7 @@ _Pour des instructions plus détaillées, [visitez notre site d’aide](${CONST.
'Fréquence à laquelle Expensify prélèvera sur votre compte bancaire professionnel pour régler les transactions récentes d’Expensify Travel.',
monthlySpendLimitLabel: 'Limite de dépenses mensuelle par membre',
monthlySpendLimitDescription: 'Le montant maximum que chaque membre peut dépenser en déplacements par mois.',
- reduceLimitTitle: 'Réduire la limite de dépenses de voyage\u00A0?',
+ reduceLimitTitle: 'Réduire la limite de dépenses de voyage ?',
reduceLimitWarning:
'Si vous réduisez la limite, les membres ayant déjà dépensé plus que ce montant ne pourront pas effectuer de nouvelles réservations de voyage avant le mois prochain.',
},
@@ -7335,9 +7335,9 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
setReceiptRequiredAmount: (newValue: string) => `définir le montant de reçu obligatoire sur « ${newValue} »`,
changedReceiptRequiredAmount: (oldValue: string, newValue: string) => `a modifié le montant requis pour le reçu à « ${newValue} » (auparavant « ${oldValue} »)`,
removedReceiptRequiredAmount: (oldValue: string) => `a supprimé le montant requis pour le reçu (précédemment « ${oldValue} »)`,
- setItemizedReceiptRequiredAmount: (newValue: string) => `définir le montant requis pour le reçu détaillé sur « ${newValue} »`,
- changedItemizedReceiptRequiredAmount: (oldValue: string, newValue: string) => `a modifié le montant requis pour le reçu détaillé à « ${newValue} » (auparavant « ${oldValue} »)`,
- removedItemizedReceiptRequiredAmount: (oldValue: string) => `a supprimé le montant requis pour le reçu détaillé (précédemment « ${oldValue} »)`,
+ setItemizedReceiptRequiredAmount: (newValue: string) => `définir le montant requis pour le reçu détaillé sur « ${newValue} »`,
+ changedItemizedReceiptRequiredAmount: (oldValue: string, newValue: string) => `a modifié le montant du reçu détaillé requis à « ${newValue} » (auparavant « ${oldValue} »)`,
+ removedItemizedReceiptRequiredAmount: (oldValue: string) => `montant requis de reçu détaillé supprimé (précédemment « ${oldValue} »)`,
setMaxExpenseAmount: (newValue: string) => `définir le montant maximal de dépense sur « ${newValue} »`,
changedMaxExpenseAmount: (oldValue: string, newValue: string) => `montant maximal de dépense modifié en « ${newValue} » (précédemment « ${oldValue} »)`,
removedMaxExpenseAmount: (oldValue: string) => `montant de dépense maximal supprimé (précédemment « ${oldValue} »)`,
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 8b21d000..ebf90219 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -7300,10 +7300,10 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
setReceiptRequiredAmount: (newValue: string) => `imposta l’importo richiesto per la ricevuta su "${newValue}"`,
changedReceiptRequiredAmount: (oldValue: string, newValue: string) => `ha modificato l’importo richiesto per la ricevuta in "${newValue}" (in precedenza "${oldValue}")`,
removedReceiptRequiredAmount: (oldValue: string) => `ha rimosso l’importo richiesto per la ricevuta (in precedenza «${oldValue}»)`,
- setItemizedReceiptRequiredAmount: (newValue: string) => `imposta l’importo richiesto per la ricevuta con voci singole su "${newValue}"`,
+ setItemizedReceiptRequiredAmount: (newValue: string) => `imposta l’importo richiesto per la ricevuta dettagliata su "${newValue}"`,
changedItemizedReceiptRequiredAmount: (oldValue: string, newValue: string) =>
`ha modificato l’importo richiesto per la ricevuta con voci a "${newValue}" (in precedenza "${oldValue}")`,
- removedItemizedReceiptRequiredAmount: (oldValue: string) => `ha rimosso l’importo richiesto per la ricevuta dettagliata (precedentemente "${oldValue}")`,
+ removedItemizedReceiptRequiredAmount: (oldValue: string) => `ha rimosso l’importo richiesto per la ricevuta con dettaglio voci (precedentemente «${oldValue}»)`,
setMaxExpenseAmount: (newValue: string) => `imposta l’importo massimo della spesa su "${newValue}"`,
changedMaxExpenseAmount: (oldValue: string, newValue: string) => `ha modificato l'importo massimo della spesa a "${newValue}" (precedentemente "${oldValue}")`,
removedMaxExpenseAmount: (oldValue: string) => `importo massimo spesa rimosso (precedentemente "${oldValue}")`,
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index bce46aaa..bbacab22 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -7215,7 +7215,7 @@ ${reportName}
removedReceiptRequiredAmount: (oldValue: string) => `必須領収書金額を削除しました(以前の値:「${oldValue}」)`,
setItemizedReceiptRequiredAmount: (newValue: string) => `明細付き領収書の必須金額を「${newValue}」に設定しました`,
changedItemizedReceiptRequiredAmount: (oldValue: string, newValue: string) => `品目別レシートの必須金額を「${newValue}」(以前は「${oldValue}」)に変更しました`,
- removedItemizedReceiptRequiredAmount: (oldValue: string) => `品目別レシートの必須金額を削除しました(以前の値:「${oldValue}」)`,
+ removedItemizedReceiptRequiredAmount: (oldValue: string) => `明細化された領収書の必須金額を削除しました(以前の値:「${oldValue}」)`,
setMaxExpenseAmount: (newValue: string) => `最大経費金額を「${newValue}」に設定`,
changedMaxExpenseAmount: (oldValue: string, newValue: string) => `上限経費額を「${newValue}」に変更しました(以前は「${oldValue}」)`,
removedMaxExpenseAmount: (oldValue: string) => `最大経費金額を削除しました(以前の値: 「${oldValue}」)`,
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 130b06a3..07ef31ee 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -7278,10 +7278,10 @@ Voeg meer bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
setReceiptRequiredAmount: (newValue: string) => `stel het vereiste bonbedrag in op "${newValue}"`,
changedReceiptRequiredAmount: (oldValue: string, newValue: string) => `heeft het vereiste bonbedrag gewijzigd naar "${newValue}" (voorheen "${oldValue}")`,
removedReceiptRequiredAmount: (oldValue: string) => `vereiste bedrag op verwijderde bon (voorheen “${oldValue}”)`,
- setItemizedReceiptRequiredAmount: (newValue: string) => `stel het vereiste bedrag voor de gespecificeerde bon in op "${newValue}"`,
+ setItemizedReceiptRequiredAmount: (newValue: string) => `bedrag voor gespecificeerde bon ingesteld op ‘${newValue}’`,
changedItemizedReceiptRequiredAmount: (oldValue: string, newValue: string) =>
- `heeft het vereiste bedrag voor gespecificeerde bonnen gewijzigd naar "${newValue}" (voorheen "${oldValue}")`,
- removedItemizedReceiptRequiredAmount: (oldValue: string) => `vereist bedrag voor gespecificeerde bon verwijderd (voorheen "${oldValue}")`,
+ `heeft het vereiste bedrag voor gespecificeerde bonnen gewijzigd naar ‘${newValue}’ (voorheen ‘${oldValue}’)`,
+ removedItemizedReceiptRequiredAmount: (oldValue: string) => `heeft het vereiste bedrag voor gespecificeerde bonnen verwijderd (voorheen "${oldValue}")`,
setMaxExpenseAmount: (newValue: string) => `maximumbedrag voor uitgave instellen op "${newValue}"`,
changedMaxExpenseAmount: (oldValue: string, newValue: string) => `maximale onkostensom gewijzigd naar "${newValue}" (voorheen "${oldValue}")`,
removedMaxExpenseAmount: (oldValue: string) => `maximaal bedrag voor uitgave verwijderd (voorheen "${oldValue}")`,
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 5b8d5db8..aaa3673e 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -7268,9 +7268,9 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`,
setReceiptRequiredAmount: (newValue: string) => `ustaw wymaganą kwotę paragonu na „${newValue}”`,
changedReceiptRequiredAmount: (oldValue: string, newValue: string) => `zmienił(a) wymaganą kwotę paragonu na „${newValue}” (wcześniej „${oldValue}”)`,
removedReceiptRequiredAmount: (oldValue: string) => `usunięto wymagany limit paragonu (wcześniej „${oldValue}”)`,
- setItemizedReceiptRequiredAmount: (newValue: string) => `ustaw wymaganą kwotę z wyszczególnionego paragonu na „${newValue}”`,
- changedItemizedReceiptRequiredAmount: (oldValue: string, newValue: string) => `zmienił wymaganą kwotę za zindeksowany paragon na „${newValue}” (wcześniej „${oldValue}”)`,
- removedItemizedReceiptRequiredAmount: (oldValue: string) => `usunięto wymaganą kwotę z rozbitego paragonu (wcześniej „${oldValue}”)`,
+ setItemizedReceiptRequiredAmount: (newValue: string) => `ustaw wymaganą kwotę z rozbiciem paragonu na „${newValue}”`,
+ changedItemizedReceiptRequiredAmount: (oldValue: string, newValue: string) => `zmienił wymaganą kwotę z wyszczególnionym paragonem na „${newValue}” (wcześniej „${oldValue}”)`,
+ removedItemizedReceiptRequiredAmount: (oldValue: string) => `usunięto wymaganą kwotę z paragonu ze szczegółami (wcześniej „${oldValue}”)`,
setMaxExpenseAmount: (newValue: string) => `ustaw maksymalną kwotę wydatku na „${newValue}”`,
changedMaxExpenseAmount: (oldValue: string, newValue: string) => `zmieniono maksymalną kwotę wydatku na „${newValue}” (wcześniej „${oldValue}”)`,
removedMaxExpenseAmount: (oldValue: string) => `usunięto maksymalną kwotę wydatku (wcześniej „${oldValue}”)`,
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 56ae3263..66d7690c 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -7270,9 +7270,9 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`,
setReceiptRequiredAmount: (newValue: string) => `definir valor exigido do recibo como "${newValue}"`,
changedReceiptRequiredAmount: (oldValue: string, newValue: string) => `alterou o valor obrigatório do recibo para "${newValue}" (antes "${oldValue}")`,
removedReceiptRequiredAmount: (oldValue: string) => `removeu o valor obrigatório do recibo (antes era "${oldValue}")`,
- setItemizedReceiptRequiredAmount: (newValue: string) => `definir o valor obrigatório do recibo detalhado como "${newValue}"`,
+ setItemizedReceiptRequiredAmount: (newValue: string) => `definir valor exigido de recibo detalhado como "${newValue}"`,
changedItemizedReceiptRequiredAmount: (oldValue: string, newValue: string) => `alterou o valor obrigatório do recibo detalhado para "${newValue}" (antes "${oldValue}")`,
- removedItemizedReceiptRequiredAmount: (oldValue: string) => `removeu o valor exigido de recibo detalhado (antes era "${oldValue}")`,
+ removedItemizedReceiptRequiredAmount: (oldValue: string) => `removeu o valor obrigatório do recibo detalhado (antes "${oldValue}")`,
setMaxExpenseAmount: (newValue: string) => `definir valor máximo da despesa como "${newValue}"`,
changedMaxExpenseAmount: (oldValue: string, newValue: string) => `alterou o valor máximo da despesa para "${newValue}" (antes "${oldValue}")`,
removedMaxExpenseAmount: (oldValue: string) => `removeu o valor máximo de despesa (anteriormente "${oldValue}")`,
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 8a955441..9dbbbd55 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -7087,9 +7087,9 @@ ${reportName}
setReceiptRequiredAmount: (newValue: string) => `将需要收据的金额设置为“${newValue}”`,
changedReceiptRequiredAmount: (oldValue: string, newValue: string) => `已将所需收据金额更改为“${newValue}”(之前为“${oldValue}”)`,
removedReceiptRequiredAmount: (oldValue: string) => `已移除所需收据金额(先前为“${oldValue}”)`,
- setItemizedReceiptRequiredAmount: (newValue: string) => `将分项收据所需金额设置为”${newValue}”`,
- changedItemizedReceiptRequiredAmount: (oldValue: string, newValue: string) => `将逐项列示收据的必填金额更改为 “${newValue}”(之前为 “${oldValue}”)`,
- removedItemizedReceiptRequiredAmount: (oldValue: string) => `已移除按项目明细收据所需金额(先前为”${oldValue}”)`,
+ setItemizedReceiptRequiredAmount: (newValue: string) => `将分项目收据所需金额设置为“${newValue}”`,
+ changedItemizedReceiptRequiredAmount: (oldValue: string, newValue: string) => `已将逐项收据必填金额更改为“${newValue}”(原为“${oldValue}”)`,
+ removedItemizedReceiptRequiredAmount: (oldValue: string) => `已移除逐项收据所需金额(之前为“${oldValue}”)`,
setMaxExpenseAmount: (newValue: string) => `将最高报销金额设置为”${newValue}”`,
changedMaxExpenseAmount: (oldValue: string, newValue: string) => `将最高报销金额更改为 “${newValue}”(之前为 “${oldValue}”)`,
removedMaxExpenseAmount: (oldValue: string) => `已移除最⾼报销金额(原为“${oldValue}”)`,
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
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.
|
|
@thelullabyy making sure you saw this new PR that melvin created for some reason |
|
@MelvinBot Please tick all the checkboxes in PR desc and open this PR for review |
|
🤖 Done! I've:
|
Reviewer Checklist
Screenshots/VideosiOS: HybridAppMacOS: Chrome / SafariScreen.Recording.2026-04-29.at.11.18.39.mov |
|
@jjcoffee Looks like there is a mistake in auto assignment. Please ignore this PR. I will review it. Thx |
|
@codex review |
| setReceiptRequiredAmount: (newValue) => `estableció el importe requerido del recibo en "${newValue}"`, | ||
| changedReceiptRequiredAmount: (oldValue, newValue) => `cambió el importe requerido del recibo a "${newValue}" (antes "${oldValue}")`, | ||
| removedReceiptRequiredAmount: (oldValue) => `eliminó el importe requerido del recibo (antes "${oldValue}")`, | ||
| setItemizedReceiptRequiredAmount: (newValue) => `estableció el importe requerido del recibo detallado en "${newValue}"`, |
| setReceiptRequiredAmount: (newValue: string) => `set receipt required amount to "${newValue}"`, | ||
| changedReceiptRequiredAmount: (oldValue: string, newValue: string) => `changed receipt required amount to "${newValue}" (previously "${oldValue}")`, | ||
| removedReceiptRequiredAmount: (oldValue: string) => `removed receipt required amount (previously "${oldValue}")`, | ||
| setItemizedReceiptRequiredAmount: (newValue: string) => `set itemized receipt required amount to "${newValue}"`, |
|
Codex Review: Didn't find any major issues. Breezy! ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
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". |
|
@MelvinBot Please add this test case to QA Steps and Tests part in PR description
|
|
Updated the PR description — added the test case to both the Tests and QA Steps sections. |
thelullabyy
left a comment
There was a problem hiding this comment.
LGTM!
But... we still need Spanish copy confirmation here
|
🎯 @thelullabyy, thanks for reviewing and testing this PR! 🎉 A payment issue will be created for your review once this PR is deployed to production. If payment is not needed (e.g., regression PR review fix etc), react with 👎 to this comment to prevent the payment issue from being created. |
|
@dangrous looks like Melvin failed for assignment... Ping you here to make sure u know it |
|
Ah, annoying, will look! |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚧 @dangrous 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! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/dangrous in version: 9.3.67-0 🚀
Bundle Size Analysis (Sentry): |
|
No help site changes are required for this PR. Reason: This PR adds frontend display support for changelog messages (shown in the #admin room) when the "Itemized receipt required amount" setting is changed, and fixes a bug in the manual approval threshold message. The underlying feature — setting itemized receipt required amounts — already exists and is already documented in the help site:
Since no new user-facing features, UI labels, or workflows were added or changed, no docs updates are needed. |
|
🚀 Deployed to production by https://github.com/francoisl in version: 9.3.67-13 🚀
|
|
🤖 Payment issue created: #89823 |



Explanation of Change
This PR adds frontend support for the itemized receipt changelog action type and fixes a bug in the manual approval threshold message, to match the formatting changes made in https://github.com/Expensify/Web-Expensify/pull/51501.
Itemized receipt changelog:
UPDATE_MAX_EXPENSE_AMOUNT_NO_ITEMIZED_RECEIPTaction type toCONST.tsoldMaxExpenseAmountNoItemizedReceiptandnewMaxExpenseAmountNoItemizedReceiptfields toOriginalMessage.tsgetPolicyChangeLogMaxExpenseAmountNoItemizedReceiptMessagefunction inReportActionsUtils.ts(mirrors the existingNoReceiptversion)PolicyChangeLogContent.tsx,ContextMenuActions.tsx,ReportNameUtils.ts, andSidebarUtils.tsBug fix:
getUpdatedManualApprovalThresholdMessagewhich checkedtypeof oldLimit !== 'number'twice instead of checkingnewLimiton the second clause. This meantnewLimitwas never validated, so if it wasundefined, the function would produce incorrect output instead of falling back togetReportActionText.Note: This replaces #87532 which had a corrupted git history (orphan branch with no shared ancestry to
main). The changes have been rebased onto currentmainwith conflict resolution — notably adapting to the newPolicyChangeLogContent.tsxarchitecture and adding entries toContextMenuActions.tsxandReportNameUtils.ts.Fixed Issues
$ https://github.com/Expensify/Expensify/issues/616183
Tests
Itemized receipt required amountset itemized receipt required amount to "$AMOUNT"/removed itemized receipt required amount (previously "$AMOUNT")Offline tests
N/A - these are display-only changes for server-generated report actions.
QA Steps
Itemized receipt required amountset itemized receipt required amount to "$AMOUNT"/removed itemized receipt required amount (previously "$AMOUNT")PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))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.ScrollViewcomponent to make it scrollable when more elements are added to the page.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
N/A - display-only changelog text changes
Android: mWeb Chrome
N/A - display-only changelog text changes
iOS: Native
N/A - display-only changelog text changes
iOS: mWeb Safari
N/A - display-only changelog text changes
MacOS: Chrome / Safari
N/A - display-only changelog text changes