Skip to content

feat(settings): 3-radio deploy TTL policy + free-tier gating#155

Merged
mastermanas805 merged 2 commits into
mainfrom
feat/team-settings-ttl-3radio
May 31, 2026
Merged

feat(settings): 3-radio deploy TTL policy + free-tier gating#155
mastermanas805 merged 2 commits into
mainfrom
feat/team-settings-ttl-3radio

Conversation

@mastermanas805
Copy link
Copy Markdown
Member

Summary

mastermanas805 (Pro tier) was stuck on default_deployment_ttl_policy=auto_24h with no in-dashboard path to flip it back — only the agent could PATCH /api/v1/team/settings. Even after api#212 auto-flipped this on tier upgrade, anyone who landed there via support / pre-promotion was stranded.

This PR surfaces the existing team setting as a 3-radio group on /app/settings.

Changes

  • DeployTtlPolicyCard converted from two pill-buttons to a role="radiogroup" of 3 native radios:
    1. Permanent — default for paid tiers
    2. Auto-expire after 24h — default for free tier
    3. Custom hours — surface in place; disabled-with-tooltip until the api accepts per-team hours (per-deploy custom TTL via POST /deployments/:id/ttl is unchanged)
  • Static help text (testid ttl-policy-help): "This applies to all NEW deploys. Existing deploys keep their per-deploy setting."
  • Free-tier gate: card stays visible (users can see the default), every radio is disabled with an "Upgrade to change" tooltip, plus an upgrade hint linking to /app/billing.
  • Existing RBAC hide for non-owner/admin (developer / viewer) preserved.

Anti-goal adherence

  • Additive only — no refactor of SettingsPage.
  • No new team-settings unrelated to TTL.
  • No backfill of existing deploys' TTL from this UI (that lives on the api side).

Test plan

  • npm run gatetsc --noEmit clean, npm run build clean, vitest run.
  • New test file SettingsPage.tier-gate.test.tsx — 5 cases:
    • pro/owner reflects current policy + PATCH fires on Permanent click
    • help text always rendered
    • Custom hours disabled with coming-soon tooltip even on paid tier
    • free/owner: card visible, all radios disabled, "Upgrade to change" tooltip + upgrade-hint visible
    • free/owner: disabled radio click does NOT call updateTeamSettings
  • Existing SettingsPage.test.tsx 23 cases still pass (radios are click-compatible drop-ins for the previous buttons).
  • Post-merge: dogfood live as mastermanas805@gmail.com (Pro) and flip the radio back to Permanent.

Coverage block (rule 17):

Symptom:        Pro users on auto_24h had no in-UI policy switch
Enumeration:    rg -F 'default_deployment_ttl_policy' instanode-web/src/
Sites found:    4 (types + getter + setter + card)
Sites touched:  1 (card only — additive, no contract change)
Coverage test:  SettingsPage.tier-gate.test.tsx (5 cases)
Live verified:  pending CI + post-merge dogfood

mastermanas805 (Pro) landed on `default_deployment_ttl_policy=auto_24h`
with no in-dashboard path to flip back — only the agent could PATCH
/api/v1/team/settings. Surfaces the existing setting as a 3-radio group
(Permanent / Auto-expire 24h / Custom hours) so users who arrived at
auto_24h via support or pre-promotion can self-serve.

UX:
- 3 native radios, accessible role=radiogroup, full-row click target.
- Static help text: "applies to all NEW deploys. Existing deploys keep
  their per-deploy setting." (testid: ttl-policy-help).
- Free tier: card stays visible (so users can SEE the active default),
  every radio disabled with an "Upgrade to change" tooltip + an upgrade
  hint linking to /app/billing.
- Custom hours: surface present but disabled-with-tooltip on every tier
  — the api PATCH only accepts the two-value enum today; per-deploy
  custom TTL via POST /deployments/:id/ttl is unchanged.
- Existing non-admin RBAC hide (developer/viewer) preserved.

Coverage:
  Symptom: pro/team users on auto_24h had no in-UI policy switch.
  Enumeration: rg -F 'default_deployment_ttl_policy' instanode-web/src/
  Sites found: 4 (api/index.ts type/getter/setter + SettingsPage card).
  Sites touched: 1 (SettingsPage card — additive, no api shape change).
  Coverage test: SettingsPage.tier-gate.test.tsx asserts radio state +
    PATCH call + free-tier disabled state + custom-hours coming-soon.
  Live verified: pending CI + post-merge curl of the live dashboard.

Tests: 28/28 SettingsPage tests pass (incl. 5 new tier-gate cases).
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 31, 2026

size-limit report 📦

Path Size
dist/assets/index-CdvC7st8.js 0 B (-100% 🔽)
dist/assets/index-BsJUZYRr.css 6.13 KB (0%)
dist/assets/index-P1Fto0gZ.js 163.84 KB (+100% 🔺)

The previous commit left 6 uncovered lines (diff-cover failed with 80%
patch coverage). Refactor so every branch is reachable from the existing
pro/free tier tests:

- Hoist save callbacks into stable savePermanent / saveAuto24h refs
  (one line each instead of inline arrows on every render).
- Hoist tier-conditional title / disabled / description into named
  consts so the JSX has no inline ternaries.
- Replace the custom-radio no-op arrow with a module-level `noop` so
  there is no "unreachable disabled handler" arrow for coverage to flag.
- Add tier-gate test covering save('auto_24h') (permanent → auto_24h flip).

diff-cover: 100% (25/25 lines).
@mastermanas805 mastermanas805 merged commit 2da5b1b into main May 31, 2026
17 checks passed
@mastermanas805 mastermanas805 deleted the feat/team-settings-ttl-3radio branch May 31, 2026 07:38
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