Skip to content

Show what Starter changes before checkout, and swap at the plan cap - #1603

Open
helpcodeai wants to merge 2 commits into
feat/plan-fitfrom
feat/plan-fit-ui
Open

helpcodeai wants to merge 2 commits into
feat/plan-fitfrom
feat/plan-fit-ui

Conversation

@helpcodeai

Copy link
Copy Markdown
Contributor

Summary

The Cloud trial now includes everything in Team. A workspace that buys Starter afterwards is downgraded automatically: the most used connectors and MCP servers stay active, and the rest are paused. This PR is the dashboard side. It says before checkout what Starter would pause or leave out, using the plan-fit endpoint from #1601. After a downgrade, it lets the user swap which items are active. The tone is calm. Starter stays selectable, and Team is one click away.

Stacked on #1601 (feat/plan-fit).

Changes

  • lib/api.ts: PlanFit types, license.getPlanFit(token, plan?), planFit on the reactivation view, and pausedByPlan? on usage. planLimitOf() / isPlanLimitError() recognise a 403 PLAN_LIMIT on every axis (connectors, mcpServers, users, fileSearchConnectors).
  • lib/card-trial.ts: planFitLines(fit) turns a plan fit into short lines, each a message key plus its values, so every UI language words them. Also adds selectionForFit (preselects Team when Starter does not fit and Team does, e.g. because inline code is in use), fitFor and formatStorage. limitsExceeded / selectionForUsage are unchanged.
  • components/plan-fit-notice.tsx (new): the "What changes with Starter" block. It shows the lines, a "See which ones" disclosure with the keep/pause lists and their calls in 30 days, and "Choose Team instead". When Team fits, it shows one quiet line instead. It sends plan_fit_shown (once per plan) and plan_fit_details_opened, both added to paywall-tracking.ts.
  • Where the notice appears: plan-picker.tsx (under the selected plan), license-wall.tsx (ended-trial wall, source: trial_ended_wall), start-trial/page.tsx (card-trial checkout) and reactivate/[token]/page.tsx. On the reactivation page there are no names, only counts ("…You choose which ones after signing in."), worded in the page's 7 languages (copy.ts, PLAN_FIT_COPY).
  • trial-banner.tsx: now reads "Your trial includes everything in Team." In the last 3 days, if the workspace does not fit Starter (plan-fit is fetched only then), it adds "Above Starter: see what changes", which opens the block in a dialog. The old "Keep your N connectors running." clause was removed to keep the banner short.
  • Settings → License (components/plan-usage-meters.tsx, new): meters for connectors, MCP servers, users, File Search folders, files and storage, saved code tools and code runs this month, plus an inline-code line. They are built from the plan fit of the plan in use (a trial uses Team's limits). During a trial there is also a "See what changes with Starter" disclosure.
  • Swap (components/plan-swap-dialog.tsx, new):
    • A "Paused: plan limit" badge on the connectors list, connector detail, MCP servers list and MCP server detail when the id is in usage.pausedByPlan.
    • Activating at the cap opens the swap dialog: "Your plan includes 5 active connectors. Pause one to activate this one". It lists the active items, most used first (ranked by plan-fit calls for connectors, server usage.calls30d for MCP servers), with the least used preselected. Actions are "Pause and activate" and "Upgrade to Team" (useManagePlan), or Enterprise past Team. If activation fails, the paused item is turned back on.
    • The dialog opens on a 403 PLAN_LIMIT and also, client-side, when usage shows the cap is reached. The client-side check only applies once the server reports pausedByPlan. Before that, caps are advisory and the client must not refuse what the server accepts.
  • PLAN_LIMIT on create / invite: PlanLimitNotice ("Your plan includes N … Pause one or upgrade", where "Pause one" opens the swap dialog in create mode). It is shown on connectors/new, connectors/setup/[slug], the MCP server create form and Settings → Users invitations (axis: 'users').
  • usage-banner.tsx: when items are paused, it says e.g. "1 connector is paused by your plan. Switch which ones are active, or upgrade to Team."
  • i18n: new planFit, planSwap and planUsage namespaces in en/de/it. The files that were English-only (plan picker, banners, licence wall body) stay English-only.

Cloud vs self-hosted

Everything here is Cloud only. Plan-fit answers 404 on self-hosted, usePlanFit / usePlanUsage do not call it off Cloud, pausedByPlan is never present, and no PLAN_LIMIT is returned. Self-hosted shows nothing new. Any surface degrades to today's UI when the endpoint is missing or fails (covered by a smoke test).

Type

  • Bug fix
  • New feature
  • Documentation
  • Refactoring
  • Performance improvement
  • Other (describe below)

Testing

  • Added/updated unit tests (pure helpers in tests/e2e/plan-fit.spec.ts, rendered with the real en.json and every reactivation-page language)
  • Tested manually (Playwright smoke with mocked API, screenshots below)
  • No tests needed (explain why)

New spec packages/frontend/tests/e2e/plan-fit.spec.ts (12 tests):

  • helper tests;
  • the ended-trial wall shows the block for Starter and the quiet line for Team, the disclosure lists names, "Choose Team instead" works, and the events fire;
  • without a plan-fit answer, no block is shown;
  • a connector paused by the plan gets the badge, and activating it at the cap opens the swap dialog and sends pause then activate;
  • Settings → License meters and the trial-banner dialog;
  • the reactivation page shows counts only.

Commands (all in packages/frontend, after npm ci at the root):

Command Result
npm run lint 0 errors, 51 warnings (same count as the base branch; none from the new files)
npx tsc --noEmit -p tsconfig.json pass
npx playwright test tests/e2e/plan-fit.spec.ts --workers=1 12 passed
npx playwright test --workers=1 (full suite) 386 passed (2.6 min)

Backend not touched; backend tests not run for this PR.

Checklist

  • My code follows the existing code style
  • I have tested my changes locally
  • I have updated documentation (if applicable)
  • All existing tests pass (frontend Playwright suite; the frontend has no npm test)
  • This PR has a descriptive title

Notes on the API contract

  • The MCP server update route is PUT /api/mcp-servers/:id (not PATCH); the client uses PUT.
  • GET /api/license/plan-fit does not check the role (the plan says ADMIN); the UI only asks for it in admin flows (wall, card trial, banner for trial admins) and on Settings → License, which is admin-only.
  • A trial without a card has a 500/month code-run cap, while plan-fit for team reports 5,000. The meter shows runs without a max during a trial. A cardTrial flag or the trial's own run cap in plan-fit would let it show the real cap.
  • fileSearchConnectors PLAN_LIMIT is handled by swapping among File Search folders. pausedByPlan.connectors covering File Search folders works with the same badge.

Related Issues

Stacked on #1601.

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