Select more than one file at a time #194

Closed
opened 2026-09-02 04:11:48 +00:00 by jcoffey-dev · 0 comments
Owner

Moving or deleting five files meant doing it five times, each with its own confirm.

Rows now select the way a file manager taught everyone:

gesture result
click replaces the selection
ctrl / cmd click adds or removes one
shift click the run from the last row clicked
click past the last row, or Escape clears it

Two or more selected raises a bar with Move to… and Delete; the row menu offers the same for the whole selection.

The parts that are decisions, not plumbing

One FileNode/set, not a loop. Not only for the round trip: a loop would apply half the moves and then throw, leaving a selection split across two folders with nothing saying which half went. One call is one answer, and notUpdated names whatever the server refused.

Right-clicking outside the selection moves it. Inside, the menu acts on all of it. Outside means you meant that row — so the selection follows the pointer rather than the menu quietly applying to something scrolled off-screen.

A drag carries the whole selection, which is why the payload is a list now (readDraggedIds), and why canDropFileNodes refuses unless every file in it can land: a drag that moves four of five and silently skips the fifth is worse than one that will not start.

A selection belongs to the folder it was made in. Changing folder or account drops it — rows left selected off-screen make the delete two folders later a surprise.

Verified

Mock stack, visible Chrome tab, four uploaded files:

result
plain click one row; DOM checked, not just the screenshot
ctrl-click two non-adjacent rows, bar says "2 items selected"
shift-click the run a–c, "3 items selected"
Move to… on 3 "Move 3 items", Move here disabled at their current parent, all three moved in one action, selection cleared
Delete on 3 "Delete 3 items?", all three gone, one toast
click empty space selection cleared (this was missing; found while testing and fixed)
folder change selection cleared

The drag gesture itself is not hand-verified — HTML5 drag-and-drop does not respond to synthetic mouse events. Its two new pure pieces are unit-tested instead: readDraggedIds (one id, many ids, and a drag carrying nothing of ours) and canDropFileNodes (all-or-nothing, a folder into itself, the empty list, the top level).

typecheck clean, 603 web + 110 server tests, i18n:check clean, build clean.

Merged 2026-09-01 as coffey-labs/ihasmail@34578ba426

Rebuilt from: git history, session transcript.

Moving or deleting five files meant doing it five times, each with its own confirm. Rows now select the way a file manager taught everyone: | gesture | result | |---|---| | click | replaces the selection | | ctrl / cmd click | adds or removes one | | shift click | the run from the last row clicked | | click past the last row, or Escape | clears it | Two or more selected raises a bar with **Move to…** and **Delete**; the row menu offers the same for the whole selection. ## The parts that are decisions, not plumbing **One `FileNode/set`, not a loop.** Not only for the round trip: a loop would apply half the moves and then throw, leaving a selection split across two folders with nothing saying which half went. One call is one answer, and `notUpdated` names whatever the server refused. **Right-clicking outside the selection moves it.** Inside, the menu acts on all of it. Outside means you meant that row — so the selection follows the pointer rather than the menu quietly applying to something scrolled off-screen. **A drag carries the whole selection,** which is why the payload is a list now (`readDraggedIds`), and why `canDropFileNodes` refuses unless *every* file in it can land: a drag that moves four of five and silently skips the fifth is worse than one that will not start. **A selection belongs to the folder it was made in.** Changing folder or account drops it — rows left selected off-screen make the delete two folders later a surprise. ## Verified Mock stack, visible Chrome tab, four uploaded files: | | result | |---|---| | plain click | one row; DOM checked, not just the screenshot | | ctrl-click | two non-adjacent rows, bar says "2 items selected" | | shift-click | the run a–c, "3 items selected" | | Move to… on 3 | "Move 3 items", **Move here** disabled at their current parent, all three moved in one action, selection cleared | | Delete on 3 | "Delete 3 items?", all three gone, one toast | | click empty space | selection cleared (this was missing; found while testing and fixed) | | folder change | selection cleared | **The drag gesture itself is not hand-verified** — HTML5 drag-and-drop does not respond to synthetic mouse events. Its two new pure pieces are unit-tested instead: `readDraggedIds` (one id, many ids, and a drag carrying nothing of ours) and `canDropFileNodes` (all-or-nothing, a folder into itself, the empty list, the top level). `typecheck` clean, 603 web + 110 server tests, `i18n:check` clean, build clean. **Merged** 2026-09-01 as coffey-labs/ihasmail@34578ba426cb <sub>Rebuilt from: git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.