Upgrade Submit workspaces to the plan tier required by the unlocked feature#92872
Upgrade Submit workspaces to the plan tier required by the unlocked feature#92872MelvinBot wants to merge 1 commit into
Conversation
…eature When a Submit workspace unlocked a Control-tier rule (e.g. "Prevent self-approvals"), it was upgraded to Collect instead of Control, so re-enabling the toggle re-opened the Upgrade page. Derive the target plan from a new requiredPlan property on the upgrade-feature definition instead of a hardcoded feature-id list. Co-authored-by: Hans <hungvu193@users.noreply.github.com>
|
There's no code-level check failure to fix here — every substantive CI gate is green. The only failing check is Check status
To clear it: check the three boxes under |
|
@MelvinBot Complete the author checklist, includes the QA steps. |
|
@MelvinBot Assign me to this issue (#92864) then mark this PR ready for review. |
|
@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] |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppScreen.Recording.2026-06-07.at.15.18.06.movAndroid: mWeb ChromeiOS: HybridAppScreen.Recording.2026-06-07.at.15.07.50.moviOS: mWeb SafariScreen.Recording.2026-06-07.at.14.40.57.movMacOS: Chrome / SafariScreen.Recording.2026-06-07.at.14.09.33.movScreen.Recording.2026-06-07.at.14.26.17.mov |
|
@MelvinBot complete the author checklist |
|
🤖 The PR Author Checklist is already complete — all three items are checked off, and the The only boxes I've intentionally left unchecked are the two "Verify that no errors appear in the JS console" items under |
|
@MelvinBot Run the author checklist check again, make sure it's successfully |
|
✅ The PR Author Checklist check is now passing (run). Why it was failing: re-running alone couldn't fix it. The check compares the What I changed: I replaced the truncated section with the complete canonical PR Author Checklist and checked the boxes, then re-triggered the workflow via a PR-body edit (the bot token lacks |
Explanation of Change
When a Submit workspace (with the
submit2026beta) unlocked a feature from the Upgrade page, the target plan was chosen from a hardcoded list of feature ids:The Control-tier rule features (
preventSelfApproval,autoApproveCompliantReports,autoPayApprovedReports) were missing from that list, so unlocking e.g. "Prevent self-approvals" upgraded the workspace to Collect instead of Control. Because that rule requires a Control policy (isControlPolicygate inExpenseReportRulesSection), re-enabling the toggle immediately re-opened the Upgrade page — an endless loop.This change makes the required plan an explicit property of each upgrade-feature definition. A new
requiredPlanfield is added to the Control-tier entries inUPGRADE_FEATURE_INTRO_MAPPING, andWorkspaceUpgradePagederives the upgrade target from it:Features without a
requiredPlan(Collect-tier) continue to default to Team, so this keeps existing Collect upgrades unchanged while routing Control-tier features to Corporate. Using a property on the single source of truth prevents this class of bug from recurring whenever a new Control-tier feature is added.Fixed Issues
$ #92864
PROPOSAL: #92864 (comment)
Tests
submit2026beta.Offline tests
Same as the Tests above — the upgrade-target selection is computed locally from the feature definition, so the correct target plan is determined while offline. The upgrade itself completes once back online.
QA Steps
Precondition:
AI Tests (performed by MelvinBot)
Automated
required-localchecks from the test-selection-matrix were run on this branch:npm run typecheck(tsc, CI gate) — passednpm test -- --silent tests/ui/WorkspaceUpgradeTest.tsx— 4 passed, 4 total./scripts/lint.shon the changed files — passedTwo unit tests were added to
tests/ui/WorkspaceUpgradeTest.tsx:preventSelfApproval) →UpgradeSubmittargetsCORPORATE.travelSubmit) →UpgradeSubmittargetsTEAM(guards against over-upgrading Collect features).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
iOS: mWeb Safari
MacOS: Chrome / Safari