Skip to content

Commit a0a78f7

Browse files
authored
Hold channel loading state until the feed is complete so it opens at the latest message
The channel scroller's one-shot initial end-scroll fired against partial content (the synthesized "joined" opener renders as soon as the backend channel resolves, before the task cards arrive), and the engine never re-scrolls for late rows unless autoScroll forces it. Fold the feed-messages loading state into the gate and hold the spinner while any feed data is still loading, so the scroller mounts once with complete data and lands at the most recent message. Generated-By: PostHog Code Task-Id: d887d524-7d87-4d7a-b38c-b20289937ad1
1 parent d0002a5 commit a0a78f7

2 files changed

Lines changed: 21 additions & 8 deletions

File tree

packages/ui/src/features/canvas/components/ChannelFeedView.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,12 @@ export function ChannelFeedView({
695695
return merged;
696696
}, [tasks, systemMessages]);
697697

698-
if (isLoading && entries.length === 0 && pending.length === 0) {
698+
// Hold the loading state even when some entries already exist (the "joined"
699+
// opener renders as soon as the channel resolves, before the task cards):
700+
// mounting the scroller around partial content spends its one-shot initial
701+
// end-scroll on a near-empty list, and it never re-scrolls when the real
702+
// cards arrive. Pending kickoffs bail out so an optimistic post shows now.
703+
if (isLoading && pending.length === 0) {
699704
return (
700705
<div className="flex flex-1 items-center justify-center">
701706
<Spinner />

packages/ui/src/features/canvas/components/WebsiteChannelHome.tsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,26 @@ export function WebsiteChannelHome({ channelId }: { channelId: string }) {
6969
const { tasks, isLoading: isLoadingFeed } = useChannelFeed(
7070
backendChannel?.id,
7171
);
72-
// Until the backend channel resolves there's no feed to ask for, and the feed
73-
// query is disabled — which reports isLoading:false, indistinguishable from
74-
// "this channel is empty". useBackendChannel reports loading for the whole
75-
// identity-resolution window (settling if the resolve fails), so fold it in:
76-
// we can't call a channel empty until we know which channel it is.
77-
const isLoading = isLoadingChannels || isResolvingChannel || isLoadingFeed;
7872
// Marking this channel read lives in ChannelHeader (rendered by every channel
7973
// surface), so opening Artifacts or CONTEXT.md counts as reading it too.
8074

8175
// Durable "PostHog agent" rows (CONTEXT.md being built, …) live on the
8276
// backend channel — the same id the feed tasks use, not the folder id.
83-
const { messages: feedMessages } = useChannelFeedMessages(backendChannel?.id);
77+
const { messages: feedMessages, isLoading: isLoadingMessages } =
78+
useChannelFeedMessages(backendChannel?.id);
79+
// Until the backend channel resolves there's no feed to ask for, and the feed
80+
// query is disabled — which reports isLoading:false, indistinguishable from
81+
// "this channel is empty". useBackendChannel reports loading for the whole
82+
// identity-resolution window (settling if the resolve fails), so fold it in:
83+
// we can't call a channel empty until we know which channel it is. Messages
84+
// loading is included so the scroller mounts once with the complete feed and
85+
// its one-shot initial end-scroll lands at the latest message (it never
86+
// re-fires for late-arriving rows).
87+
const isLoading =
88+
isLoadingChannels ||
89+
isResolvingChannel ||
90+
isLoadingFeed ||
91+
isLoadingMessages;
8492
// The Slack-style "joined" opener, derived from the channel row so it renders
8593
// (and sorts first) even where the feed endpoint isn't deployed.
8694
const systemMessages = useMemo(() => {

0 commit comments

Comments
 (0)