Skip to content

Add drag-and-drop file upload to workspace tree#548

Draft
hoyla wants to merge 11 commits intomainfrom
ljh-claude-drag-and-drop-upload
Draft

Add drag-and-drop file upload to workspace tree#548
hoyla wants to merge 11 commits intomainfrom
ljh-claude-drag-and-drop-upload

Conversation

@hoyla
Copy link
Contributor

@hoyla hoyla commented Feb 15, 2026

Addresses #314

Users can now drag files and folders from their file system directly onto any folder in the workspace tree (or the empty area below it) to trigger an upload to that location. The upload modal opens pre-populated with the dropped files and targeted at the correct workspace folder.

What this does

  • New shared utility (dropZoneUtils.ts) — readFilesFromDragEvent reads files and recursively reads directories from the DataTransfer, and dragEventContainsFiles distinguishes file-system drops from internal tree item drags.
  • TreeBrowser detects file-system drops via a new onDropFiles prop, falling through to the existing internal-move logic otherwise.
  • Workspaces resolves the target folder from the drop location and sets droppedFiles state, which flows through WorkspaceSummary to UploadFiles.
  • UploadFiles consumes droppedFiles via a useEffect, pre-populating the upload modal and opening it automatically.
  • FilePicker de-duplicated — its inline readDragEvent was replaced with the shared readFilesFromDragEvent.

Key implementation details

  • FileSystemEntry references are captured synchronously before any async work. Browsers invalidate the DataTransfer after the synchronous event handler returns, so awaiting inside the dataTransfer.items loop would silently lose all items beyond the first. The fix collects all entry handles up front, then processes them asynchronously.
  • readEntries() batching — Chrome/Safari cap directory reads at ~100 entries per call. readDirectoryEntry now loops until an empty batch is returned, ensuring large directories are fully read.
  • Graceful fallback — browsers that don't support webkitGetAsEntry() fall back to getAsFile().

Tested locally with

  • Single folder (containing subfolders and files)
  • Multiple files
  • Multiple folders
  • Mixed selection of files and folders

@hoyla hoyla added workspaces uploader feature Departmental tracking: work on a new feature labels Feb 15, 2026
@hoyla hoyla self-assigned this Feb 15, 2026
hoyla added 5 commits March 2, 2026 15:42
Users can now drag files and folders from their file system directly
onto folders in the workspace tree to trigger an upload to that location.

Changes:
- Add dropZoneUtils.ts with shared utilities for handling file drops
- Update TreeBrowser to detect and handle file system drops vs internal moves
- Update UploadFiles to accept pre-populated files via droppedFiles prop
- Wire up Workspaces component to pass dropped files to upload modal

Cross-platform compatible using the File System Access API (webkitGetAsEntry)
which is supported by all major browsers.
Chrome and Safari may return at most ~100 entries per readEntries() call.
The spec requires calling it repeatedly until an empty array is returned.
Without this, dropping a Finder folder with >100 files would silently
lose everything after the first batch.
@hoyla hoyla force-pushed the ljh-claude-drag-and-drop-upload branch from 617ca67 to 965ac4f Compare March 2, 2026 15:54
- Tighten file detection: exclude drags containing application/json
  to prevent internal tree drags being misidentified as file drops
- Add .catch() to readFilesFromDragEvent in TreeBrowser to handle
  errors (permissions, broken symlinks) instead of swallowing them
- Fix collapsed folder drop target: search workspace tree recursively
  instead of only expandedNodes, so drops onto collapsed folders go
  to the correct folder rather than silently falling back to root
- Remove unused readingDroppedFiles state from TreeBrowser
- Remove unused dragEventContainsInternalData export from dropZoneUtils
@hoyla hoyla force-pushed the ljh-claude-drag-and-drop-upload branch from 965ac4f to efea5a0 Compare March 2, 2026 15:57
…d selections

Collect all FileSystemEntry references synchronously from the DataTransfer
before any async work. The browser invalidates the DataTransfer after the
synchronous event handler returns, so awaiting inside the iteration loop
caused items beyond the first to be silently lost.

Also removes redundant double-call to webkitGetAsEntry() per item.
@hoyla hoyla changed the title DO NOT MERGE: Experiment: Add drag-and-drop file upload to workspace tree Add drag-and-drop file upload to workspace tree Mar 2, 2026
@hoyla
Copy link
Contributor Author

hoyla commented Mar 2, 2026

This does actually seem to work locally. When I'm back I might ask how to deploy to playground so others can try it.

hoyla added 4 commits March 3, 2026 22:49
Reject mixed selections (folders + files, or multiple folders) which
caused duplicate entries due to how the OS includes both a folder and
its visible children as separate DataTransfer items.

Now only two shapes are accepted:
 1. A single directory (full hierarchy preserved)
 2. One or more files with no directories

Show an alert to the user when an unsupported selection is dropped.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Departmental tracking: work on a new feature uploader workspaces

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Drag and drop from computer file system into workspace or folder to trigger an upload to that location ❤️❤️❤️❤️

1 participant