Skip to content

fix(dm): auto-scroll in DM thread modal no longer fires after PR #278's Codex round-1 fix #283

@sanity

Description

@sanity

Symptom

User reports: when new messages arrive in an open DM thread modal, the scroll position doesn't move to the bottom. Worked before, broken on production build commit `94fcd8c2` (PR #278).

Root cause

The auto-scroll `use_effect` in `ui/src/components/direct_messages/dm_thread_modal.rs:356` doesn't subscribe to any reactive signal. It:

  • Captures `message_count` as a plain `usize` (not a signal read)
  • Reads `OUTBOUND_SEND_COUNTER.peek()` — `.peek()` does NOT register a subscription
  • Touches `prev_outbound_bump` / `first_scroll_done` — `Rc`, not signals

Dioxus 0.7 `use_effect` only re-runs when a reactive signal read inside the closure changes. With no signal reads inside, the effect runs once on mount and never again.

The PR #278 Codex round-1 P2 fix replaced `.read()` with `.peek()` on `OUTBOUND_SEND_COUNTER` to avoid a hypothetical re-entrant borrow panic. `.peek()` is non-subscribing by design — that fix killed the auto-scroll's reactivity.

Working reference

`ui/src/components/conversation.rs` (main room) uses a `Signal<Option<Rc>>` updated by the last bubble's `onmounted` handler. The effect reads the signal (`let trigger = last_chat_element();`) → subscribes → re-runs on each new mount. Mirror that pattern for the DM modal.

Fix shape (~30 lines)

  1. Add `let last_dm_bubble: Signal<Option<Rc>> = use_signal(|| None);`
  2. In the bubble rendering loop, attach `onmounted` to the last bubble that sets `last_dm_bubble`.
  3. Inside `use_effect`, read `last_dm_bubble()` → subscribes → re-runs each render-with-new-bubble.
  4. Keep `OUTBOUND_SEND_COUNTER.peek()` for the "force-scroll on user send" decision (a value read on an already-triggered effect, not the subscription trigger).

Regression test

The test should pin "effect re-runs when a new bubble mounts." Build a fixture with a small thread, drive an inbound or outbound message → assert effect closure fired. Without this test, the next Codex round chasing a phantom `.peek` panic would silently re-break the same thing.

[AI-assisted - Claude]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions