Repository navigation
feat(web): Studio IDE rebuild — three-pane layout, toolbar, paywall at export - #2330
Conversation
Kill the lime/ice-cream green color scheme per product direction. New direction: near-black surfaces, warm amber accent (amber-500/400), coherent with the brand film's night/amber look.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🔍 PR Validation |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Repository: groupthinking/EventRelay/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID:
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 |
✅ E2E Test Results: ALL TESTS PASSED
Test Output |
| Retry player | ||
| </button> | ||
| <a | ||
| href={`https://www.youtube.com/watch?v=${videoId}`} |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Cancellation and chat have correctness issues, while the agent workflow flag no longer exposes its promised controls.
Review effort: Balanced
Findings: 2
Open (8)
Duplicate current prompt in chat history and query · New Pending responses can append to the wrong video conversation · New Agent workflow controls are unreachable behind the feature flag · New Anonymous chat quota is shared globally across visitors · New Fixed side panes eliminate chat viewport at narrow widths · New Video resize separator lacks keyboard accessibility · New Cancellation signal misses phases and misreports aborts · New Cancellation test does not verify request abortion · New
What changed in this PR
Rebuilds the canonical Studio as a three-pane IDE and standardizes UVAI’s amber visual theme.
Changes:
- Adds resizable video, live chat, and structured output panes.
- Consolidates Studio actions and adds cancellation/deletion controls.
- Removes the legacy embed workspace and retokens public surfaces.
| File | Description |
|---|---|
apps/web/src/store/dashboard-store.ts |
Adds cancellation signal support. |
apps/web/src/lib/__tests__/uvai-surface-unification.test.ts |
Updates Tools surface assertion. |
apps/web/src/lib/__tests__/studio-pipeline-status.test.ts |
Updates IDE surface assertions. |
apps/web/src/components/studio/StudioThreePanelShell.tsx |
Removes legacy shell. |
apps/web/src/components/studio/StudioIdeShell.tsx |
Adds three-pane IDE layout. |
apps/web/src/components/studio/StudioIdeOutput.tsx |
Adds seven output tabs. |
apps/web/src/components/studio/StudioIdeChat.tsx |
Adds pack-grounded chat. |
apps/web/src/components/studio/studio-three-panel-shell.css |
Removes legacy shell CSS. |
apps/web/src/components/OneLoopStudio.tsx |
Integrates IDE and toolbar. |
apps/web/src/components/landing/WorkflowSection.tsx |
Applies amber theme. |
apps/web/src/components/landing/TemplatesSection.tsx |
Applies amber theme. |
apps/web/src/components/landing/LandingNav.tsx |
Retokens navigation. |
apps/web/src/components/landing/LandingFooter.tsx |
Retokens footer branding. |
apps/web/src/components/landing/HeroSection.tsx |
Retokens hero and animation. |
apps/web/src/components/landing/DeveloperSection.tsx |
Retokens developer section. |
apps/web/src/components/landing/ContactSection.tsx |
Retokens contact CTA. |
apps/web/src/components/landing/BentoFeatures.tsx |
Retokens feature cards. |
apps/web/src/components/home/HomeProCheckout.tsx |
Retokens checkout card. |
apps/web/src/components/home/HomePasteForm.tsx |
Retokens URL form. |
apps/web/src/components/billing/ProCheckoutButton.tsx |
Updates checkout focus styling. |
apps/web/src/components/__tests__/OneLoopStudio.three-panel.test.tsx |
Tests new IDE shell presence. |
apps/web/src/components/__tests__/OneLoopStudio.job-strip.test.tsx |
Updates status/transcript tests. |
apps/web/src/components/__tests__/OneLoopStudio.gate.test.tsx |
Targets new Spec tab. |
apps/web/src/components/__tests__/OneLoopStudio.build-live.test.tsx |
Updates empty IDE assertions. |
apps/web/src/app/terms/page.tsx |
Retokens legal links. |
apps/web/src/app/studio/StudioShell.tsx |
Removes embed toggle and iframe. |
apps/web/src/app/privacy/page.tsx |
Retokens legal links. |
apps/web/src/app/pricing/page.tsx |
Retokens pricing surfaces. |
apps/web/src/app/page.tsx |
Retokens homepage offer. |
apps/web/src/app/login/page.tsx |
Retokens login branding. |
apps/web/src/app/globals.css |
Replaces global teal tokens with amber. |
apps/web/src/app/docs/api/page.tsx |
Retokens API documentation. |
apps/web/src/app/ContactForm.tsx |
Retokens form status and CTA. |
apps/web/public/studio-pane/styles.css |
Deletes embed styles. |
apps/web/public/studio-pane/README.md |
Deletes embed documentation. |
apps/web/public/studio-pane/logic.js |
Deletes embed utilities. |
apps/web/public/studio-pane/index.html |
Deletes embed entry page. |
apps/web/public/studio-pane/fx-adapter.js |
Deletes terminal adapter. |
apps/web/public/studio-pane/app.js |
Deletes embed application. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| const history = [...messages, userMsg] | ||
| .slice(-10) | ||
| .map((m) => ({ role: m.role, content: m.content })); |
| const res = await fetch('/api/chat', { | ||
| method: 'POST', | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify(body), | ||
| }); |
| outputPane={ | ||
| <StudioIdeOutput | ||
| video={selected} | ||
| specReview={ | ||
| selected?.videoPack?.pack ? ( | ||
| <GroundedSpecReview | ||
| key={selected.id} | ||
| videoId={selected.id} | ||
| pack={selected.videoPack.pack} | ||
| acknowledgment={selected.specReviewAcknowledgment} | ||
| persistenceAvailable={dashboardPersistenceSucceeded()} | ||
| onSeek={videoId === selected.videoPack.pack.video_id ? seekTo : undefined} | ||
| onAcknowledge={(value) => { | ||
| if (useDashboardStore.getState().selectedVideoId !== selected.id) return false; | ||
| updateVideo(selected.id, { specReviewAcknowledgment: value }); | ||
| return dashboardPersistenceSucceeded(); | ||
| }} | ||
| /> | ||
| ) : undefined | ||
| } | ||
| /> | ||
| } |
| * Center-pane chat for the Studio IDE. Wired to the real POST /api/chat | ||
| * endpoint with pack grounding (video_id), not a stub. Free tier gets | ||
| * 5 messages/day; the API returns 402 with upgradeRequired when exceeded. |
| <div className="flex min-h-0 flex-1"> | ||
| {/* LEFT: video */} | ||
| {!leftCollapsed ? ( | ||
| <aside | ||
| data-testid="studio-ide-video-pane" | ||
| aria-label="Video" | ||
| className="flex min-h-0 w-[var(--ide-left-w)] shrink-0 flex-col border-r border-white/10" |
| <div | ||
| role="separator" | ||
| aria-orientation="vertical" | ||
| aria-label="Resize video pane" | ||
| data-testid="studio-ide-splitter-left" | ||
| className="w-1 shrink-0 cursor-col-resize bg-white/5 hover:bg-amber-500/40" | ||
| onPointerDown={(e) => { | ||
| e.preventDefault(); | ||
| startResize('left', e.currentTarget); | ||
| }} |
| processVideo: async (url) => { | ||
| processVideo: async (url, opts) => { | ||
| const { addVideo, updateVideo, addActivity } = get(); | ||
| const signal = opts?.signal; |
| // Run is async; the cancel button appears once busy flips true. | ||
| fireEvent.click(screen.getByTestId('studio-ide-run')); | ||
| expect(await screen.findByTestId('studio-ide-cancel')).toBeTruthy(); |
| setSending(true); | ||
| setError(null); | ||
|
|
||
| const history = [...messages, userMsg] |
There was a problem hiding this comment.
| const history = [...messages, userMsg] | |
| // History is the PRIOR conversation only. The current query is sent | |
| // separately via the `query` field and appended server-side, so including | |
| // userMsg here would duplicate the current message in the LLM conversation. | |
| const history = messages |
The current user message is sent twice to the LLM because history includes the just-added userMsg while query carries the same message separately.



Closes #2329
Blocked on me
Nothing. All pieces built, verified, committed, and pushed.
Changed
apps/web/src/components/studio/StudioIdeShell.tsx(new) — Three-pane IDE shell: top toolbar, left video / center chat / right output, resizable + collapsible panes. Check: tsc clean, eslint clean, three-panel tests.apps/web/src/components/studio/StudioIdeChat.tsx(new) — Center chat wired to real POST /api/chat with pack grounding, conversation history, 402 free-quota -> upgrade prompt. Check: tsc clean, eslint clean.apps/web/src/components/studio/StudioIdeOutput.tsx(new) — Right output pane, 7 tabs around action extraction: Events, Lingo, Tools, Intent, Signals, Spec, Transcript. Check: tsc clean, eslint clean.apps/web/src/components/OneLoopStudio.tsx(restructured) — Renders the IDE; toolbar consolidates URL + Run/Cancel + stored packs + Export + Build live + Check preflight. Check: tsc clean, eslint clean, 20 component tests pass.apps/web/src/store/dashboard-store.ts— processVideo accepts AbortSignal; abort marks run cancelled. Check: tsc clean.apps/web/src/app/studio/StudioShell.tsx— Dead Pack/Embed toggle + iframe removed.apps/web/public/studio-pane/deleted.StudioThreePanelShell.tsx+ CSS deleted (orphaned, 686 lines). Check: tsc clean.Found