Skip to content

Open chat history at a pinned message or reply, then scroll to the present (GRYT-1686) - #812

Merged
sivert-io merged 2 commits into
mainfrom
claude/GRYT-1686-history-window
Oct 6, 2026
Merged

sivert-io merged 2 commits into
mainfrom
claude/GRYT-1686-history-window

Conversation

@sivert-io

Copy link
Copy Markdown
Member

The client half of opening chat history at any message. Task: GRYT-1686. The server half is server#282. Without it, this falls back to the 1,000-message search from #811, so it can merge first.

What it does

  • Clicking an old pin or reply quote asks the server for the page around that message and opens history there, with the message in view.
  • Scrolling down loads newer pages. When they reach the present, the window merges into the channel and the bar goes away.
  • While you're in a window, a bar above the composer says "You're looking at older messages", with a Jump to present button.
  • Sending a message, or switching conversation, also returns to the present.

How

  • useHistoryWindow keeps the window as its own list on top of the channel's. useChat re-syncs the channel list from a cache that always runs up to the newest message, so a list with a gap can't live in it.
    • Edits, reactions, deletions and settled attachments reach the window through the same handlers.
    • New messages don't, because they belong at the present.
  • useChat leaves window pages (around, after, or before while a window is open) to the window, and shows the window's list, older-page loader and hasOlder while it's open.
  • useChatScroll loads newer pages within 200px of the bottom of a window. Inside a window it no longer auto-scrolls on a changed last row, and the ResizeObserver stops holding the bottom.
  • useJumpToMessage tries openAt first. It falls back to paging older history when the answer is unsupported, and says the message is gone when it's missing.

Checked

In a headless browser against a seeded channel (220 messages, a pin on the 4th):

  • server#282: the click shows the pinned message in view after about 1.7 s, with the bar up. Four newer pages reach the present, and the window merges and drops the bar.
  • Jump to present: back at the bottom with only the latest page loaded. At first it stopped about 900px short, which is why it now scrolls instantly.
  • Main's server (no around): falls back to paging, and the message is in view after about 4 s.
  • No page errors in any run. yarn lint passes.

Look at

  • useChat changes are small but sit on the path every channel uses. Nothing changes until openAt is called: historyWindow.messages is null, and every branch falls through to the old values.
  • MLS DMs don't use the window yet, because their timeline merges an archive (mergeTimeline). They get the paging search.
  • An older server answers around with the newest page. If a normal latest-page fetch, from a reconnect for instance, lands while a jump is waiting, the jump reads it as "unsupported" and pages instead. It still finds the message, just more slowly.

🤖 Generated with Claude Code

…esent (GRYT-1686)

Jumping to an old pin or reply quote loaded every page in between and
gave up after 1,000 messages. On a server with server#282, it now asks
for the page around that message and opens history there. Scrolling
down loads newer pages. A bar saying "You're looking at older messages"
has a Jump to present button.

The window is its own list (useHistoryWindow) on top of the channel's.
useChat keeps the channel list in step with a cache that always runs
up to the newest message, so a list with a gap in it can't live there.
Edits, reactions and deletions still reach the window. New messages
don't, because they belong at the present. When the window's newer
pages reach the present, it merges into the cache and goes away.
Sending a message, or switching conversation, leaves it as well.

On a server without `around`, the answer is the newest page. The client
recognises that and falls back to the 1,000-message search from #811.
MLS DMs use that search too, because their timeline is merged with an
archive.

useChatScroll loads newer pages near the bottom of a window, and stops
holding the view at the bottom there, since a window's last row isn't
the present. Jump to present scrolls instantly. A smooth scroll from the
top crossed the load-older line, and the prepend that followed stopped
it short.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The check runs the ResizeObserver effect's source with the refs it
reads. That effect now also reads detachedRef, so the check passes one,
and a new case confirms an old window isn't held at its bottom.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@sivert-io
sivert-io merged commit 4b66519 into main Oct 6, 2026
17 checks passed
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