feat(desktop): drag-to-pin follow-ups — positional drop, messaging pins render, drag hint#146
Merged
Merged
Conversation
…ns render, drag hint Three gaps from the drag-to-pin feature (#145): Pinned messaging/cron-adjacent rows now render: sessionByAnyId only indexed cron + recents, so pinning a messaging-platform row (menu, shift-click, or drag) stored an id the Pinned section could never resolve — the pin silently vanished. Messaging sessions join the index, and pinned rows are filtered out of their platform section so pinning MOVES the row (matching how recents behave) instead of duplicating it. Drops are positional: rows carry data-session-id, the drop zone hands the drop event to its handler, and sessionDropAnchor() resolves the row under the pointer (top half = before, bottom half = after). Drag-to-pin inserts at that index in the raw pinned-id store (translated via the anchor's durable pin id, since rendered rows can be a subset of stored ids); drag-to-unpin splices into the saved flat-list order, falling back to the old surface-at-top reconcile for header drops, fresh anchors, or grouped/ALL-profiles views. The empty-Pinned hint now teaches the gesture: 'Drag a chat here, or shift-click to pin' (en/zh/zh-hant/ja). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🔎 Lint report:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Drag-to-pin (#145) shipped with three documented gaps, all called out in its Risks/gaps and on the MeshBoard task
hermes-desktop-drag-sessions-between-sessions-and:sessionByAnyIdindexes only cron + recents, so pinning a messaging-platform row (context menu, shift-click, or the new drag) stores an id the Pinned section can never resolve — the pin takes effect in the store and renders nothing. This predates feat(desktop): drag sessions between Pinned and Sessions to pin/unpin #145 (the menu had the same bug) but drag-to-pin made it much easier to hit.What changed
apps/desktop/src/app/chat/sidebar/index.tsxsessionByAnyIdnow also indexes$messagingSessions(recents still win id collisions), so messaging pins resolve and render in Pinned. Side benefit: server FTS hits for loaded messaging sessions resolve to the real row instead of a synthesized placeholder.messagingGroupsfilterspinnedRealIdSetso pinning MOVES the row out of its platform section (same semantics as recents) instead of duplicating it; a platform whose every row is pinned drops its section.indexOfof the anchor's durable pin id — rendered rows can be a subset of stored ids, so rendered position is not trusted. Unpin: splice the dropped id into the saved flat-list order before/after the anchor; header drops, fresh-row anchors, and grouped/ALL-profiles views keep the previous behavior (recency reconcile surfaces the row at the top). The handler block also moved below the memos it reads so declaration order matches data flow.apps/desktop/src/app/chat/sidebar/use-session-drop-zone.ts—onDropSessionnow receives the drop event; new exportedsessionDropAnchor(event)resolves the[data-session-id]row under the pointer with top-half/bottom-half = before/after semantics.apps/desktop/src/app/chat/sidebar/session-row.tsx— rows carrydata-session-id(used by the anchor lookup; also handy for tests).apps/desktop/src/i18n/{en,zh,zh-hant,ja}.ts— empty-Pinned hint becomes "Drag a chat here, or shift-click to pin" (each locale keeps its existing pin/chat terminology).apps/desktop/src/app/chat/sidebar/use-session-drop-zone.test.tsx— 4 newsessionDropAnchortests (before/after midpoint, nested children, null off-row); drop tests updated for the(payload, event)signature.How to review
use-session-drop-zone.ts—sessionDropAnchorand the event pass-through are the whole mechanism.index.tsxdrop handlers — the pin-index translation comment explains why anchor → raw-store index goes through the durable pin id; the unpin path's guards (flat-list only, anchor must exist in the saved order) fall back to pre-positional behavior rather than guessing.index.tsxmessaging changes — one added list in the index memo + onecontinueguard in the platform-split loop; check the dep arrays picked upmessagingSessions/pinnedRealIdSet.Evidence
Live verification in real Chromium (vite dev renderer, seeded stores; same harness as #145):
$pinnedSessionIds = ["s-pin-1","s-2","s-pin-2"]— between the two existing pins, rendered in that order.["s-1","s-pin-2","s-3","s-4"]and Sessions rendered One → Bravo → Three → Four.pinnedIds=[...,"m-2"], the row rendered under Pinned, and the Discord section listed onlym-1— per-section row audit:Pinned => [s-pin-1,s-2,m-2] || Sessions => [s-1,s-pin-2,s-3,s-4] || Discord => [m-1].npx vitest run --environment jsdom src/app/chat/sidebar/use-session-drop-zone.test.tsx: 13/13 pass.Verification
npm run type-check(tsc -b): pass.npx eslinton all eight touched files: pass, no warnings.npx vitest run --environment jsdom) atorigin/main(410c71f) + this diff: no new failures — the sorted FAIL set equals the documented baseline minus the twouse-prompt-actionsfile-attach failures that fix(desktop): restore file.attach client upload path (Phase 2b companion to #142) #144 fixed on main (diff-verified against the recorded baseline set).npm run build(tsc -b + production vite build): pass.Risks / gaps
Collaborators