[deep dive] Threads: full UI/UX audit + "mark all threads read" #165

Open
opened 2026-09-17 23:06:35 -04:00 by jared · 3 comments
Owner

Jared: "we need an extreme deep dive into our implementation of threads as a whole, especially UI/UX."

Audit the whole thread surface: thread panel open/close and navigation, thread composer parity with the main composer (toolbar, drafts, paste, uploads, mentions), "N replies" chips + unread badges, per-thread read tracking, the Threads list panel (sorting, filters, empty states), notifications overrides, jumping between root and thread, replies-in-thread vs. replies-to-thread-root confusion, mobile layout, keyboard/a11y, and edge cases (edited/redacted roots, threads in encrypted rooms, threads across the search/bookmarks/forward features). Plus the small feature: Mark all threads read in the Threads list panel.

Deliverable: findings ranked by severity as a checklist here, then fixes in reviewed batches (a11y and privacy items first — see #140/#141).

Jared: "we need an extreme deep dive into our implementation of threads as a whole, especially UI/UX." Audit the whole thread surface: thread panel open/close and navigation, thread composer parity with the main composer (toolbar, drafts, paste, uploads, mentions), "N replies" chips + unread badges, per-thread read tracking, the Threads list panel (sorting, filters, empty states), notifications overrides, jumping between root and thread, replies-in-thread vs. replies-to-thread-root confusion, mobile layout, keyboard/a11y, and edge cases (edited/redacted roots, threads in encrypted rooms, threads across the search/bookmarks/forward features). Plus the small feature: **Mark all threads read** in the Threads list panel. Deliverable: findings ranked by severity as a checklist here, then fixes in reviewed batches (a11y and privacy items first — see #140/#141).
jared added this to the Features 2026-Q4 milestone 2026-09-17 23:06:35 -04:00
jared added the priority: mediumuxarea: threadsresearch labels 2026-09-17 23:06:35 -04:00
jared self-assigned this 2026-09-17 23:06:35 -04:00
Author
Owner

From #163: media posted inside threads never appears in the Media Gallery — thread replies are partitioned out of the room timeline by the SDK (room.partitionThreadedEvents), so neither the old live-timeline scan nor the new detached media timeline sees them. Include in this audit: decide whether the gallery should walk thread timelines (or the server-side filter should include thread relations) and whether the gallery tile should say which thread an item came from.

From #163: media posted **inside threads** never appears in the Media Gallery — thread replies are partitioned out of the room timeline by the SDK (`room.partitionThreadedEvents`), so neither the old live-timeline scan nor the new detached media timeline sees them. Include in this audit: decide whether the gallery should walk thread timelines (or the server-side filter should include thread relations) and whether the gallery tile should say which thread an item came from.
Author
Owner

From the #141 verification: each thread read receipt is POSTed twice for the same event (observed 4 /receipt/ requests for 2 events, identical bodies). ThreadPanel.tsx:150-176 runs markRead on both ThreadEvent.NewReply and RoomEvent.Timeline; lastReadEventIdRef should dedupe, so either both fire before the ref updates (it is set synchronously — unlikely) or two ThreadPanel instances are mounted. Low priority; fold into the audit.

From the #141 verification: each thread read receipt is POSTed **twice** for the same event (observed 4 `/receipt/` requests for 2 events, identical bodies). `ThreadPanel.tsx:150-176` runs `markRead` on both `ThreadEvent.NewReply` and `RoomEvent.Timeline`; `lastReadEventIdRef` should dedupe, so either both fire before the ref updates (it is set synchronously — unlikely) or two `ThreadPanel` instances are mounted. Low priority; fold into the audit.
Author
Owner

Threads audit — exercised end to end on the local dev homeserver (Playwright, desktop 1400px + Pixel 7)

Fixed on lotus (all pushed):

  • 58a716c7opening a thread on a pristine composer crashed the client (shared Slate initialValue; see #184). This alone explains most "threads feel broken" reports.
  • f2f49842every reply in the panel showed a Thread ↩ <root author> <root text…> quote because the spec's fallback reply relation (is_falling_back → root) was rendered like a real reply. Root is already pinned at the top, so that was noise on every row. Genuine reply-to-a-reply quotes stay. Before/after: the first screenshot on this issue vs the one below.
  • f2f49842no way to open the Threads list (or Widgets) on a phone: the header buttons were Desktop-only and the ⋮ menu had no entry. Both added next to Members / Media Gallery. (Closes #211.)
  • Thread receipts honour the privacy toggles (#141) and per-thread notifications behave Slack-style (#184) — verified separately.

Verified working: chips "N replies · time" on roots, replies never inline in the main timeline; panel = root + divider + reply timeline + own composer, opens scrolled to the latest reply; own reply updates the chip live; reply-to-a-reply produces a proper m.thread + non-fallback m.in_reply_to; Escape closes the panel; edit inside a thread keeps the thread relation and re-renders; reactions inside a thread work; deleting a reply drops the chip count; redacting the root while the panel is open leaves a stable "deleted" panel; Threads list with All/Unread/Participating + Recent/Oldest, participant avatars, "N replies · just now"; mobile panel is full-screen with Back.

Filed as follow-ups (need a decision or are bigger):

  • #217 [decide] visiting a room marks all its threads read, so thread unread badges never survive a glance at the room (Discord/Slack keep them until the thread is opened). Also causes the duplicate receipt seen in #141.
  • #218 thread panel + member drawer + timeline do not fit at 1400 px; composers collapse to "S…".
  • "Mark all threads read" (this issue's title) does not exist yet — keep this issue open for that, or fold it into #217 since the current behaviour already marks everything read on room visit.
  • Media posted inside threads is invisible to the Media Gallery (noted earlier).

panel after fix
list · mobile · chip

## Threads audit — exercised end to end on the local dev homeserver (Playwright, desktop 1400px + Pixel 7) **Fixed on `lotus`** (all pushed): - `58a716c7` — **opening a thread on a pristine composer crashed the client** (shared Slate `initialValue`; see #184). This alone explains most "threads feel broken" reports. - `f2f49842` — **every reply in the panel showed a `Thread ↩ <root author> <root text…>` quote** because the spec's fallback reply relation (`is_falling_back` → root) was rendered like a real reply. Root is already pinned at the top, so that was noise on every row. Genuine reply-to-a-reply quotes stay. Before/after: the first screenshot on this issue vs the one below. - `f2f49842` — **no way to open the Threads list (or Widgets) on a phone**: the header buttons were Desktop-only and the ⋮ menu had no entry. Both added next to Members / Media Gallery. (Closes #211.) - Thread receipts honour the privacy toggles (#141) and per-thread notifications behave Slack-style (#184) — verified separately. **Verified working:** chips "N replies · time" on roots, replies never inline in the main timeline; panel = root + divider + reply timeline + own composer, opens scrolled to the latest reply; own reply updates the chip live; reply-to-a-reply produces a proper `m.thread` + non-fallback `m.in_reply_to`; Escape closes the panel; edit inside a thread keeps the thread relation and re-renders; reactions inside a thread work; deleting a reply drops the chip count; redacting the root while the panel is open leaves a stable "deleted" panel; Threads list with All/Unread/Participating + Recent/Oldest, participant avatars, "N replies · just now"; mobile panel is full-screen with Back. **Filed as follow-ups (need a decision or are bigger):** - #217 **[decide]** visiting a room marks all its threads read, so thread unread badges never survive a glance at the room (Discord/Slack keep them until the thread is opened). Also causes the duplicate receipt seen in #141. - #218 thread panel + member drawer + timeline do not fit at 1400 px; composers collapse to "S…". - "Mark all threads read" (this issue's title) does not exist yet — keep this issue open for that, or fold it into #217 since the current behaviour already marks everything read on room visit. - Media posted inside threads is invisible to the Media Gallery (noted earlier). ![panel after fix](https://code.lotusguild.org/attachments/0af29802-339a-4bcf-85aa-03b1073b8cba) ![list · mobile · chip](https://code.lotusguild.org/attachments/b95b8788-2c5d-4a6a-bbe3-db429bc1fd82)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#165