fix(layout): show no-webcam for camera-less projects - #310
Conversation
|
Warning Review limit reached
Next review available in: 25 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough
ChangesCamera-aware layout handling
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 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: 1
🤖 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 `@src/components/ai-edition/RightPanes.layout.test.tsx`:
- Around line 67-88: The “LayoutPane camera availability” tests need to cover
all camera-dependent UI behavior when no camera is available. Extend the
no-camera case to assert reactive zoom and webcam size are hidden, and verify
the remaining camera-dependent controls are disabled; keep the existing
saved-preset assertions unchanged and add coverage in this test file for each
new branch.
🪄 Autofix
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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: f87047f2-ff91-4d9d-9804-be27ca140d0b
📒 Files selected for processing (2)
src/components/ai-edition/RightPanes.layout.test.tsxsrc/components/ai-edition/RightPanes.tsx
EtienneLescot
left a comment
There was a problem hiding this comment.
Reviewed at the PR head (7fad1f1c). Verdict: ship with nits. Nice, small, correctly-placed change.
Things I checked that came back clean:
- It's live code.
App.tsx:19→AiEditionShell→NewEditorShell.tsx:46,1207mountsFloatingInspector→v4/FloatingInspector.tsx:47importsLayoutPanefrom../RightPanesand renders it at:1057. (The v4 shell reuses these panes; the dead-code note applies toRightPanelStack/Bottombar/Titlebar, not here.) - It reuses the consolidated camera helper rather than adding a fourth way to ask "is there a webcam" —
hasAnyClipWithCamerafromlib/ai-edition/timeline/camera.ts, no new detection code. - It reuses the existing
"no-webcam"preset instead of inventing an empty-state component, and derivesisPip/supportsReactiveZoom/valuefrom oneeffectiveLayoutPresetconst so the three consumers can't drift. - Test verified by reverting: at PR head 2/2 pass; with
RightPanes.tsxreverted tomainand the new test kept, it fails exactly on the fix's assertion (expect(element).toHaveValue(no-webcam) … Received: picture-in-picture). Genuine regression test, asserting on rendered DOM. // @vitest-environment jsdomcorrectly on line 1. Both typecheck configs, biome, and the tests all pass locally.
1. The same defect is still live on the Full Camera control
Not introduced here, and I'd file it as a follow-up rather than expand this PR — but it's the sibling of exactly what you just fixed, so worth naming while the context is fresh.
V4Timeline.tsx:1369 and NewEditorShell.tsx:980 — the "Add Full Camera" toolbar button and the C shortcut create a camera-fullscreen region on a camera-less project with no gate at all, while the AI-agent path refuses the identical action verbatim (agent-tools.ts:208-226: "this recording has no webcam").
Open a project whose only asset has cameraTrack: null, press C. A Full Camera pill appears in the lane and is persisted into legacyEditor.cameraFullscreenRegions, but PreviewCanvas.effectiveLayout short-circuits (if (!layout?.webcamRect || cameraFullscreenProgress <= 0) return layout) and the export does the same — the region renders nothing, forever, with no feedback.
The right depth is inside useTimeline.addCameraFullscreen (useTimeline.ts:348), so both entry points and any future one route through it:
if (!hasAnyClipWithCamera(document.assets, document.timeline.clips)) return;…plus disabled on the toolbar button. I'll open an issue for this.
2. Two predicates now disagree about what the user sees
camera.ts holds both answers to "does this have a camera":
hasAnyClipWithCamera(:23) →cameraTrack != nullassetCameraSource(:45-52) →visible && sourcePath, declared "THE answer" by the SSOT refactor
This PR promotes the looser one from "should the controls be enabled" to "what value does the control display", so for an asset with cameraTrack: { sourcePath: "/cam.webm", visible: false } the select would show and enable "Picture-in-Picture" while sceneDescription.ts:593, PreviewCanvas.tsx:230 and ExportDialog.tsx:66 all resolve no-webcam — the exact defect this PR fixes, unfixed for hidden cameras.
Latent, not shipping: nothing writes visible: false today (schema defaults true; migrate.ts:112 and projectStore.ts:164 both write true; no UI toggle exists), and camera.test.ts:83 pins the current behaviour on purpose. So no code change needed — but one line in the new comment saying the panel deliberately keeps the saved preset for a hidden-but-present camera would stop the next reader "fixing" it in the wrong direction.
3. Third literal copy of the same expression
RightPanes.tsx:1510 — hasCamera ? settings.webcamLayoutPreset : "no-webcam" now exists in three places (the others are PreviewCanvas.tsx:230 and sceneDescription.ts:593). lib/compositeLayout.ts already hosts exactly this shape next door — resolveWebcamReactiveZoom(preset, enabled) at :140, "the stored setting, gated by the active preset", right beside supportsWebcamReactiveZoom.
Adding a second preset to the "renders nothing without a camera" set currently means editing three files:
export function resolveWebcamLayoutPreset(preset: WebcamLayoutPreset, hasCamera: boolean) {
return hasCamera ? preset : "no-webcam";
}4. The select has no accessible name
RightPanes.tsx:1528-1531 — <label>{ts("layout.title")}</label> is a sibling with no htmlFor, and the select has no id/aria-label. A screen reader announces "combobox, No Webcam, dimmed" with nothing saying what it controls — and this PR makes that announced value the entire point of the change.
The tell is in the new test: getByRole("combobox") with no name filter only works because the control is nameless. Adding htmlFor/id and tightening the test to getByRole("combobox", { name: "Layout" }) fixes both.
Nits
RightPanes.tsx:1505-1506— the comment ("make the disabled control describe what the preview/export actually render right now") is only true for uniformly camera-less projects. Preview and scene resolve per-clip, so in a mixed projecthasAnyCameraistrueand the panel shows PiP while the playhead sits over a camera-less clip. Suggest "…describe whether this project has any camera at all".- A user whose saved preference is Picture-in-Picture now reads "No Webcam" in a dead control with nothing telling them the setting survived. The test asserts the preservation; the UI never communicates it. A
titleon the disabled select, or a camera-less variant ofts("layout.help"), would close that. RightPanes.tsx:1507-1509—hasAnyClipWithCamerais an unmemoizedclips.some(… assets.find(…)), O(clips × assets), on every LayoutPane render; the pane subscribes to the wholedocument, andsetLiveduring a slider drag replaces the document every frame. Pre-existing (identical onmain), but the PR rewrites these exact lines, souseMemo(…, [document])is a one-line win while you're here.RightPanes.layout.test.tsx:41,56,70— locals nameddocumentshadow the jsdom global inside a jsdom test file. Harmless now; adocument.querySelector(...)added later would silently query theAxcutDocument.docwould be safer.- No locale is pinned, unlike the sibling
RightPanes.i18n.test.tsx:17,22,26. The hardcoded English strings ride on jsdom's impliciten-US; if the i18n fallback ever changed, the threequeryByText(...).not.toBeInTheDocument()assertions would pass vacuously. - The second test ("keeps the saved preset active…") passes unchanged against
main, so its only value is guarding over-reach — fine, just noting three of its five assertions restate coverageRightPanes.i18n.test.tsxalready carries.
Worth knowing for the rebase: this branch is 22 commits behind origin/main and does not contain the camera-SSOT refactor. It merges clean only because it never touches camera.ts — but §2 above is written against what it will actually land on.
Nothing blocking. Happy to approve as-is; §4 is the one I'd fold in while you're in the file.
|
Filed the Full Camera gap from my review as #353 — out of scope for this PR, tracked separately. |
Summary
No Webcamstate for camera-less timelines, matching preview/export behaviorThis completes the remaining UI portion of #248 after the renderer/export correction merged in #261.
Related issue
Fixes #248
Type of change
Release impact
Desktop impact
Screenshots / video
Not included; DOM regression coverage verifies both camera-less and camera-present states.
Testing
picture-in-picturewas displayed)npx vitest --run src/components/ai-edition/RightPanes.layout.test.tsx src/components/ai-edition/RightPanes.i18n.test.tsx(7 passed)npm run test(1,679 passed, 1 skipped across 141 files)npx tsc --noEmitnpx tsc -p tsconfig.test.json --noEmitnpx biome check src/components/ai-edition/RightPanes.tsx src/components/ai-edition/RightPanes.layout.test.tsxnpm run docs:checknpm run i18n:checknpm run build-viteAuthored with Codex assistance and manually verified against the remaining #248 UI behavior.
Summary by CodeRabbit