-
Notifications
You must be signed in to change notification settings - Fork 4k
[feat] Add reusable ChatInput audio components #12834
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat] Add reusable ChatInput audio components #12834
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
✅ PR preview is ready!
|
📉 Python coverage change detectedThe Python unit test coverage has decreased by 0.0611%
💡 Consider adding more unit tests to maintain or improve coverage. Coverage by files
|
12d807c to
a28875d
Compare
deb8f05 to
53062ef
Compare
53062ef to
662c525
Compare
a28875d to
356976d
Compare
662c525 to
fa19cbe
Compare
356976d to
0646ce4
Compare
5dbf8af to
53b4659
Compare
c3d5122 to
ba14e2a
Compare
53b4659 to
9ba9e8d
Compare
📉 Frontend coverage change detectedThe frontend unit test (vitest) coverage has decreased by 0.0200%
✅ Coverage change is within normal range. |
e9eb59c to
e5cdcf3
Compare
d6cbf53 to
a79a224
Compare
Refactor handleApprove to use finally block for proper state cleanup. Ensures pending state is reset regardless of success or failure. Resolves comment 1
Standardize callback types to always return Promise<void> for callbacks that are awaited internally, making the API contract clearer and more consistent. Resolves comment 2
Remove over-engineered customizable strings prop from ChatAudioRecorder and ChatComposer. Hardcode English UI strings to align with Streamlit patterns. Resolves comments 3 and 7
Remove unnecessary requestAnimationFrame delay before starting recording. The mount ref is always rendered (even when hidden), so the delay is not needed. Resolves comment 4
Add error logging to the recording startup catch block using Streamlit's loglevel logger instead of silently swallowing errors. Resolves comment 5
Removed $ transient prop pattern (not used elsewhere in codebase) and simplified code by removing confusing intermediate boolean variables. Changed $variant to variant and use direct comparisons for clarity. Resolves comments 11 and 12
Removed customizable strings from ChatComposer to match ChatAudioRecorder. This pattern was over-engineering - no i18n system exists yet and it adds unnecessary complexity. Now uses hard-coded aria-labels directly. Also restored requestAnimationFrame in focusInput after tests proved it's necessary. RAF ensures focus happens after click events fully process, preventing race conditions when transitioning focus from buttons to input. Resolves PR #12834 comment #7 Addresses PR #12834 comment #4
Removed the strings prop from ChatAudioRecorder test that was passing a prop that doesn't exist in the component interface. This prop was removed when we fixed the over-engineering in comment #3, but the test wasn't updated. Test still passes as it searches for hard-coded labels. Resolves PR #12834 comment #14
Removed the .catch() handler from the Approve button's onClick since it's unreachable code. The handleApprove() function already catches errors internally and doesn't rethrow them, so the returned promise never rejects. This simplifies the code and removes the confusion about duplicate error handling. Resolves PR #12834 Graphite Agent comment
Add memoized handleApproveClick wrapper to satisfy @typescript-eslint/no-misused-promises rule while maintaining referential stability. The async handleApprove function is now wrapped in a useCallback that explicitly discards the Promise with void operator.
Replace toBeInTheDocument() with toBeVisible() to follow React Testing Library best practices. Using getBy* queries with toBeInTheDocument() is redundant since getBy* already throws if element not found. Resolves comment 2
Remove hardcoded minWidth from audio buttons to allow natural content-based sizing. Investigated theme.sizes and found no appropriate minElementWidth constant exists, so letting buttons size to their content is cleaner. Resolves comment 3
Convert all outlineOffset values from pixel units (2) to relative units ("0.125rem") to follow coding guidelines. This ensures better accessibility and proper scaling with user font preferences.
Resolves comment 4
Removed incomplete catch block with placeholder comment and added proper error logging to handleSubmit and handleRecordingApprove using LOG.error() for better observability and debugging. Resolves comment 4
Remove the isRecording prop from ChatAudioRecorder and implement internal state management with callback notification pattern. This eliminates tight coupling between parent and child components while maintaining proper React patterns. Changes: - Remove isRecording prop from ChatAudioRecorderProps - Add internal isRecording state to ChatAudioRecorder - Add onRecordingStateChange callback to notify parent of state changes - Expose isRecording as readonly property on ChatAudioRecorderRef - Update ChatComposer to use callback pattern for state synchronization - Update all tests to use ref-based API (ref.current?.startRecording()) - Fix ChatComposer.test.tsx mock to properly implement ref interface This refactor fixes the failing JS unit tests by aligning test expectations with the ref-based imperative API pattern introduced in the previous PR feedback iteration.
9d3d255 to
5bcbbef
Compare
37a8398 to
8c11177
Compare
frontend/lib/src/components/ChatInput/ChatAudioRecorder.test.tsx
Outdated
Show resolved
Hide resolved
Define MockProps and MockRef interfaces for the ChatAudioRecorder mock component instead of using 'any' types. This provides proper type safety and matches the actual component interface.
When using queryBy* queries (which return null if not found), use toBeNull() instead of not.toBeInTheDocument() to avoid redundant assertions. This follows the TypeScript Test Guide best practices.
Explicitly type the props and ref parameters in the forwardRef callback
since TypeScript cannot infer types from require('react'). This resolves
TS2347 and TS7006 errors.
Cannot pass type arguments to forwardRef from require('react') as it's
untyped. Instead, remove the generic type arguments from forwardRef and
add them to useImperativeHandle where they're actually needed. This fixes
TS2347 error in strict mode.
Remove generic type arguments from useImperativeHandle call in the mock
ChatAudioRecorder component. Functions imported via require("react") are
untyped and cannot accept TypeScript generic type arguments.
This is the same issue previously fixed for forwardRef on line 73.
|
Gonna close this one for now until I've had more time to think through this abstraction |

Describe your changes
Added new chat input components for the Streamlit frontend:
ChatComposer- A versatile chat input component that supports:ChatAudioRecorder- A component for recording audio messages that:These components are designed to be used together to create a modern chat interface with multimedia support.
Testing Plan
ChatAudioRecorder.test.tsx- Tests recording lifecycle, error handling, and UI statesChatComposer.test.tsx- Tests input handling, file selection, and audio recording integrationContribution License Agreement
By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.