Skip to content

feat: Threads UI drawer#2787

Open
smokku wants to merge 8 commits intocinnyapp:devfrom
smokku:threads-ui
Open

feat: Threads UI drawer#2787
smokku wants to merge 8 commits intocinnyapp:devfrom
smokku:threads-ui

Conversation

@smokku
Copy link

@smokku smokku commented Mar 16, 2026

This PR introduces dedicated side panel UI for conversation threads.

This is a direct port of SableClient/Sable#123
It was fixed/updated/modified for Cinny integration.

One significant difference to original is joining of MembersDrawer and ThreadDrawer in the same place instead of two separate drawers side-by-side. This change is isolated in separate commit and can be easily reverted.

Type of change

  • New feature (non-breaking change which adds functionality)

Copilot AI review requested due to automatic review settings March 16, 2026 07:21
@smokku smokku changed the title Threads UI drawer feat: Threads UI drawer Mar 16, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a dedicated Threads side panel (browser + thread view) integrated into the room UI, enabling users to browse, open, and reply within Matrix threads while keeping the main timeline and notifications thread-aware.

Changes:

  • Enable thread support in the Matrix client and update notification/read-receipt logic to ignore thread reply relation events.
  • Add new Threads UI: ThreadBrowser for listing/searching threads and ThreadDrawer for viewing a thread and replying inside it.
  • Integrate thread state into room header/timeline/input (open thread per-room, thread chips in timeline, thread-aware input drafts).

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/client/initMatrix.ts Enables SDK thread support on client start.
src/app/utils/room.ts Excludes thread-relation events from notification-event detection.
src/app/utils/notifications.ts Avoids marking thread replies as the latest “read” event.
src/app/utils/matrix.ts Adds shared toggleReaction helper (now used by timeline/thread UI).
src/app/state/room/roomToThreadBrowser.ts Adds per-room atom family for “thread browser open” state.
src/app/state/room/roomToOpenThread.ts Adds per-room atom family for currently open thread root event id.
src/app/features/room/message/Message.tsx Adds hideThreadButton support and minor layout tweak for message content container.
src/app/features/room/ThreadDrawer.tsx New: thread view drawer with root message, replies list, reply input, and read receipt behavior.
src/app/features/room/ThreadDrawer.css.ts New: styles for thread drawer and thread browser items.
src/app/features/room/ThreadBrowser.tsx New: thread list/search UI and thread preview cards.
src/app/features/room/RoomViewHeader.tsx Adds Threads button + unread badge; initializes/fetches threads and updates unread thread counts.
src/app/features/room/RoomViewFollowing.tsx Supports showing readers for a specific thread event + filtering by participants.
src/app/features/room/RoomTimeline.tsx Adds thread reply chips, hides thread reply relation events from main timeline, and updates reply/thread interactions.
src/app/features/room/RoomInput.tsx Adds thread-aware draft keying and thread reply relation construction for sends/uploads.
src/app/features/room/Room.tsx Wires thread browser/drawer rendering (desktop side panel vs mobile overlay).
src/app/components/editor/Editor.tsx Makes Slate initial value stable via state initializer.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a dedicated Threads side panel UI (thread browser + per-thread drawer) to the room view, wiring it into timeline interactions and message composition so threads behave as first-class navigation targets in Cinny.

Changes:

  • Enable Matrix thread support and suppress thread-reply events from main notifications/read markers.
  • Introduce new thread UI components (ThreadBrowser, ThreadDrawer) and per-room Jotai state for “threads panel open” / “open thread id”.
  • Update timeline, message, and composer flows to open threads, show a thread reply chip, and send thread replies (including uploads) correctly.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/client/initMatrix.ts Enables threadSupport on client start.
src/app/utils/room.ts Excludes thread-relation events from notification eligibility.
src/app/utils/notifications.ts Skips thread-relation events when choosing the latest read marker.
src/app/utils/matrix.ts Extracts reaction toggling into a reusable helper (supports thread timeline sets).
src/app/state/room/roomToThreadBrowser.ts Adds per-room atom family for thread browser open state.
src/app/state/room/roomToOpenThread.ts Adds per-room atom family for currently open thread root event id.
src/app/features/room/message/Message.tsx Adds hideThreadButton prop and adjusts message content layout width.
src/app/features/room/ThreadDrawer.tsx New thread drawer UI for viewing a thread and replying inside it.
src/app/features/room/ThreadDrawer.css.ts Styles for the drawer, overlay mode, and thread browser items.
src/app/features/room/ThreadBrowser.tsx New thread list/search UI and thread preview items.
src/app/features/room/RoomViewHeader.tsx Adds Threads button, unread thread badge, and initializes/fetches threads.
src/app/features/room/RoomViewFollowing.tsx Supports “following” indicator for a specific thread event + participant filtering.
src/app/features/room/RoomTimeline.tsx Hides thread replies from main timeline, adds thread chip + open-thread behavior.
src/app/features/room/RoomInput.tsx Adds thread-aware drafting/sending and constructs thread reply relations.
src/app/features/room/Room.tsx Integrates thread browser/drawer into the overall room layout (desktop + overlay mobile).
src/app/components/editor/Editor.tsx Makes Slate initial value stable via lazy useState initialization.

@kfiven
Copy link
Collaborator

kfiven commented Mar 16, 2026

Duplicate of #2492 ?

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a dedicated Threads side-panel UI to the room view, integrating Matrix threads (browse threads, open a thread, and reply within a thread) into Cinny’s existing drawers and timeline behavior.

Changes:

  • Enable Matrix client thread support and update notification/read-receipt logic to ignore thread reply relation events in the main timeline flow.
  • Add new thread browser + thread drawer UI, plus per-room Jotai state for “threads panel open” and “currently open thread”.
  • Update the room timeline, message actions, and composer logic to start/open threads, render a thread reply chip, and send messages with thread/reply relations.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/client/initMatrix.ts Enables threadSupport when starting the Matrix client.
src/app/utils/room.ts Excludes thread-relation events from notification-event detection.
src/app/utils/notifications.ts Avoids using thread-relation events as the “latest valid event” for room read receipts.
src/app/utils/matrix.ts Introduces reusable toggleReaction helper (supports thread timeline sets).
src/app/state/room/roomToThreadBrowser.ts Adds per-room atom family for thread browser open state.
src/app/state/room/roomToOpenThread.ts Adds per-room atom family for currently open thread root ID.
src/app/features/room/message/Message.tsx Adds hideThreadButton and adjusts message layout width.
src/app/features/room/ThreadDrawer.tsx New side panel to view a thread root + replies and compose within the thread.
src/app/features/room/ThreadDrawer.css.ts Styles for thread drawer/browser UI.
src/app/features/room/ThreadBrowser.tsx New side panel to list/search threads and open a thread.
src/app/features/room/RoomViewHeader.tsx Adds Threads button with unread badge + initializes/fetches thread data and counts.
src/app/features/room/RoomViewFollowing.tsx Supports “following” indicator scoped to a thread event + participant filtering.
src/app/features/room/RoomTimeline.tsx Hides thread replies from main timeline, renders thread reply chip, opens thread drawer, and refreshes on thread updates.
src/app/features/room/RoomInput.tsx Adds thread-root-aware draft keying and sends messages/uploads in thread context with correct relations.
src/app/features/room/Room.tsx Hosts thread drawer/browser alongside members drawer; opens thread drawer when navigating to a thread reply event.
src/app/components/editor/Editor.tsx Stabilizes Slate initialValue via component state to avoid re-init churn.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a dedicated threads side panel UI (thread browser + thread drawer) to the room view, integrating Matrix thread support into timeline rendering, notifications/read receipts, and the composer.

Changes:

  • Enable Matrix thread support at client startup and adjust notification/read logic to ignore thread-relation events in main-room unread calculations.
  • Introduce ThreadBrowser and ThreadDrawer side panels, with per-room Jotai state to track browser open/active thread.
  • Update timeline/message rendering to surface thread reply counts and open threads, while filtering thread replies out of the main timeline.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/client/initMatrix.ts Enables threadSupport when starting the Matrix client.
src/app/utils/room.ts Excludes thread-relation events from notification-event detection.
src/app/utils/notifications.ts Avoids using thread-relation events as the “latest valid event” for room read markers.
src/app/utils/matrix.ts Adds toggleReaction helper with optional thread timeline support.
src/app/state/room/roomToThreadBrowser.ts New atom family: thread browser open state per room.
src/app/state/room/roomToOpenThread.ts New atom family: open thread root ID per room.
src/app/features/room/message/Message.tsx Adds hideThreadButton prop and tweaks content container sizing.
src/app/features/room/ThreadDrawer.tsx New thread drawer UI: renders root + replies, supports replying/reactions, sends thread read receipts.
src/app/features/room/ThreadDrawer.css.ts Styles for drawer, overlay mode, and thread browser items.
src/app/features/room/ThreadBrowser.tsx New thread browser UI with search + thread previews.
src/app/features/room/RoomViewHeader.tsx Adds Threads button + unread thread badge; initializes/fetches threads and aggregates unread thread counts.
src/app/features/room/RoomViewFollowing.tsx Supports showing “following/reads” for a specific thread event + filtered participants.
src/app/features/room/RoomTimeline.tsx Adds thread reply chip, hides thread replies from main timeline, refreshes on thread updates, opens thread drawer on start-thread action.
src/app/features/room/RoomInput.tsx Adds thread-aware draft keying + reply/thread relation handling for sends/uploads.
src/app/features/room/Room.tsx Wires thread browser/drawer into layout (desktop side panel + mobile overlay).
src/app/components/editor/Editor.tsx Makes Slate initial value stable via useState initializer.

Comment on lines +122 to +141
const getReplyContent = (replyDraft: IReplyDraft): IContent['m.relates_to'] => {
const relation: Record<string, unknown> = {};

if (replyDraft.relation?.rel_type === RelationType.Thread) {
relation.event_id = replyDraft.relation.event_id;
relation.rel_type = RelationType.Thread;

if (replyDraft.eventId !== replyDraft.relation.event_id) {
relation['m.in_reply_to'] = {
event_id: replyDraft.eventId,
};
relation.is_falling_back = false;
} else {
relation.is_falling_back = true;
}
} else {
relation['m.in_reply_to'] = {
event_id: replyDraft.eventId,
};
}
Comment on lines +345 to +352
const relateTo =
contents.length > 0 && plainText.length === 0 && replyDraft
? getReplyContent(replyDraft)
: undefined;

contents
.map((content) => (relateTo ? { ...content, 'm.relates_to': relateTo } : content))
.forEach((content) => mx.sendMessage(roomId, threadRootId ?? null, content as any));
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.

3 participants