[No QA] [Bulk workspace edits] Add CopyPolicySettings action file and tests#89963
[No QA] [Bulk workspace edits] Add CopyPolicySettings action file and tests#89963fedirjh wants to merge 17 commits intoExpensify:mainfrom
Conversation
Adds the failure RBR message used when a bulk Copy Policy Settings request fails. Defined across all ten language files so the TranslationPaths type accepts it.
Implements the Onyx + API logic for the bulk Copy Policy Settings flow. Exports: - setCopyPolicySettingsData / clearCopyPolicySettings — Onyx helpers - requestCopyPolicySettingsNotification — fires CopyPolicySettings_Notify - PARTS_TO_POLICY_FIELDS — part key → list of Policy field names; drives pendingFields expansion so OfflineWithFeedback wrappers grey out per-tab during the copy - buildCopyPolicySettingsData — produces optimistic/success/failure Onyx updates following the four-step algorithm in the design doc: field patch from source, per-target merge with snapshot rollback, SET-level overwrite of POLICY_CATEGORIES / POLICY_TAGS collection keys, and currentStep lifecycle on COPY_POLICY_SETTINGS - copyPolicySettings — entry point that calls API.write customUnits handling preserves each target's existing distance / per-diem unit ID and only generates a new hex ID when the target has no unit of that type yet.
Covers the four behaviors required by the design doc: - each part key in isolation patches the right Policy fields and marks each one pending - SET-level overwrite of POLICY_CATEGORIES and POLICY_TAGS collection keys, with failure data restoring the target's snapshot - failure data restores the target's pre-copy field values - customUnits preservation: target's existing distance / per-diem unit ID is reused; a new ID is generated only when absent
|
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 ts-node ./scripts/generateTranslations.ts --helpTypically, you'd want to translate only what you changed by running |
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
Switches from `import type * as OnyxCommon` to `import type {Errors}`
to satisfy the no-restricted-syntax rule that disallows namespace
imports from sibling modules.
Replaces `import * as` namespace imports for `@libs/API`, `@libs/ErrorUtils`, and `@libs/NumberUtils` with named imports (`write`, `getMicroSecondOnyxErrorWithTranslationKey`, `generateHexadecimalValue`) to satisfy the no-restricted-syntax rule that disallows namespace imports from `@libs`. Also picks up a prettier formatting fix in the test import.
Renames the placeholder custom unit IDs (`SOURCEDISTID`,
`SOURCEPERDIEM`, `TARGETDISTID`, `TARGETPERDIEMID`) to digit-only
13-character strings so cspell stops flagging them as unknown words.
The strings remain valid `[0-9A-F]{13}` hex IDs and tests still pass.
Includes a JSDoc comment to clarify the purpose of the sourcePolicyID field, indicating that it represents the ID of the source policy from which settings are copied.
|
@francoisl Can you please trigger translation action #89963 (comment) |
|
Looks like they're already included? Started it for good measure though. |
🦜 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 d9b5c0c8..53b996df 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -5964,9 +5964,7 @@ _Für ausführlichere Anweisungen [besuchen Sie unsere Hilfeseite](${CONST.NETSU
`Sie sind dabei, ${newWorkspaceName ?? ''} mit ${totalMembers ?? 0} Mitgliedern aus dem ursprünglichen Workspace zu erstellen und zu teilen.`,
error: 'Beim Duplizieren deines neuen Workspace ist ein Fehler aufgetreten. Bitte versuche es erneut.',
},
- copyPolicySettings: {
- error: 'Beim Kopieren der Arbeitsbereich-Einstellungen ist ein Fehler aufgetreten. Bitte versuche es erneut.',
- },
+ copyPolicySettings: {error: 'Beim Kopieren der Arbeitsbereichseinstellungen ist ein Fehler aufgetreten. Bitte versuche es erneut.'},
emptyWorkspace: {
title: 'Du hast keine Arbeitsbereiche',
subtitle: 'Belege erfassen, Auslagen erstatten, Reisen verwalten, Rechnungen versenden und mehr.',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index a7b12004..84d4f848 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -5984,9 +5984,7 @@ _Pour des instructions plus détaillées, [visitez notre site d’aide](${CONST.
`Vous êtes sur le point de créer et de partager ${newWorkspaceName ?? ''} avec ${totalMembers ?? 0} membres de l’espace de travail d’origine.`,
error: 'Une erreur s’est produite lors de la duplication de votre nouvel espace de travail. Veuillez réessayer.',
},
- copyPolicySettings: {
- error: 'Une erreur s’est produite lors de la copie des paramètres de l’espace de travail. Veuillez réessayer.',
- },
+ copyPolicySettings: {error: 'Une erreur s’est produite lors de la copie des paramètres de l’espace de travail. Veuillez réessayer.'},
emptyWorkspace: {
title: 'Vous n’avez aucun espace de travail',
subtitle: 'Suivez les reçus, remboursez les dépenses, gérez les voyages, envoyez des factures, et plus encore.',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 0de05c84..098859a5 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -5954,9 +5954,7 @@ _Per istruzioni più dettagliate, [visita il nostro sito di assistenza](${CONST.
`Stai per creare e condividere ${newWorkspaceName ?? ''} con ${totalMembers ?? 0} membri dello spazio di lavoro originale.`,
error: 'Si è verificato un errore durante la duplicazione del tuo nuovo workspace. Riprova.',
},
- copyPolicySettings: {
- error: 'Si è verificato un errore durante la copia delle impostazioni del workspace. Riprova.',
- },
+ copyPolicySettings: {error: 'Si è verificato un errore durante la copia delle impostazioni dello spazio di lavoro. Riprova.'},
emptyWorkspace: {
title: 'Non hai nessuna area di lavoro',
subtitle: 'Tieni traccia delle ricevute, rimborsa le spese, gestisci i viaggi, invia le fatture e altro ancora.',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 1bb9bda1..f9d589e4 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -5887,9 +5887,7 @@ _詳しい手順については、[ヘルプサイトをご覧ください](${CO
`元のワークスペースから ${totalMembers ?? 0} 人のメンバーと一緒に、${newWorkspaceName ?? ''} を作成して共有しようとしています。`,
error: '新しいワークスペースの複製中にエラーが発生しました。もう一度お試しください。',
},
- copyPolicySettings: {
- error: 'ワークスペース設定のコピー中にエラーが発生しました。もう一度お試しください。',
- },
+ copyPolicySettings: {error: 'ワークスペース設定のコピー中にエラーが発生しました。もう一度お試しください。'},
emptyWorkspace: {
title: 'ワークスペースがありません',
subtitle: '領収書を管理し、経費を精算し、出張を管理し、請求書を送信するなど、さまざまなことができます。',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index d09a9548..4c12551f 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -5934,9 +5934,7 @@ _Voor meer gedetailleerde instructies, [bezoek onze help-site](${CONST.NETSUITE_
`Je staat op het punt ${newWorkspaceName ?? ''} te maken en te delen met ${totalMembers ?? 0} leden van de oorspronkelijke werkruimte.`,
error: 'Er is een fout opgetreden bij het dupliceren van je nieuwe werkruimte. Probeer het opnieuw.',
},
- copyPolicySettings: {
- error: 'Er is een fout opgetreden bij het kopiëren van de werkruimte-instellingen. Probeer het opnieuw.',
- },
+ copyPolicySettings: {error: 'Er is een fout opgetreden bij het kopiëren van de werkruimtainstellingen. Probeer het opnieuw.'},
emptyWorkspace: {
title: 'Je hebt geen werkruimtes',
subtitle: 'Volg bonnen, vergoed uitgaven, beheer reizen, verstuur facturen en meer.',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index a4d23675..6bf18a28 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -5928,9 +5928,7 @@ _Aby uzyskać bardziej szczegółowe instrukcje, [odwiedź naszą stronę pomocy
`Za chwilę utworzysz i udostępnisz ${newWorkspaceName ?? ''} ${totalMembers ?? 0} członkom oryginalnego obszaru roboczego.`,
error: 'Wystąpił błąd podczas duplikowania Twojego nowego obszaru roboczego. Spróbuj ponownie.',
},
- copyPolicySettings: {
- error: 'Wystąpił błąd podczas kopiowania ustawień przestrzeni roboczej. Spróbuj ponownie.',
- },
+ copyPolicySettings: {error: 'Wystąpił błąd podczas kopiowania ustawień przestrzeni roboczej. Spróbuj ponownie.'},
emptyWorkspace: {
title: 'Nie masz żadnych przestrzeni roboczych',
subtitle: 'Śledź paragony, rozliczaj wydatki, zarządzaj podróżami, wysyłaj faktury i wiele więcej.',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index c1ba130b..a9027d77 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -5934,9 +5934,7 @@ _Para instruções mais detalhadas, [visite nossa central de ajuda](${CONST.NETS
`Você está prestes to criar e compartilhar ${newWorkspaceName ?? ''} com ${totalMembers ?? 0} membros do workspace original.`,
error: 'Ocorreu um erro ao duplicar seu novo espaço de trabalho. Tente novamente.',
},
- copyPolicySettings: {
- error: 'Ocorreu um erro ao copiar as configurações do espaço de trabalho. Tente novamente.',
- },
+ copyPolicySettings: {error: 'Ocorreu um erro ao copiar as configurações do workspace. Tente novamente.'},
emptyWorkspace: {
title: 'Você não tem nenhum workspace',
subtitle: 'Controle recibos, reembolse despesas, gerencie viagens, envie faturas e muito mais.',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 3b2bbf5c..ede27d7c 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -5789,9 +5789,7 @@ _如需更详细的说明,请[访问我们的帮助网站](${CONST.NETSUITE_IM
`您即将创建并共享 ${newWorkspaceName ?? ''},其中包含来自原始工作区的 ${totalMembers ?? 0} 位成员。`,
error: '复制您的新工作区时发生错误。请重试。',
},
- copyPolicySettings: {
- error: '复制工作区设置时发生错误。请重试。',
- },
+ copyPolicySettings: {error: '复制工作区设置时发生错误。请重试。'},
emptyWorkspace: {
title: '你还没有工作区',
subtitle: '跟踪收据、报销费用、管理差旅、发送发票等。',
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
Explanation of Change
Adds the action layer for the new "Copy configuration" RHP flow that's part of the Bulk workspace edits project. This is task 2 of the project — task 1 is the declarative plumbing in #89959 and this PR is stacked on top of it. Please review #89959 first.
What this PR adds
src/libs/actions/Policy/CopyPolicySettings.ts— owns all logic that talks to Onyx and the API for the copy flow. Exports:setCopyPolicySettingsData(data)—Onyx.mergehelper forCOPY_POLICY_SETTINGS.clearCopyPolicySettings()— clears the key when the flow exits.requestCopyPolicySettingsNotification()— firesCopyPolicySettings_Notify.PARTS_TO_POLICY_FIELDS— map of part key → list ofPolicyfield names. DrivespendingFieldsexpansion so existingOfflineWithFeedbackwrappers grey out per settings tab during the copy.buildCopyPolicySettingsData(sourcePolicy, targetPolicies, parts, allPolicyCategories, allPolicyTags)— produces{optimisticData, successData, failureData}following the four-step algorithm in the design doc:partsusing the mapping tablependingFieldskeyed byPolicyfield names (not part names)POLICY_CATEGORIES/POLICY_TAGScollection keys; failure data restores the target's snapshotcurrentSteponCOPY_POLICY_SETTINGSitself ('loading'optimistically, cleared on failure, untouched on success — backend transitions to'complete'via NVP)copyPolicySettings(...)— entry point that callsAPI.write(WRITE_COMMANDS.COPY_POLICY_SETTINGS, ...).tests/actions/CopyPolicySettingsTest.ts— 20 unit tests forbuildCopyPolicySettingsDatacovering each part key in isolation, collection key overwrites, failure rollback, andcustomUnitsID preservation.Translation key
workspace.copyPolicySettings.erroradded to all 10 language files. ThefailureDataupdates surface this RBR viaErrorUtils.getMicroSecondOnyxErrorWithTranslationKey, which requires the key to exist inTranslationPaths.Notes on
customUnitspreservationUnlike Duplicate (which generates new unit IDs for the new policy), Copy Settings preserves each target's existing distance/per-diem unit ID — the source unit data is written under the target's existing ID. A new 13-character hex ID is generated only when the target has no unit of that type yet.
Fixed Issues
$ #88668
PROPOSAL: N/A
Tests
This PR has no UI surface yet (the pages it powers land in later issues). To verify the action layer:
npm install.npm run typecheck— should pass with no errors.npx jest tests/actions/CopyPolicySettingsTest.ts— all 20 tests should pass.npm run linton the changed files — should pass with no errors.Offline tests
N/A — no runtime UI is wired up yet. The optimistic / failure data structure that this PR produces is what enables the offline pattern "B - Optimistic WITH Feedback" once the pages are wired up in follow-up issues.
QA Steps
This PR contains no user-facing changes and ships behind no UI entry point.
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
N/A — no UI changes in this PR.
Android: Native
N/A
Android: mWeb Chrome
N/A
iOS: Native
N/A
iOS: mWeb Safari
N/A
MacOS: Chrome / Safari
N/A