Skip to content

add header threads attention menu#1572

Draft
tellaho wants to merge 2 commits into
mainfrom
tho/threads-header-activity
Draft

add header threads attention menu#1572
tellaho wants to merge 2 commits into
mainfrom
tho/threads-header-activity

Conversation

@tellaho

@tellaho tellaho commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Category: new-feature
User Impact: Users can find unread or active threads from the channel header without scanning a busy chat timeline.
Problem: Thread-level attention was too hard to parse when it lived inline with busy message rows. Users need a higher-level, repeatable shortcut for chasing unread or currently active threads across channels.
Solution: Add a ReceiptText header control beside the members action that opens one combined attention list. The badge counts unread replies only, while the dropdown merges unread and active threads and opens the selected thread directly with focus on the thread head.

File changes

desktop/src/features/channels/lib/threadAttention.ts
Adds pure derivation for the combined unread/active thread rows, badge total, row equality, preview collapsing, and coarse uptime formatting.

desktop/src/features/channels/lib/threadAttention.test.mjs
Covers row merging, sorting, unread totals, equality stabilization, preview behavior, and Ns/Nm/Nh uptime formatting.

desktop/src/features/channels/ui/ChannelThreadsAttentionMenu.tsx
Adds the header dropdown UI with the ReceiptText trigger, unread badge, combined attention rows, unread pills, and active uptime pills.

desktop/src/features/channels/ui/useThreadAttention.ts
Derives attention rows from thread unread counts, loaded timeline summaries, and thread-scoped bot typing while stabilizing row references for busy channels.

desktop/src/features/channels/ui/ChannelMembersBar.tsx
Places the new thread attention control immediately before the members/users affordance in inline headers and before the compact actions menu in compact headers.

desktop/src/features/channels/ui/ChannelScreenHeader.tsx
Passes thread attention data and selection callbacks from the channel screen into the header actions.

desktop/src/features/channels/ui/ChannelScreen.tsx
Wires the attention derivation into the channel header, includes DMs via the existing header path, and gates forums because they do not have the thread panel destination.

desktop/src/features/channels/useChannelPaneHandlers.ts
Adds a non-toggle thread-open path so selecting a dropdown item always opens and refocuses the thread instead of closing an already-open thread.

desktop/src/features/messages/useChannelTyping.ts
Scopes nested thread typing to the thread root rather than the immediate reply parent so active-thread detection aligns with thread heads.

desktop/src/features/messages/useChannelTyping.test.mjs
Adds coverage for channel-scoped typing, direct thread replies, and nested thread replies.

Reproduction Steps

  1. Open a normal channel or DM that has unread thread replies and/or an active bot typing in a thread.
  2. Look in the channel header immediately left of the users/members control.
  3. Confirm the ReceiptText control appears and its badge reflects unread thread replies only.
  4. Open the dropdown and confirm unread and active threads appear in one list, with active rows showing a coarse uptime such as 45s, 3m, or 2h.
  5. Select a row and confirm the thread panel opens and scroll-focuses the selected thread head; selecting the same row again should refocus rather than close the panel.
  6. Open a forum channel and confirm the control is not shown.

Screenshots/Demos

Not captured in this pass; this should get a manual click-through before merge because the navigation path was validated by code path and tests, not live app interaction.

Validation

  • pnpm test -- src/features/channels/lib/threadAttention.test.mjs src/features/messages/useChannelTyping.test.mjs from desktop/ — full suite passed: 1944/1944
  • pnpm typecheck from desktop/ — passed
  • pnpm check from desktop/ — passed

Notes for reviewers

  • Active uptime starts when the client first sees a thread as active, not from the true agent-turn start time. The true started-at signal is currently channel-scoped rather than thread-scoped.
  • Threads whose heads are outside the loaded message window fall back to N replies without author/preview, but unread count and navigation still work.

npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w and others added 2 commits July 6, 2026 23:23
getTypingScopeId keyed typing entries on the reply parent tag, so an agent
working deep in a thread produced a threadHeadId that matched no ingress row
(and missed the open-thread composer filter). Typing and completion events
already carry a root tag for nested replies — prefer it, falling back to the
parent for direct replies where root === parent and no root tag is emitted.

Both the registration and post-message suppression paths flow through the
same helper, so suppression keys stay consistent. Exported for tests.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Threads needing attention were hard to chase down inside a busy timeline,
so the affordance moves to the channel header: a ReceiptText control left
of the Users button, badged with the channel's unread-reply total, opening
one combined list of unread and active threads. Selecting a row opens the
thread panel scroll-focused on the thread head.

- threadAttention.ts: pure derivation — merge unread counts with active
  threads (active first by start recency, then unread by reply recency),
  coarse Ns/Nm/Nh uptime formatter, single-line head previews.
- useThreadAttention.ts: 'active' comes from thread-scoped bot typing;
  uptime anchors to a session-local first-seen map keyed on a stable
  active-set key, and rows are field-wise stabilized so busy-channel
  timeline churn never re-renders the header memo.
- ChannelThreadsAttentionMenu.tsx: trigger + badge + combined list; the
  uptime tick mounts only while the menu is open.
- handleOpenThreadFocused: non-toggle open + thread-head scroll target,
  so re-selecting an already-open thread refocuses instead of closing it.
- Wired through ChannelScreenHeader/ChannelMembersBar in both inline and
  compact variants; DMs get the control (DMs are channels), forums are
  gated off since they render no thread panel.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
@tellaho tellaho marked this pull request as draft July 7, 2026 08:02
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