Skip to content

feat(tasks): add conversation multi-select right sidebar #2442

Open
janburzinski wants to merge 4 commits into
mainfrom
jan/eng-1406-support-shift-select-in-conversation-drawer
Open

feat(tasks): add conversation multi-select right sidebar #2442
janburzinski wants to merge 4 commits into
mainfrom
jan/eng-1406-support-shift-select-in-conversation-drawer

Conversation

@janburzinski

Copy link
Copy Markdown
Collaborator

Description

  • add multi selector support for conversations in right sidebar
  • shift select and bulk delete

Screenshot/Recording (if applicable)

https://streamable.com/vh10x6

Checklist
  • I kept this PR small and focused
  • I ran a self-review before opening this PR
  • I ran the relevant local checks or explained why not
  • I updated docs when behavior or setup changed
  • I added or updated tests when behavior changed, or explained why not
  • I only added comments where the logic is not obvious
  • I used Conventional Commits for commit
    messages and, when possible, the PR title

@greptile-apps

greptile-apps Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds multi-select support to the sidebar conversations list, including shift-click range selection and a bulk-delete flow via a floating SelectionBar. The feature is powered by a new useMultiSelect hook that manages selectedIds, a snapshotted selectionAnchor, and ordered selected IDs derived from the current list order.

  • use-multi-select.ts: New generic hook that tracks a Set<string> of selected IDs, stores a SelectionAnchor snapshot (ID + ordered ID list) to bound range selection, and exposes toggle (with optional { range: true } for shift-click), selectAll, clear, selectedCount, and selectedOrderedIds.
  • sidebar-conversations-list.tsx: Integrates the hook into each ConversationRow (checkbox + shift-click row handler), shows a sticky SelectionBar when anything is selected, and handles bulk deletion via the existing confirmActionModal pattern.

Confidence Score: 4/5

Safe to merge with awareness that shift-click can only expand (not contract) the selection range, and that bulk deletion clears the user's selection synchronously before async deletes resolve.

The two main logic concerns — stale anchor index during live-sort re-ordering and range selection overwriting manual picks — were already flagged in prior review threads and addressed in this implementation. The remaining behavioural difference (shift-click accumulates rather than pivoting, so a second shift-click can never shrink the selection) is a deliberate design trade-off. The bulk delete clears selection synchronously before async deletions resolve, so a failed delete leaves the list correct but the selection lost. Neither rises to a blocking issue.

use-multi-select.ts — the range-accumulation behaviour and anchor-snapshot ordering edge cases are worth a second look before this ships to users who rely heavily on keyboard-driven multi-select.

Important Files Changed

Filename Overview
apps/emdash-desktop/src/renderer/lib/hooks/use-multi-select.ts New hook managing multi-select state with range selection; anchor-snapshot approach correctly avoids live-sort drift during a selection gesture, though the accumulation-only range model (can't contract a shift-click range) differs from standard OS behavior.
apps/emdash-desktop/src/renderer/features/tasks/conversations/sidebar-conversations-list.tsx Integrates useMultiSelect into a virtualised row list; uses onCheckedChange + mousedown ref pattern to capture shift state correctly; bulk delete captures ID snapshot before modal open, avoiding stale-closure issues.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
apps/emdash-desktop/src/renderer/lib/hooks/use-multi-select.ts:41-49
**Shift-click can only expand selection, never contract it**

Range IDs are always added to the existing `Set` (`next.add`), so a second shift-click can never shrink a previously established range. In standard OS/spreadsheet behavior, shift-clicking closer to the anchor replaces the previous range with the smaller one. Here, if the user clicks A, shift-clicks E (selects A–E), then shift-clicks C, the expected result is A–C, but the actual result remains A–E. There is no way to shrink the selection via shift-click — the user must clear and start over. This is probably acceptable for a sidebar list, but worth being aware of if the behavior feels surprising during testing.

### Issue 2 of 2
apps/emdash-desktop/src/renderer/features/tasks/conversations/sidebar-conversations-list.tsx:291-294
**Selection cleared before async deletes resolve**

`clearSelection()` is called synchronously in `onSuccess`, immediately after dispatching all `deleteConversation` promises with `void`. If any deletion fails (network error, server rejection), the user's carefully assembled selection is already gone — they must re-select the conversations and retry manually. The existing single-delete path has the same pattern, but bulk deletes make losing the selection more costly. Consider clearing after all promises settle, or at minimum surfacing a toast on error so the user knows a retry is needed.

Reviews (3): Last reviewed commit: "fix(conversations): remove extra scroll ..." | Re-trigger Greptile

Comment thread apps/emdash-desktop/src/renderer/lib/hooks/use-multi-select.ts Outdated
Comment thread apps/emdash-desktop/src/renderer/lib/hooks/use-multi-select.ts
@janburzinski

Copy link
Copy Markdown
Collaborator Author

@greptileai

@janburzinski

Copy link
Copy Markdown
Collaborator Author

@greptileai

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.

1 participant