feat(web): swipe session rows to archive or delete on touch - #3154
Conversation
|
@btli This PR is a Bug fix, Feature, or UI / frontend change but the Demo section is missing or only contains a placeholder. These change types require a screenshot or screen recording so reviewers can see the new behaviour without checking out the branch. Please update the Demo section with:
Use |
f5a2567 to
371798c
Compare
Add a configurable horizontal swipe gesture on left-panel session rows for touch devices. Each direction (left/right) maps to an action — archive, delete, or none — persisted per-device and set from Settings → Appearance. Swipe→archive reuses the kebab's stop-then-archive handler; swipe→delete opens the same confirm dialog (no immediate delete). The gesture disambiguates from the existing dnd-kit drag by axis and yields once a long-press drag begins, so drag-to-project is unaffected. Co-authored-by: Isaac Signed-off-by: Bryan Li <bryan.li@gmail.com>
61d8e1c to
d037cea
Compare
Address review findings on the touch swipe-to-archive/delete gesture: - Only wrap the row in the translating moving-surface div when the swipe is actually available (touch + mobile + owner, not selection mode). Selection/desktop rows keep the prior `<li> > link` DOM so the selection-mode checkbox stays a sibling of the link's parent (fixes the standing sidebar bulk-actions e2e selection-mode assertion). - Add `touch-action: pan-y` to the swiped row so vertical scroll stays native and the horizontal gesture isn't handed off to native scroll (which would pointercancel during the pre-activation window). - Suppress the trailing synthesized click after a committed swipe so the row's <Link> can't navigate into the session being archived/deleted. Scope the capture-phase guard to the moving surface so it never swallows a click in the delete-confirm dialog. - Replace the stale-closure eslint-disable on the swipe handler with a latest-handler ref, so archive/delete always see the live row state. - Release pointer capture when a dnd-kit drag preempts a locked swipe. - Cache the swipe-action preference snapshot so getSnapshot stops re-parsing localStorage on every render; refresh only on real changes (writes, cross-tab storage events, and subscribe). Add a mobile e2e test that drives a real touch swipe (CDP touch) on a session row: swipe-left archives (server flag flips), swipe-right opens the delete-confirm dialog and cancels cleanly. Signed-off-by: Bryan Li <bryan.li@gmail.com>
d037cea to
5a9676a
Compare
|
Closing this PR because it has been labeled The label was last applied on 2026-07-26T23:17:55Z. If you are ready to continue, please reopen this PR or open a new one. |
|
Continued in #3985 — I don't have permission to reopen this one, so the work landed in a fresh PR against current @fanzeyi all three points from your review are fixed there:
#3985 has the demo recorded against the running app, plus the geometry readings behind those numbers. A second review pass also turned up a real gesture bug — a fast flick could commit off a stale offset and either miss the archive or fire when you had pulled back — fixed there with a regression test. |


Related issue
N/A
Summary
Session rows in the left panel had no touch-friendly quick actions — on
mobile you had to open the kebab to archive or delete. This adds a
configurable horizontal swipe gesture on each row:
maps to Archive, Delete, or None, persisted per-device.
one per direction). Defaults: swipe-left → Archive, swipe-right → None.
swipe→delete opens the same delete confirm dialog the kebab uses (no
immediate delete, no separate undo path). "None" is inert.
axis (horizontal past a threshold) and yields to the long-press drag, so
drag-to-file-into-project is unaffected. Gated to touch/mobile so desktop
hover controls don't regress.
Test Plan
Run in
web/(Node 20):npm run type-check— cleannpm run lint— no new issues in changed files (pre-existing warnings/errors only)npm run test— 4099 passed | 3 expected fail | 2 skippednpm run format:check— all files match Prettier styleNew/updated tests:
web/src/lib/swipeActionPreferences.test.ts— read/write/validate/defaults round-trip.web/src/shell/Sidebar.rowActions.test.tsx— swipe→archive drives thestop→archive handler; swipe→delete opens the confirm dialog (deletes only
after confirm); "none" is inert; both-directions-same-action; sub-threshold
swipe is a no-op; desktop ignores the gesture. Driven with
fireEvent.pointerDown/Move/Upsince jsdom has no real touch.Demo
Recorded on a mobile viewport (touch emulation). The clip shows: opening
Settings → Appearance → Swipe actions and setting Swipe left → Archive
and Swipe right → Delete, then back on the session list a swipe-left
archives a row (it slides over the archive hint and leaves the list), and a
swipe-right on another row opens the Delete confirmation dialog — delete
stays gated behind confirm, never immediate.
Download MP4
Type of change
Test coverage
Coverage notes
Behavior is covered by unit tests (preference round-trip + swipe gesture via
synthetic pointer events). The live touch gesture / visual affordance is shown in the Demo section above.
Changelog
Swipe left or right on a session row (touch devices) to archive or delete it, configurable in Settings → Appearance.
This pull request and its description were written by Isaac.