Skip to content

frontend/recs: mountBottomActionBox does not re-sync purchase visibility after in-session permission change #20

Description

@cristim

Context

Surfaced during CR pass-1 review of PR LeanerCloud/cloud-commitments-cli#924 (Purchaser group carve-out). CodeRabbit noted that mountBottomActionBox() in frontend/src/recommendations.ts (around line 2861) returns early when the recommendations-action-box DOM element already exists, which means the purchaseBtn.hidden snapshot and the no-Purchaser banner are evaluated once and never refreshed on subsequent renders.

Symptom

If the current user's permission set changes in-session (for example an admin adds themselves to the Purchaser group via Settings then Users without reloading the page) the Purchase CTA visibility and the no-Purchaser banner stay stuck at their initial values until a full page reload. The new copy on the banner explicitly tells the user "add yourself in Settings then Users" so the worst case is a user follows that instruction, comes back, and still sees the read-only banner with no spending button.

Why this was not fixed in PR LeanerCloud/cloud-commitments-cli#924

The carve-out work in PR LeanerCloud/cloud-commitments-cli#924 only changed the predicates that drive these elements (canAccess('execute', 'purchases') and the matching carved-out gates). The cache-bypass fix touches the entire mountBottomActionBox and updateBottomActionBox lifecycle and is the same shape of issue on the Create Plan button, the disabled-hint, and the Capacity input. Scoping that into PR LeanerCloud/cloud-commitments-cli#924 would have expanded the diff considerably and would have needed its own regression suite for the lifecycle changes.

Proposed fix

Options to consider:

  • Remove the early return at the top of mountBottomActionBox and let updateBottomActionBox be the single source of truth for visibility, or
  • Add an explicit updateBottomActionBox() call on every render so the hidden / banner snapshot is re-evaluated, or
  • Push the Purchase CTA and banner state into updateBottomActionBox so mountBottomActionBox only creates the DOM scaffolding and the per-render state lives in the update function.

The same pattern applies to the #create-plan-btn (create:plans) and the disabled-hint, so the fix should be lifecycle-wide rather than verb-specific.

Repro

  1. Log in as admin who is NOT in the Purchaser group (no execute:purchases via custom group either).
  2. Open the Opportunities tab. The Purchase button is hidden, the no-Purchaser banner is visible.
  3. Open Settings then Users and add yourself to the Purchaser group (no page reload).
  4. Navigate back to Opportunities. Purchase button is still hidden, banner still visible. A full reload fixes it.

Acceptance

  • A test that flips the current user's effectivePermissions between renders and asserts purchaseBtn.hidden plus banner presence both update without a reload.
  • The same fix applies to #create-plan-btn and the disabled-hint.

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions