Skip to content

Conversation

@sfc-gh-nbellante
Copy link
Contributor

@sfc-gh-nbellante sfc-gh-nbellante commented Jan 11, 2026

Describe your changes

Fixed an issue where the file upload button in st.chat_input would stop working after drag-dropping a file and then deleting it. The fix includes:

  1. Added a reset counter to force re-render of dropzone components when files are cleared
  2. Refactored ChatFileUploadButton to use its own dropzone instance instead of sharing props
  3. Improved handling of single file uploads when multiple files are dropped
  4. Disabled the File System Access API to ensure consistent behavior

Testing Plan

  • E2E Tests: Added a comprehensive Playwright test that verifies the upload button works after drag-dropping a file and deleting it
  • The test simulates drag-drop using DataTransfer, verifies file upload, deletes the file, and then confirms the upload button still works correctly

Contribution License Agreement

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.

@snyk-io
Copy link
Contributor

snyk-io bot commented Jan 11, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 11, 2026

✅ PR preview is ready!

Name Link
📦 Wheel file https://core-previews.s3-us-west-2.amazonaws.com/pr-13556/streamlit-1.52.2-py3-none-any.whl
📦 @streamlit/component-v2-lib Download from artifacts
🕹️ Preview app pr-13556.streamlit.app (☁️ Deploy here if not accessible)

Copy link
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@sfc-gh-nbellante sfc-gh-nbellante added security-assessment-completed Security assessment has been completed for PR change:bugfix PR contains bug fix implementation impact:users PR changes affect end users labels Jan 11, 2026
@sfc-gh-nbellante sfc-gh-nbellante changed the title fix: enforce single file limit when multiple files are dropped [fix] Fix upload button functionality after drag-drop and delete in st.chat_input Jan 11, 2026
@sfc-gh-nbellante sfc-gh-nbellante force-pushed the fixit/chat-input-single-file-validation branch 4 times, most recently from fd1e739 to aa61cf0 Compare January 11, 2026 19:00
@sfc-gh-nbellante sfc-gh-nbellante added the ai-review If applied to PR or issue will run AI review workflow label Jan 11, 2026
@github-actions github-actions bot removed the ai-review If applied to PR or issue will run AI review workflow label Jan 11, 2026
@github-actions
Copy link
Contributor

Summary

This PR fixes a bug where the file upload button in st.chat_input stops working after drag-dropping a file and then deleting it. The issue is caused by a known react-dropzone bug where the file input becomes unresponsive after files are removed.

Key changes:

  1. ChatFileUploadButton now creates its own useDropzone instance instead of receiving props from the parent
  2. A dropzoneResetCounter state is used with React's key prop to force remount when files are cleared
  3. useFsAccessApi: false is added to ensure consistent behavior across browsers
  4. New E2E test validates the fix

Code Quality

Strengths:

  • The implementation follows React best practices by using the "keyed reset" pattern to reset component state
  • Follows the "You Might Not Need an Effect" principle - the counter is incremented directly at call sites where files are cleared, not via useEffect
  • Clear, helpful comments explaining the purpose of the dropzoneResetCounter state
  • The props interface change in ChatFileUploadButton improves encapsulation - the component now manages its own dropzone instance

Minor observations:

  • The PR description mentions "Improved handling of single file uploads when multiple files are dropped" which doesn't appear in this diff - this may have been from a previous iteration

Code locations reviewed:

  • frontend/lib/src/components/widgets/ChatInput/ChatInput.tsx (lines 186-192, 258-280, 395-411, 441-465, 805-819)
  • frontend/lib/src/components/widgets/ChatInput/fileUpload/ChatFileUploadButton.tsx (lines 33-56)

Test Coverage

E2E Test (st_chat_input_test.py lines 1763-1828):

  • ✅ Comprehensive test that validates the complete bug scenario
  • ✅ Uses @use_chat_input decorator for navigation (follows best practices)
  • ✅ Uses @pytest.mark.only_browser("chromium") appropriately since DataTransfer API behavior varies across browsers
  • ✅ Uses expect assertions with Playwright (reduces flakiness)
  • ✅ Includes negative assertions (not_to_be_visible after deletion)
  • ✅ Tests the full cycle: drag-drop → verify upload → delete → verify deletion → upload via button → verify success

Frontend Unit Tests:

  • The existing unit tests in ChatInput.test.tsx should continue to work because they interact with the file upload through DOM queries (querySelector('input')) rather than component props directly
  • No new unit test was added for the specific bug fix, but the E2E test provides adequate coverage for this user-facing bug

Backwards Compatibility

No breaking changes

  • The ChatFileUploadButton props interface changed, but this is an internal component (not part of the public API)
  • External behavior remains unchanged - this is purely a bug fix
  • The fix should work across all browsers, even though the test is Chromium-only

Security & Risk

No security concerns identified

  • No new network calls or data handling
  • No changes to authentication or authorization logic

Risk assessment: Low

  • Targeted fix for a specific bug
  • Changes are isolated to file upload functionality
  • No impact on core data flow or state management

Recommendations

  1. Consider adding a frontend unit test for the ChatFileUploadButton component that verifies it can receive new dropzone configuration via key-based remount. While the E2E test covers the user scenario, a unit test would provide faster feedback during development.

  2. Minor documentation update: The PR description mentions "Improved handling of single file uploads when multiple files are dropped" but this change isn't visible in the current diff. Consider updating the description to match the actual changes, or clarify if this was addressed in a separate commit.

Verdict

APPROVED: This is a well-implemented fix for a real user-facing bug. The approach follows React best practices, the E2E test coverage is comprehensive, and there are no backwards compatibility or security concerns. The code is ready for merge.


This is an automated AI review. Please verify the feedback and use your judgment.

@sfc-gh-nbellante sfc-gh-nbellante marked this pull request as ready for review January 11, 2026 20:50
Copilot AI review requested due to automatic review settings January 11, 2026 20:50
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a bug where the file upload button in st.chat_input would stop working after drag-dropping a file and then deleting it. The fix refactors the upload button to use its own dropzone instance and implements a reset mechanism using a counter to force component remounting when files are cleared.

Changes:

  • Refactored ChatFileUploadButton to create its own dropzone instance instead of receiving shared props from parent
  • Added dropzoneResetCounter state in ChatInput to force re-render/remount of dropzone components when files are cleared
  • Disabled File System Access API (useFsAccessApi: false) for consistent behavior across dropzone instances
  • Added comprehensive E2E test verifying upload button functionality after drag-drop and delete cycle

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
frontend/lib/src/components/widgets/ChatInput/fileUpload/ChatFileUploadButton.tsx Refactored to use its own useDropzone hook with onDrop, multiple, accept, and maxSize props instead of receiving getRootProps/getInputProps from parent; added useFsAccessApi: false configuration
frontend/lib/src/components/widgets/ChatInput/ChatInput.tsx Added dropzoneResetCounter state to force component remounting on file clear; updated deleteFile and submitChatInput to increment counter when all files are cleared; added key={dropzoneResetCounter} to ChatFileUploadButton; configured useFsAccessApi: false in main dropzone
e2e_playwright/st_chat_input_test.py Added test_upload_button_works_after_drag_drop_and_delete test that simulates drag-drop using DataTransfer, verifies file upload, deletes the file, and confirms upload button still works correctly

@sfc-gh-nbellante sfc-gh-nbellante force-pushed the fixit/chat-input-single-file-validation branch from aa61cf0 to 79424be Compare January 12, 2026 17:04
@github-actions
Copy link
Contributor

github-actions bot commented Jan 12, 2026

📈 Frontend coverage change detected

The frontend unit test (vitest) coverage has increased by 0.0100%

  • Current PR: 86.6200% (12848 lines, 1719 missed)
  • Latest develop: 86.6100% (12840 lines, 1719 missed)

✅ Coverage change is within normal range.

📊 View detailed coverage comparison

@sfc-gh-nbellante sfc-gh-nbellante force-pushed the fixit/chat-input-single-file-validation branch from 2b3d996 to 8623c4d Compare January 12, 2026 18:31
…upload button

Move useDropzone hook into ChatFileUploadButton so it can be properly
reset via React key when files are deleted. This fixes a react-dropzone
bug where the file input becomes unresponsive after files are removed.

Add e2e test that validates the upload button still works after a
drag-drop + delete cycle.

See: react-dropzone/react-dropzone#972
Increment dropzoneResetCounter directly at call sites where files are
cleared rather than detecting the transition via useEffect. This follows
the 'You Might Not Need an Effect' principle from React docs.
Add documentation comment explaining why useFsAccessApi: false is set in ChatFileUploadButton, referencing issue #6176 for context.

Resolves comment 1
Add documentation comment explaining why useFsAccessApi: false is set in the main ChatInput dropzone config, referencing issue #6176.

Resolves comment 2
Change marker from only_browser("chromium") to skip_browser("webkit") to run the DataTransfer drag-drop test in both Chromium and Firefox.

Resolves comment 3
Add assertion to verify the originally deleted file doesn't reappear after uploading a new file, following E2E best practices.

Resolves comment 4
Remove explicit viewport size setting since this test doesn't depend on layout behavior - it's purely testing file upload mechanics.

Resolves comment 5
Revert skip_browser(webkit) back to only_browser(chromium) since
DataTransfer dispatch_event has inconsistent behavior in Firefox
as well. Added comment explaining the limitation.
The DataTransfer dispatch_event approach is unreliable across browsers.
Using button uploads still tests the same react-dropzone reset bug
(file input becomes unresponsive after files are deleted).
@sfc-gh-nbellante sfc-gh-nbellante force-pushed the fixit/chat-input-single-file-validation branch from 8623c4d to 2600482 Compare January 12, 2026 20:16
The upload button test was failing because 'second_upload.txt' (17 chars)
was being truncated by the UI's 16-character filename limit, causing the
get_by_text() locator to fail. Changed to 'first.txt' and 'second.txt'.
@sfc-gh-nbellante sfc-gh-nbellante merged commit e4bbc06 into develop Jan 13, 2026
45 checks passed
@sfc-gh-nbellante sfc-gh-nbellante deleted the fixit/chat-input-single-file-validation branch January 13, 2026 00:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:bugfix PR contains bug fix implementation impact:users PR changes affect end users security-assessment-completed Security assessment has been completed for PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants