Skip to content

fix(plans): say that cancelling a scheduled purchase also disables its plan - #770

Merged
cristim merged 1 commit into
mainfrom
fix/disable-plan-dialog-wording
Oct 9, 2026
Merged

cristim merged 1 commit into
mainfrom
fix/disable-plan-dialog-wording

Conversation

@cristim

@cristim cristim commented Oct 9, 2026

Copy link
Copy Markdown
Member

Summary

The x button on a scheduled purchase asked "Disable this plan?" with a "Disable plan" button. The server does two things for that click: DELETE /api/purchases/planned/{id} cancels that one scheduled execution, then disables its parent plan when the caller may change every plan account (handler_purchases.go, deletePlannedPurchase). The dialog now says both: "Cancel this scheduled purchase?", body "This scheduled purchase will be canceled, and its plan will be disabled so no further purchases are scheduled from it...", buttons "Cancel purchase and disable plan" / "Keep it". The button tooltip matches.

Wording only; no behavior change. A caller whose scope does not cover every plan account still has the purchase canceled but the plan left enabled (the API reports plan_disabled); the dialog does not distinguish that case.

Verification

  • plans.test.ts disable-action test now asserts the dialog title and the "plan will be disabled" body.
  • Not run locally: this worktree has no node_modules and the disk hold rules out npm ci. CI runs the frontend tests.
  • No closing issue, so no triage labels to mirror.

🤖 Generated with Claude Code

…s plan

The row action on a scheduled purchase asked "Disable this plan?" with a
"Disable plan" button, but DELETE /purchases/planned/{id} cancels that one
execution and then disables the parent plan. Name both effects in the
dialog and the button tooltip.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 2 billable files and costs up to $0.50.

  • Ask an admin to make reviews automatic

Open in CodeRabbit

Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing.

Or wait 33 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 85 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: LeanerCloud/cloud-commitments-platform/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 2f1f4275-344c-4aa2-aca3-a2e7cb237be2

📥 Commits

Reviewing files that changed from the base of the PR and between 0e34519 and 84b9ac5.


📒 Files selected for processing (2)
  • frontend/src/__tests__/plans.test.ts
  • frontend/src/plans.ts


  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@cristim

cristim commented Oct 9, 2026

Copy link
Copy Markdown
Member Author

Independent review (rv-ux-visual): PR #770 at 84b9ac5dd54c5675dcee0a31025210e6d6ba4525

Verdict: approved (no blocking findings). One copy note and one backend follow-up for the lead are below. CI status at this SHA is listed further down.

Copy vs deletePlannedPurchase (internal/api/handler_purchases.go:454, unchanged by this PR)

  • The handler cancels the execution via cancelOrRecoverExecution (only from pending/paused, otherwise 409; idempotent if already canceled). Then, when the execution has a PlanID, disablePlanIfInScope sets plan.enabled=false only if the caller passes requirePlanMutationAccess for every plan account. Otherwise the cancel stands, the plan stays enabled, and the response carries plan_disabled:false.
  • The new copy ("Cancel this scheduled purchase?" / "…will be canceled, and its plan will be disabled so no further purchases are scheduled from it…" / "Cancel purchase and disable plan" / "Keep it", tooltip "Cancel this purchase and disable its plan") matches the normal path. The old "Disable this plan?" hid the cancel. The out-of-scope case the PR body names is real: plans.ts ignores plan_disabled and shows no toast either way, so the user is told the plan was disabled when it was not. That is fine to defer, but worth a follow-up toast keyed on plan_disabled === false.

Verified live (production build of 84b9ac5, mock API, 1280/768/390)

CI (the PR says the frontend test was not run locally)

  • Build frontend (the jest gate) ran at exactly 84b9ac5d: Test Suites 99/99 passed; Tests 3144 passed, 1 skipped (unrelated describe.skip, dashboard.test.ts:1293). The updated plans.test.ts assertion (title + "plan will be disabled") is in that run.
  • Playwright Chromium passed.
  • All 26 checks green at 84b9ac5d, including Unit and Integration Tests.

Follow-ups

  • Nit: the catch toast still says "Failed to disable purchase: …" (Failed to ${action} purchase, with action='disable'). "Failed to cancel purchase" would match the new copy.
  • Backend, for the lead (not this PR): disabling a plan does not stop its other already-scheduled executions. ProcessScheduledPurchases → executableByScheduler (internal/purchase/manager.go:635) gates only on plan.AutoPurchase and the source, never on plan.Enabled. GetPendingExecutions (store_postgres.go:1583) does not join plans either. New executions are gated (shouldNotifyPlan checks Enabled; POST /plans/{id}/purchases currently returns 409), so "no further purchases are scheduled" holds for new rows. But sibling pending rows that already exist would still run when AutoPurchase=true.

@cristim
cristim merged commit 225ad35 into main Oct 9, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant