fix(react-dogfood): correct closed captions capability checks - #2365
Conversation
The closed captions toggle checked START_CLOSED_CAPTIONS_CALL and STOP_CLOSED_CAPTIONS_CALL together. useHasPermissions requires all listed capabilities, so a user holding only one of the two grants got a permanently disabled button and could never start captions. Check the two grants independently and pick the one matching the current captioning state. Also gate on transcription.closed_caption_mode, and hide the button entirely when captions are disabled for the call or the user holds neither grant.
📝 WalkthroughWalkthroughThe closed captions button now checks whether captions are enabled, evaluates start and stop permissions separately, and sets its disabled state based on the required action. ChangesClosed captions controls
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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 |
Bundle sizeBuilt package output. Sizes in KB; delta vs No significant package size increase vs |
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 `@sample-apps/react/react-dogfood/components/ClosedCaptions.tsx`:
- Around line 24-28: Update the isClosedCaptionsEnabled/render guard in
ClosedCaptions so closed captions remain hidden while settings is null or
undefined, requiring loaded settings before evaluating closed_caption_mode;
preserve the existing disabled-mode and canStart/canStop checks, and add a
regression test covering the initial unloaded settings state.
🪄 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: 961ec12c-3d04-4dba-aa26-217a7c55d66d
📒 Files selected for processing (1)
sample-apps/react/react-dogfood/components/ClosedCaptions.tsx
| const isClosedCaptionsEnabled = | ||
| settings?.transcription.closed_caption_mode !== | ||
| TranscriptionSettingsResponseClosedCaptionModeEnum.DISABLED; | ||
|
|
||
| if (!isClosedCaptionsEnabled || (!canStart && !canStop)) return null; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 12 \
'\b(useCallSettings|closed_caption_mode|ToggleClosedCaptionsButton)\b' \
packages/react-sdk packages/client sample-apps/react/react-dogfood \
--glob '*.{ts,tsx}'Repository: GetStream/stream-video-js
Length of output: 50381
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- ClosedCaptions component ---'
sed -n '1,130p' sample-apps/react/react-dogfood/components/ClosedCaptions.tsx
printf '%s\n' '--- useCallSettings definitions and state selectors ---'
rg -n -C 8 \
'useCallSettings|callSettings|settings\??:' \
packages/react-sdk/src \
--glob '*.{ts,tsx}' \
| head -n 500
printf '%s\n' '--- Call context mounting and call lifecycle around ActiveCall ---'
rg -n -C 8 \
'ActiveCall|StreamCall|StreamVideo|call\.join|callingState|CallState' \
sample-apps/react/react-dogfood \
--glob '*.{ts,tsx}' \
| head -n 500Repository: GetStream/stream-video-js
Length of output: 50381
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- Exact useCallSettings implementation ---'
rg -l 'useCallSettings' packages/react-sdk/src --glob '*.{ts,tsx}' |
while IFS= read -r file; do
if rg -q 'useCallSettings' "$file"; then
printf '\n### %s\n' "$file"
rg -n -C 15 'useCallSettings' "$file"
fi
done
printf '%s\n' '--- ActiveCall render conditions ---'
rg -n -C 15 \
'export const ActiveCall|<ActiveCall|ToggleClosedCaptionsButton|CallingState|call\.get|getOrCreate' \
sample-apps/react/react-dogfood/components/ActiveCall.tsx \
sample-apps/react/react-dogfood/pages \
--glob '*.{ts,tsx}' \
| head -n 700
printf '%s\n' '--- Tests for call settings and closed captions ---'
rg -n -C 10 \
'useCallSettings|ClosedCaptions|closed_caption_mode|START_CLOSED_CAPTIONS_CALL|STOP_CLOSED_CAPTIONS_CALL' \
packages/react-sdk sample-apps/react/react-dogfood \
--glob '*.{test,spec}.{ts,tsx}' \
--glob '*__tests__*'Repository: GetStream/stream-video-js
Length of output: 43728
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- Call-state hook factory and selector source ---'
rg -n -C 12 \
'useCallStateHooks|CallStateHooks|useCallSettings|callSettings' \
packages \
--glob '*.{ts,tsx}' \
--glob '!**/gen/**' \
--glob '!**/__tests__/data.ts' \
| grep -E '(^[^-].*|useCallStateHooks|CallStateHooks|useCallSettings|callSettings)' \
| head -n 800
printf '%s\n' '--- All files that define or export call-state hooks ---'
rg -l \
'useCallStateHooks|useCallSettings' \
packages \
--glob '*.{ts,tsx}' \
--glob '!**/gen/**' \
| sort
printf '%s\n' '--- Call state initialization and settings loading ---'
rg -n -C 12 \
'settings:|callSettings|call\.get\(|call\.getOrCreate\(|getOrCreate\(' \
packages/client/src \
--glob '*.{ts,tsx}' \
| head -n 800Repository: GetStream/stream-video-js
Length of output: 50383
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- Candidate binding and call-state files ---'
git ls-files | rg \
'(^|/)(react-bindings|.*CallState.*|.*call.*state.*|.*hooks.*)\.(ts|tsx)$' \
| head -n 300
printf '%s\n' '--- Hook factory declarations and exports ---'
rg -n \
'export .*useCallStateHooks|function useCallStateHooks|const useCallStateHooks|create.*Call.*State|CallState.*Hooks' \
. \
--glob '*.{ts,tsx}' \
--glob '!**/gen/**' \
--glob '!**/node_modules/**' \
--glob '!**/dist/**' \
--glob '!**/build/**' \
| head -n 300
printf '%s\n' '--- Call settings state assignments ---'
rg -n -C 8 \
'callState\.settings|state\.settings|settings\s*=' \
packages/client/src \
--glob '*.{ts,tsx}' \
| head -n 400Repository: GetStream/stream-video-js
Length of output: 50381
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- useCallSettings selector ---'
rg -n -C 12 \
'useCallSettings|settings\$|settings' \
packages/react-bindings/src/hooks/callStateHooks.ts
printf '%s\n' '--- CallState settings declaration and updates ---'
rg -n -C 15 \
'settings|callSettings|call\.settings' \
packages/client/src/store/CallState.ts
printf '%s\n' '--- Call get/getOrCreate state hydration ---'
rg -n -C 15 \
'getOrCreate|get\(|settings' \
packages/client/src/Call.ts \
packages/client/src \
--glob '*Call*.ts' \
| head -n 600Repository: GetStream/stream-video-js
Length of output: 50381
Require loaded call settings before rendering closed captions.
settings$ starts as undefined and receives data only after get() or getOrCreate() updates call state. The current comparison enables the control during this interval. Require settings != null before evaluating closed_caption_mode, and add a regression test.
🤖 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 `@sample-apps/react/react-dogfood/components/ClosedCaptions.tsx` around lines
24 - 28, Update the isClosedCaptionsEnabled/render guard in ClosedCaptions so
closed captions remain hidden while settings is null or undefined, requiring
loaded settings before evaluating closed_caption_mode; preserve the existing
disabled-mode and canStart/canStop checks, and add a regression test covering
the initial unloaded settings state.
Source: MCP tools
💡 Overview
The closed captions button in the react-dogfood call controls was gated on both
START_CLOSED_CAPTIONS_CALLandSTOP_CLOSED_CAPTIONS_CALLat once.useHasPermissionsuses.every(), so a user holding only one of the two grants saw a permanently disabled button. The call'stranscription.closed_caption_modewas never consulted either, so the button looked actionable even when captions are disabled for the call type — clicking it just failed server-side.📝 Implementation notes
canStart/canStopare now checked separately;canTogglepicks the one matching the current captioning state.closed_caption_mode !== 'disabled'gate, matching the settings-plus-capability pattern inNoiseCancellationProvider.Verified with
tsc --noEmitandeslint. Not exercised in a browser: the interesting branches need a call type withclosed_caption_mode: disabledand a role missing one of the two grants, which the default dogfood login doesn't reproduce.🎫 Ticket: https://linear.app/stream/issue/REACT-1077
Summary by CodeRabbit