Repository navigation
fix(playground): chat plan gating + studio UX - #2633
Conversation
- Video studio: models are no longer disabled by the current audio mode; the audio toggle adapts to the selection instead and the audio flag is clamped per model at request time - Video studio: low-credits banner uses /chat-plans/status in the Chat plan context and promotes plans instead of top-ups - Chat: default to a funded dashboard org for unsubscribed users; Chat plan context stays default only for subscribers or when no org has credits - Chat: credit gating now also covers the Chat plan context (previously skipped when no org was selected), promoting plans when out of credits - Canvas: JSON spec hidden by default with a clearer Show/Hide JSON toggle, plus an empty state with prompt suggestions Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
WalkthroughThis PR enhances the playground with an empty-state canvas UI, implements credit/billing gating at shell and handler levels, removes global audio eligibility logic from video helpers to enable per-model audio control, and updates video component props accordingly. ChangesCanvas UI, Billing Gating, and Video Audio Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/playground/src/app/playground-shell.tsx (1)
141-175: ⚡ Quick winMove this redirect ahead of the Chat-org fetch.
This check runs after Line 87 has already fetched
"/playground/chat-org", but the nearby comment says that org is created on demand. Users who should be redirected straight into a funded dashboard org will still provision/touch the Chat org first. Run the/chat-plans/statusfallback before fetching the Chat org, then resolvechatOrgonly if the request actually stays in the personal context.Based on PR objectives, this redirect is supposed to choose the funded dashboard org before the request continues in the Chat-plan context.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/playground/src/app/playground-shell.tsx` around lines 141 - 175, The redirect logic that checks chat plan access should run before fetching the chat-org so we don't provision/touch a Chat org for users who should land in a funded dashboard org; move the block that calls fetchServerData("GET","/chat-plans/status") and computes hasChatPlanAccess (using chatPlanStatus, Number(chatPlanStatus.regularCredits)) to execute before the code that fetches "/playground/chat-org" (and before any call that may create chatOrg), and only proceed to resolve chatOrg if hasChatPlanAccess remains true; if hasChatPlanAccess is false and you find a funded organization from organizations (using Number(o.credits) > 0), build nextParams from searchParams and call redirect(`/?${nextParams.toString()}`) as currently implemented.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/playground/src/components/playground/chat-page-client.tsx`:
- Around line 1125-1146: The gate in ensureBillableContext currently lets
hasChatPlanCredits satisfy billing even when selectedOrganization is set; change
it so dashboard org gating is checked first: if selectedOrganization exists and
Number(selectedOrganization.credits) <= 0 (and isChatPlanStatusLoaded &&
!hasChatPlanCredits) then trigger setShowTopUp(true) and return false, otherwise
if no selectedOrganization resolve to chatOrg and apply the existing chat-plan
gating (use Number(chatOrg.credits) and hasChatPlanCredits) before redirecting
router.push("/pricing"); ensure this aligns with ensureCurrentChat which creates
chats under selectedOrganization?.id ?? chatOrg?.id.
In `@apps/playground/src/components/playground/video-page-client.tsx`:
- Around line 293-318: The aggregation for selectionAudioSupport is wrong: using
some(...) allows mixed selections to leave the toggle enabled even when every
selected model is forced to one mode; change the two some(...) calls to
selected.every(...) so selectionAudioSupport.audio = selected.every(model =>
model.supportsVideoAudio !== false) and selectionAudioSupport.silent =
selected.every(model => model.supportsVideoWithoutAudio === true) (keep the
empty-selection special case), which will make audioToggleLocked /
effectiveAudioEnabled / audioToggleLockedReason behave correctly for forced-only
model sets.
---
Nitpick comments:
In `@apps/playground/src/app/playground-shell.tsx`:
- Around line 141-175: The redirect logic that checks chat plan access should
run before fetching the chat-org so we don't provision/touch a Chat org for
users who should land in a funded dashboard org; move the block that calls
fetchServerData("GET","/chat-plans/status") and computes hasChatPlanAccess
(using chatPlanStatus, Number(chatPlanStatus.regularCredits)) to execute before
the code that fetches "/playground/chat-org" (and before any call that may
create chatOrg), and only proceed to resolve chatOrg if hasChatPlanAccess
remains true; if hasChatPlanAccess is false and you find a funded organization
from organizations (using Number(o.credits) > 0), build nextParams from
searchParams and call redirect(`/?${nextParams.toString()}`) as currently
implemented.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: fbddc46a-78d3-44ea-beb5-1a897fb79a89
📒 Files selected for processing (10)
apps/playground/src/app/playground-shell.tsxapps/playground/src/components/playground/canvas-page-client.tsxapps/playground/src/components/playground/chat-page-client.tsxapps/playground/src/components/playground/video-controls.tsxapps/playground/src/components/playground/video-header.tsxapps/playground/src/components/playground/video-page-client.tsxapps/playground/src/lib/canvas/templates.tsapps/playground/src/lib/hero-suggestions.tsapps/playground/src/lib/video-gen.spec.tsapps/playground/src/lib/video-gen.ts
💤 Files with no reviewable changes (2)
- apps/playground/src/lib/video-gen.spec.ts
- apps/playground/src/components/playground/video-header.tsx
- ensureBillableContext: dashboard orgs gate on their own credits only — chat plan credits live on the Chat org and never fund dashboard-org requests - Video audio toggle: lock unless every selected model supports both modes, so the toggle never appears actionable for forced-only selections - playground-shell: run the funded-org redirect before the chat-org fetch so redirected users never get a Chat org provisioned Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
## Summary Three related Chat-playground fixes for the out-of-credits experience in the Chat plan context. ### 1. Image & Audio studios: false low-credits banner in the Chat plan context The Image and Audio studios computed remaining credits straight off the `selectedOrganization` row passed from the server, which can be stale and doesn't reflect live plan status. The **"Low credits remaining. Top up…"** banner therefore showed in the Chat plan context (where top-ups don't apply) even when no chat plan was active. Both studios now mirror the **Video** studio (fixed in theopenco#2633): - Read remaining credits from `/chat-plans/status` (source of truth) when in the Chat plan context (`org.isChat`). - When out of credits in that context, the banner promotes the subscription plans (**"View plans" → `/pricing`**) instead of a top-up. ### 2. Video studio: generic "Video creation failed" instead of the real gateway error The gateway returns an OpenAI-compatible envelope — `{ error: { message, … } }` — but `getGatewayErrorMessage` only unwrapped `error` when it was a **string**, so it always fell through to the fallback. It now also unwraps the nested `error.message`, so the exact gateway error reaches the toast/gallery. Added `utils.spec.ts`. ### 3. Credit-error generation failures upsell a plan in the Chat plan context With #2 landed, the insufficient-credits **402** (`"Video generation requires at least $1.00 in available credits. Please add credits and try again."`) surfaced verbatim — wrong for the Chat plan context where top-ups don't apply. When a studio generation fails for lack of credits **and** the org is the Chat org, the toast/gallery error now upsells a subscription: - not subscribed → **"Subscribe to a plan to continue generating videos/images/audio."** - subscribed but out of plan credits → **"You've used all your plan credits. Upgrade your plan to continue generating …"** Non-credit gateway errors (e.g. unsupported image size) are unchanged and still surface verbatim. Added shared `lib/credit-error.ts` (`isInsufficientCreditsError`, `chatPlanCreditErrorMessage`) + `credit-error.spec.ts`; hoisted the chat-plan status query above the generate callbacks so they can branch on it. ## Testing - Unit: `credit-error.spec.ts` (6) + `video/utils.spec.ts` (6) → 12/12 pass - Build: `turbo run build --filter=playground` → 13/13 - **Runtime (Playwright, recorded):** logged in against the seeded stack (Chat org, 0 credits, no plan) and confirmed end-to-end: - `/image` & `/audio` banners → "Upgrade to a plan" + **View plans → /pricing** (no Top Up) - `/video` & `/image` generation → toast/gallery shows **"Subscribe to a plan to continue generating …"**, not the "$1.00 / add credits" message - control: `/api/video` still returns the raw 402 gateway message (rewording is client-side) 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved gateway error handling by extracting nested gateway error messages when available. * Standardized “insufficient credits” generation failures with chat-plan-specific, user-facing messaging. * **New Features** * Added chat-plan credit status fetching to drive accurate credit/upsell behavior for audio, image, and video. * Updated low-credits UI: chat-plan contexts now show a dedicated ChatPlanUpsell; non-chat contexts keep existing banner/top-up behavior. * **Tests** * Added unit tests for gateway error extraction and insufficient-credits detection and messaging. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Fixes a batch of playground issues around the Chat plan context and studio UX:
Video studio: audio no longer disables models
Models like MiniMax Hailuo 2.3 (silent-only) and Grok Imagine (audio-only) were disabled in the model selector with "This mapping does not support audio/silent output" tooltips depending on the current audio toggle. Any model is now selectable:
audioflag is clamped per model at request time, so mixed comparisons (e.g. Hailuo vs Grok) each get a valid mode.Video studio: low-credits banner in Chat plan context
The "Low credits remaining. Top up…" banner showed in the Chat plan context where top-ups don't apply. The banner now reads chat plan credits from
/chat-plans/status(source of truth, instead of the possibly stale org row) and, when truly out of credits in the Chat plan context, promotes the subscription plans ("View plans" →/pricing) instead of a top-up.Chat: default org selection
The chat playground always defaulted to the Chat plan context. Now, when the user has no active chat plan and no credits on the Chat org, but does have a funded dashboard org, the server redirects to that org (
?orgId=…) so generation runs against their existing credits. The Chat plan context remains the default for subscribers, or when no org has credits — so the plan upsell can do its job.Chat: unsubscribed users could generate from the Chat plan context
Credit gating only ran when a dashboard org was selected (
selectedOrganizationisnullin the Chat plan context), so unsubscribed users with zero credits could keep generating (e.g. via free models). Gating now resolves the billing org (selected org or the dedicated Chat org) and, when blocked in the Chat plan context, routes to/pricinginstead of the top-up dialog.Canvas UX
Testing
pnpm buildpasses (17/17 tasks)vitest run apps/playgroundpasses (13 tests, including updatedvideo-gen.spec.ts)pnpm test:unitfailures are environmental only (ECONNREFUSED :5432— local Postgres not running); no api/worker/gateway code touched🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Improvements
Tests