* perf(issue-detail): memoize timeline render to fix Inbox long-timeline freeze
On long-timeline issues (thousands of comments), opening from Inbox hard-freezes
the browser tab because every WS-driven parent re-render re-runs the full
react-markdown + rehype-* + lowlight pipeline for every comment. This is the
S3 mitigation for multica#1968:
- Wrap ReadonlyContent in React.memo so equal-content re-renders skip the
markdown pipeline entirely (the dominant cost per comment).
- Wrap CommentCard in React.memo so unrelated parent state updates don't
re-render every card.
- useMemo the timeline grouping in IssueDetail so the allReplies Map and
groups array references are stable across re-renders that don't change
timeline.
- Stabilize toggleReaction via a timelineRef so its identity doesn't change
on every WS event, which previously defeated CommentCard memoization.
Virtualization (S2) is the root fix for first-paint cost and lands separately.
Co-authored-by: multica-agent <github@multica.ai>
* fix(issue-detail): destructure mutate/mutateAsync so CommentCard memo holds
Per review on PR #2025: TanStack Query v5 returns a fresh result wrapper
from useMutation on every render, with only the inner mutate / mutateAsync
functions guaranteed stable. The previous useCallback dependencies listed
the whole mutation object, so on every parent re-render the callbacks
flipped identity — defeating React.memo on CommentCard and leaving the
long-timeline mitigation only half-effective.
Pull just the stable handles into deps. Add a renderHook-based regression
test that re-renders useIssueTimeline twice and asserts the four callbacks
passed to CommentCard keep the same identity.
Co-authored-by: multica-agent <github@multica.ai>
---------
Co-authored-by: multica-agent <github@multica.ai>
WebSocket event handlers for comment:created and activity:created
appended new entries to the end of the timeline array without sorting.
When events arrived out of order (e.g. agent replying rapidly), comments
displayed out of chronological order.
Sort the timeline by created_at after each append to maintain correct
chronological ordering.
Closes#1032
commentToTimelineEntry() was dropping the attachments field, and
comment-card never rendered entry.attachments. Attachments uploaded
through the CLI (not embedded in markdown) were invisible in the UI.
- Add attachments to commentToTimelineEntry() conversion
- Add AttachmentList component that renders standalone attachments
(skipping those already referenced in the markdown content)
- Render AttachmentList in both CommentRow and CommentCard