feat(desktop): refine sidebar session drag reordering - #43661
Conversation
|
Pushed a second commit folding in three follow-ups so the PR lands complete:
Verified the same way as the base commit (live Chromium drag simulation + 13 unit tests; tsc/eslint clean on this branch). |
|
Third commit: pin-aware count labels and pagers. The Sessions label previously counted unpinned rows against a pin-inclusive total (pin one row and it reads 17/18 forever); pinned rows are always loaded, so they're now dropped from both sides. Messaging platform sections count pinned rows as loaded for their label/reveal-step (they're housed in Pinned, not missing from disk), take section recency from every loaded row, and only drop their section when nothing is left to show and nothing more exists on disk. tsc/eslint clean on this branch; the drop-zone suite still passes 13/13. |
|
Maintainer-ready after refresh. I merged current Verification:
MeshBoard merge dry-run passes with green checks and a fresh base. I attempted the actual merge through |
4094eb8 to
51929ea
Compare
|
Re-authored onto current Why a rebuild was needed: since this PR was opened, What's implemented (faithful to the PR's intent):
Adaptations to current
Verification:
|
teknium1
left a comment
There was a problem hiding this comment.
Thanks for rebuilding this against the extracted sidebar structure. The native drop-zone design addresses a real gap on current main: SidebarSessionRow only produces the composer drag payload today (apps/desktop/src/app/chat/sidebar/session-row.tsx:133-147).
Problems
apps/desktop/src/app/chat/sidebar/index.tsx:535-557accepts every pinned drag into Sessions. A pinned messaging thread is therefore unpinned and inserted intoagentSessionsorder, although messaging rows are fetched and rendered separately (apps/desktop/src/app/session/hooks/use-session-list-actions.ts:34-42). Its preview is also shown in the wrong section before disappearing.
Suggested changes
- Restrict positional Sessions preview/order persistence at
index.tsx:548to local Sessions rows, while preserving any intended unpin behavior for messaging rows. Add coverage for that pinned-messaging drop path; the new hook tests use generic payloads and do not exercise the sidebar's source-specific ordering.
Automated hermes-sweeper review.
| // the pre-positional behavior. Manual mode must be flagged for the custom | ||
| // order to win over the default started_at sort. | ||
| if (!showAllProfiles && !agentsGrouped) { | ||
| const nextIds = placeSessionIdAtAnchor( |
There was a problem hiding this comment.
This ordering path also runs after a pinned messaging row is dropped here: flags.pinned accepts it at line 535, but it is absent from agentSessions, so this persists a messaging ID into the local Sessions order and previews it in the wrong section. Gate positional preview/order writes to rows from the local Sessions slice; add a pinned-messaging drop test.
…estore live context, bulk actions, and fluid drag (#283) * fix(desktop): restore live session context and bulk archive * feat(desktop): refine sidebar session drag reordering Re-authors PR NousResearch#43661 onto current main. Since the original PR, the sidebar session section was extracted into sessions-section.tsx and the row into the primitive chrome (SidebarRowShell/Body/Grab/Lead), so the original section and row edits no longer applied; this rebuilds the feature on the current shape. Native drag-and-drop for sidebar session rows: drag a row body onto Pinned to pin it, drag a pinned row onto Sessions to unpin, and drag within either section to reorder — with a live motion.div FLIP preview that animates the row shuffle before the drop commits. The grab-handle dnd-kit reorder is retained alongside. - inline-refs: the session drag payload carries pinId + pinned, plus a pinned-marker MIME so dragover can filter by pin-state before the payload is readable at drop. - use-session-drop-zone (new): hook + helpers — anchor resolution with a dead-band hysteresis, preview splicing, and pin/unpin/reorder drop handling. - session-row: the row body is the native drag source with a stable data-session-id hit-test anchor, wrapping a motion.div layout="position" visual so rects stay put while the preview animates. - sessions-section / virtual-session-list: thread the drag callbacks and the drop-zone frame (dropActive highlight + handlers) through the extracted section. - index: pinned/sessions drop zones wired to pinSession(id, index) and the flat session-order store; sessionByAnyId, messaging, and recents counts now account for pinned rows the sections no longer render. pinSession(id, index) replaces the original PR's undefined reorderPinnedSession: insertUniqueId already filters an existing pin out before re-inserting at the given index, so one call serves both pin and pin-reorder. Drag interactions can't be exercised headlessly; typecheck, build, lint, and the 21 drop-zone unit tests are green. Drag-to-pin/unpin/reorder and the FLIP animation need manual QA in the running app. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style(desktop): satisfy restored feature lint * style(desktop): fix named import order * fix(desktop): restore packaged sidebar drag activation * fix(desktop): restore continuous cross-section session drag * fix(desktop): persist the rendered drag preview * fix(desktop): commit sidebar drag on physical release * fix(desktop): retain context usage between turns * fix(desktop): honor persisted sidebar row order * fix(desktop): ignore the active row during drop collision * fix(desktop): preserve context window on warm resume * fix(desktop): stabilize cross-lane drop anchors * fix(desktop): retain session order through sidebar load * fix(desktop): settle session drops at pointer release * fix(desktop): restore session multi-select and reliable compress * fix(desktop): repair bulk archive and session drag feel * fix(desktop): persist profile session archives --------- Co-authored-by: Omar Baradei <omar@kostudios.io> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…estore live context, bulk actions, and fluid drag (#283) * fix(desktop): restore live session context and bulk archive * feat(desktop): refine sidebar session drag reordering Re-authors PR NousResearch#43661 onto current main. Since the original PR, the sidebar session section was extracted into sessions-section.tsx and the row into the primitive chrome (SidebarRowShell/Body/Grab/Lead), so the original section and row edits no longer applied; this rebuilds the feature on the current shape. Native drag-and-drop for sidebar session rows: drag a row body onto Pinned to pin it, drag a pinned row onto Sessions to unpin, and drag within either section to reorder — with a live motion.div FLIP preview that animates the row shuffle before the drop commits. The grab-handle dnd-kit reorder is retained alongside. - inline-refs: the session drag payload carries pinId + pinned, plus a pinned-marker MIME so dragover can filter by pin-state before the payload is readable at drop. - use-session-drop-zone (new): hook + helpers — anchor resolution with a dead-band hysteresis, preview splicing, and pin/unpin/reorder drop handling. - session-row: the row body is the native drag source with a stable data-session-id hit-test anchor, wrapping a motion.div layout="position" visual so rects stay put while the preview animates. - sessions-section / virtual-session-list: thread the drag callbacks and the drop-zone frame (dropActive highlight + handlers) through the extracted section. - index: pinned/sessions drop zones wired to pinSession(id, index) and the flat session-order store; sessionByAnyId, messaging, and recents counts now account for pinned rows the sections no longer render. pinSession(id, index) replaces the original PR's undefined reorderPinnedSession: insertUniqueId already filters an existing pin out before re-inserting at the given index, so one call serves both pin and pin-reorder. Drag interactions can't be exercised headlessly; typecheck, build, lint, and the 21 drop-zone unit tests are green. Drag-to-pin/unpin/reorder and the FLIP animation need manual QA in the running app. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style(desktop): satisfy restored feature lint * style(desktop): fix named import order * fix(desktop): restore packaged sidebar drag activation * fix(desktop): restore continuous cross-section session drag * fix(desktop): persist the rendered drag preview * fix(desktop): commit sidebar drag on physical release * fix(desktop): retain context usage between turns * fix(desktop): honor persisted sidebar row order * fix(desktop): ignore the active row during drop collision * fix(desktop): preserve context window on warm resume * fix(desktop): stabilize cross-lane drop anchors * fix(desktop): retain session order through sidebar load * fix(desktop): settle session drops at pointer release * fix(desktop): restore session multi-select and reliable compress * fix(desktop): repair bulk archive and session drag feel * fix(desktop): persist profile session archives --------- Co-authored-by: Omar Baradei <omar@kostudios.io> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Reimplements sidebar drag-to-pin on upstream's POINTER drag session. The original branch rode the native HTML5 session transport (HERMES_SESSION_MIME, a DataTransfer drop-zone hook), which no longer exists: session-drag.ts replaced it with a resolver over the shared pointer drag session, and the sidebar became a deny area. The feature is re-authored as a second resolver target rather than rebased. - sidebar/session-drop.ts: the sidebar's drop resolution. Registered lists publish their FULL ordering (a virtualized list only paints a window, so the DOM alone can't commit an order) plus the commit; geometry is snapshotted once at drag start and each move is pure math against it. - session-drag.ts: the sidebar lists are tested before the zones — they sit in a zone that hosts no chat surface, which would otherwise deny the drop. Zone stack/split/link behavior is untouched. - Drop on PINNED pins (or re-slots) at the hovered position; drop a pinned row on SESSIONS unpins it and lands it at the hovered slot; dropping inside either list reorders. A release that changes nothing is a no-op, so a stray drag never flips recents into manual ordering. UX changed deliberately from the original: rows do NOT shuffle live under the pointer. Upstream's drag doctrine is placement-on-release (the tab strip shows an insertion divider, not a live shuffle), so the target list draws a ring plus a hairline at the insertion slot. That also removes the reason for the old hysteresis/dead-band logic — nothing animates under the pointer to chase. The dnd-kit grab handle keeps working for in-section reorder. Verified: npm run typecheck (all three projects), npx vitest run (3820 passed), eslint + prettier on the touched files, git diff --check.
51929ea to
ceded62
Compare
|
Rewritten on top of current Why: this branch was built on the native HTML5 session transport ( What it does now
Deliberate UX change: rows no longer shuffle live under the pointer. Files: new Registered lists publish their full ordering rather than being read off the DOM — a virtualized list only paints a window, so a DOM-derived order would silently drop off-screen sessions. Verification: |
|
FYI: opened #84984 (drag to reorder profile groups in the All-profiles sidebar). Same two files touched ( |
Problem
The first pass made sidebar rows draggable between Pinned and Sessions for pin/unpin, but the final accepted UX needs the whole row to behave like Claude/Codex session reordering:
Change
This updates the sidebar drag path around the native session row drag payload:
The existing dnd-kit grab-handle path is left for grouped workspace ordering; the flat Pinned/Sessions row reorder path no longer requires the handle.
How to review
Testing
npx vitest run --environment jsdom src/app/chat/sidebar/use-session-drop-zone.test.tsx— 21 tests passed.npm --prefix apps/desktop run typecheck— passed.npx eslint src/app/chat/sidebar/index.tsx src/app/chat/sidebar/session-row.tsx src/app/chat/sidebar/use-session-drop-zone.ts src/app/chat/sidebar/use-session-drop-zone.test.tsx src/app/chat/sidebar/virtual-session-list.tsx— passed.git diff --check— passed.npm --prefix apps/desktop run build— passed. The build-stamp script warned that the worktree was dirty before commit, as expected during pre-commit verification.