Skip to content

Add support for sending folders via drag & drop - #504

Open
1270011 wants to merge 2 commits into
schlagmichdoch:masterfrom
1270011:feature/send-folders
Open

1270011 wants to merge 2 commits into
schlagmichdoch:masterfrom
1270011:feature/send-folders

Conversation

@1270011

@1270011 1270011 commented Aug 27, 2026

Copy link
Copy Markdown

Closes #290

This implements folder sending as specified in #290:
- Dropped directories (onto the page or onto a peer) are read recursively using the
File and Directory Entries API using the approach referenced in the issue, with the
two known pitfalls handled: all entries are gathered synchronously before the drop
handler yields (the DataTransferItemList is emptied afterwards), and
readEntries() is called in a loop since it returns at most 100 entries per call.
- A new dialog then lets the user choose whether to send each folder as a ZIP
archive
(directory structure preserved) or to send the contained files
individually - the optional chooser suggested in the issue.
- Zipping reuses the already bundled zip.js in store mode (level 0) via a dedicated
ZipWriter, so it cannot interfere with the shared writer used by the receive-side
"download as zip". Progress is shown on the peer icon (peer drop) or via a
persistent notification (share mode).
- The transfer protocol, the server and the receiving side are unchanged - fully
compatible with older clients and the Android app.

 Robustness details:
 - Unreadable entries (file deleted after drag start, broken symlinks) are skipped with
   a console warning instead of aborting the whole drop.
 - The drop guards are re-evaluated after the asynchronous traversal, so a dialog that
   opened in the meantime is not covered/focus-stolen.
 - Empty folders produce no zero-byte archives; loose files dropped alongside folders
   are sent unchanged.
 - Fixes a small pre-existing bug on the way: the "dropped on peer" guard in
   `PeersUI._onDrop` used `$$('x-peer').contains(e.target)`, which only checks the
   *first* peer element   a drop onto any other peer was handled twice (peer send +
   share mode activation). Now uses `e.target.closest('x-peer')`.

 Not included, to keep the main flow simple:
 - Folder selection via the file picker (`webkitdirectory` forces a folder-only picker,
   so it would need a second input).
 - Streaming the archive during transfer - the ZIP is currently materialized before
   sending, like the receive-side zip; streaming would require protocol changes.

 Translations: new strings are in `en.json`; a separate commit adds the German
 translations - feel free to drop it if translations should go through Weblate only.

 Tested manually on a deployed instance with Chromium and Firefox clients (folders with
 subfolders and >100 entries, folders mixed with loose files, empty folders, Escape to
 cancel, language switching while the dialog is open) plus automated tests for the
 traversal logic (readEntries batching, nested paths, `webkitGetAsEntry` fallback,
 unreadable entries).

1270011 and others added 2 commits August 27, 2026 11:59
Dropped directories are now read recursively using the File and
Directory Entries API. A new dialog lets the user choose whether to
send each folder as a ZIP archive (preserving its structure, created
with the already bundled zip.js) or to send the contained files
individually. The transfer protocol and the receiving side are
unchanged.

Closes schlagmichdoch#290

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement] Make sending and drag'n'drop of folders possible

1 participant