Repository navigation
Conversation
Following a link to another message in an already-open channel thread now selects that message in the existing thread view instead of rebuilding it. The unfinished reply, its reply target and expanded branches stay. Same-thread membership comes from the linked message's signed root, never the link hint; nothing changes on screen until the new message is verified. Missing or failed targets keep the current thread with a single status notice. Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
wesbillman
left a comment
There was a problem hiding this comment.
Two correctness changes are needed; details and suggested repair scope are inline.
Star Lord automated source review via Wes’s account. Reviewed head c0b5252aea069a788213d39e7cf77aef0cfa6be5 against base d55d70a071bdaa2b499673dcd40ffa37a7a5d793. Source-only: no tests or app execution; CI was not checked, and desktop/packaged-runtime and keyboard-focus behavior remain unverified.
| navigation?.complete({ | ||
| status: "failed", | ||
| reason: result === "unavailable" ? "not-found" : "unavailable", | ||
| }); |
There was a problem hiding this comment.
[P2] Keep a failed selection from failing the entire page
For a routed target that is missing or has a read error, this call reaches createNavigationController.finish(), which sets the route to failed. src/app/App.tsx:253–272 then replaces PageView with the destination-error screen. That unmounts RetainedThreadPanel, disposes the old reader, and loses the mounted editor, reply target and expanded branches; the local notice/“Try again” cannot survive either. Keep recoverable selection failure local without failing away the retained page, while still settling the navigation attempt accurately. Add coverage through the real controller and app boundary—the new panel tests mock complete, so they cannot catch this teardown.
| const event = acceptTarget(response).find( | ||
| (event) => | ||
| event.id === id && contentKind(event) && inChannel(event, channelId), | ||
| ); |
There was a problem hiding this comment.
[P2] Stage the candidate without publishing it before overlays finish
acceptTarget is session.accept(events, false), which still broadcasts to every observation, including this thread’s receive. With an existing root, a newly fetched same-root reply is therefore merged into remote and published immediately here, before the overlay read below. An edited/deleted reply outside the loaded history can appear with its original content; if that overlay read fails, the unsafe intermediate row remains displayed even though retarget reports failure. Validate visibility and stage this first response without shared observation, then admit it with the completed overlay/tombstone evidence. Extend the real-session test to inspect the snapshot after the ID response while overlays are held, and after an overlay failure.
The thread composer's Working now popup and the sidebar's channel activity popup closed by flipping their open state directly when a row action navigated. Base UI's hover and press tracking never reset, so a trigger that stayed mounted would not open again on hover. Keeping a thread open across same-thread navigation made this reachable in the thread composer; the sidebar popup already showed it as an intermittent failure in the Me sidebar journey. Both now close through Base UI's own close action. Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
wesbillman
left a comment
There was a problem hiding this comment.
Two previously reported P2 changes remain unresolved: preserve the thread/editor on failed routed retargets and stage target content until overlay verification completes. Both production paths are unchanged; I found no additional source-demonstrated defect in the two-file popup-close follow-up.
Star Lord automated source review via Wes’s account. Head 40890abef86ffdeb61fa45a62a44e0dc31c921e0, base d55d70a071bdaa2b499673dcd40ffa37a7a5d793. Source-only: no tests or app execution; CI not checked. Desktop/native and actual keyboard/pointer focus remain unverified.
What this does
When a thread is open in the channel side pane and you follow a link to a message in that same thread, the thread now stays in place. It scrolls to and highlights the linked message instead of rebuilding itself. The reply you're writing stays exactly as it was, including which message you're replying to, along with your scroll position and any expanded branches. Before, the thread reloaded: your typed text came back from its saved draft, but the reply target, scroll position and expanded branches reset.
Links into a different thread still open that thread as before. Other places that show threads (previews, Inbox, media review) are unchanged.
Why it matters
This is mainly groundwork for upcoming channel workspace tabs, where several threads can stay open at once in the main and side panes. With tabs, history and links will routinely point at a thread that's already open. Back and Forward will switch between open thread tabs, and a link to a message will select the thread tab that already holds it. Each of those needs to land in the existing thread without rebuilding it, so you don't lose your place or what you were writing. This PR gives the thread view that ability. The tabs themselves come in a follow-up PR.
On its own, the visible change today is small. Following a link within the thread you're reading no longer resets your reply target or jumps your scroll.
New rule: Navigating within an open thread selects a message in that thread. It never rebuilds the thread or its reply editor.
How it works
FOUNDATIONfile): ordinary threads now use the same guarded message lookup that exact-message links already used. No new reader, cache, permission or signing path.Verification
All on this branch's head, rebased onto current
main:pnpm typecheck, Biome,git diff --check, and the pre-push hook (types and related unit tests, design checks, Clippy).agent-activity,channel-activity-corners,activity-navigation-focus,layout,me-workspace,thread-unread). The Me sidebar journey that failed intermittently on main passes 60 of 60 repeated WebKit runs with the fix.message-navigation,thread-opening, andnavigation-thread-history. A new journey checks that the actual editor element and the chosen reply target survive two in-thread navigations.Not yet checked
AbortSignal.any, which the app already depends on elsewhere.