[Payment due @abzokhattab] Add workspace rules PDF document upload, view, and management UI#87684
Conversation
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.
|
|
I'd like to review this PR when the time comes, so going to add myself proactively. |
159f567 to
340ab6f
Compare
|
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 |
|
@MelvinBot please review that this follows our code style and patterns |
|
Overall the PR follows our code style and patterns well — the Onyx optimistic/failure/finally structure, navigation wiring, modal content architecture, and API parameter types all match established conventions. A few things worth addressing: 1. 2. Inline style objects on every render — These create new object references each render: style={{width: variables.rulesDocumentThumbnailWidth, height: variables.rulesDocumentThumbnailHeight}}and {top: variables.spacing2, right: variables.spacing2}and {borderRadius: variables.componentSizeNormal / 2, backgroundColor: theme.cardBG}Consider extracting these to 3. 4. Minor — The Everything else (translations, route/screen registration, |
|
@abzokhattab Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c41aa38280
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
c41aa38 to
a79a1df
Compare
|
Thanks! Will run a test build now 🚀 |
|
@shawnborton BE is not merged so upload will not work right now 😅 will have to wait for BE PRs to be merged meanwhile here are screenshots 👤 Employee
🛠️ Admin
|
|
@MelvinBot Review the PR |
|
@codex review |
PR ReviewOverall this is well-structured and follows existing codebase patterns (Onyx optimistic/failure/finally, navigation wiring, Issues1. 2. 3. Section visibility condition is complex — consider extracting isBetaEnabled(CONST.BETAS.CUSTOM_RULES) && (isPolicyAdmin || !!policy?.rulesDocumentURL || !StringUtils.isEmptyString(policy?.customRules ?? ''))This condition is evaluated once but is hard to parse at a glance. A named boolean (e.g. 4. Minor: Looks good
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4ba51e224d
ℹ️ 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".
| const contentProps = useMemo<AttachmentModalBaseContentProps>( | ||
| () => ({ | ||
| source: rulesDocumentSourceURL, | ||
| headerTitle: translate('workspace.rules.customRules.policyDocument'), | ||
| originalFileName: `${policyID}-policy-document.pdf`, | ||
| shouldShowNotFoundPage, | ||
| isLoading, | ||
| shouldCloseOnSwipeDown: true, |
There was a problem hiding this comment.
Wire a download action into workspace document modal
WorkspaceDocumentModalContent only passes source/metadata and never provides an onDownloadAttachment path (or a context that enables the built-in download control), so the new policy PDF is effectively view-only in-app. In AttachmentModalBaseContent, the header download button is gated by that callback/context, which means members cannot reliably download the rules document from this screen (especially on native, where browser save controls are unavailable).
Useful? React with 👍 / 👎.
|
Okay that looks pretty good, but let us know when the BE is ready so we can test with adhoc builds. Thanks! |
|
@shawnborton @abzokhattab BE PRs merged and deployed, can we trigger Adhoc build |
|
🎯 @abzokhattab, 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. |
|
@JmillsExpensify @shawnborton As per this #87684 (comment), thoughts on increased the thumbnail size?
|
|
@hungvu193 Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
|
Curious what @Expensify/design thinks. My thinking is that the thumbnail is just a preview and thus it's fine if it's smaller, like it currently is. The larger size is a bit odd to me because while it does use more space, it doesn't necessarily present you the document in a way where you can actually read it - you still need to tap into it. I would do nothing here personally. |
|
Agree with that, Shawn |
|
@MelvinBot fix failing ci |
agreed 👍 i think we are good here as is ? |
|
Yup, let's leave it as is. |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚧 @lakchote 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/lakchote in version: 9.3.65-0 🚀
Bundle Size Analysis (Sentry): |
|
Yes, help site changes are needed. The new expense policy document upload feature (PDF upload, replace, remove on the workspace overview page) is not covered in the existing documentation. Draft PR created: #89327 Changes made to
Note: I was unable to add the PR to GitHub project 196 due to token permissions. Please add it manually. |
|
Deploy Blocker #89341 was identified to be related to this PR. |
|
Deploy Blocker #89345 was identified to be related to this PR. |














Explanation of Change
Adds frontend support for workspace admins to upload, replace, view, and delete a PDF rules document on the workspace overview page. Non-admins can view/download the document. This is the frontend (App) portion of a multi-repo change.
Key changes:
rulesDocumentURLfield on the Policy Onyx typeupdatePolicyRulesDocument/deletePolicyRulesDocumentaction functions with optimistic/failure/finally Onyx updatesWORKSPACE_DOCUMENTroute andWorkspaceDocumentModalContentgetRulesDocumentSourceURLutility routing remote URLs through authenticatedGetPolicyRulesDocumentstreaming endpoint with cache-bustingKey decisions:
rulesDocumentURL(notpolicyDocumentURL) —policyprefix is redundant inside a policy objectfile.uri(local blob URL) for instant display — same pattern as workspace avatar&cacheBuster=encoding the fullrulesDocumentURL— ensures unique streaming URL per PDF versionWORKSPACE_DOCUMENTroute instead of reusingREPORT_ATTACHMENTSCompanion PRs:
Fixed Issues
$ https://github.com/Expensify/Expensify/issues/610806
PROPOSAL: N/A (internal feature implementation)
Tests
Offline tests
QA Steps
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
Android: mWeb Chrome
iOS: Native
Screen.Recording.2026-04-16.at.1.10.39.AM.mov
iOS: mWeb Safari
Screen.Recording.2026-04-16.at.1.10.02.AM.mov
MacOS: Chrome / Safari
Screen.Recording.2026-04-15.at.11.42.24.PM.mov
Screen.Recording.2026-04-15.at.11.42.24.PM.mov