mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Guard task surfaces and route targets
This commit is contained in:
@@ -78,6 +78,7 @@ import {
|
||||
mergeAgentNamesIntoProfiles,
|
||||
useChannelActivityTyping,
|
||||
} from "./useChannelActivityTyping";
|
||||
import { useAgentConversationRouteTarget } from "./useAgentConversationRouteTarget";
|
||||
import { useChannelAgentSessions } from "./useChannelAgentSessions";
|
||||
import { useChannelPanelHistoryState } from "./useChannelPanelHistoryState";
|
||||
import { useChannelProfilePanel } from "./useChannelProfilePanel";
|
||||
@@ -166,12 +167,21 @@ export function ChannelScreen({
|
||||
const mainInsetRef = useMainInsetRef();
|
||||
const currentPubkey = currentIdentity?.pubkey;
|
||||
const activeChannelId = activeChannel?.id ?? null;
|
||||
const canShowTasksSurface = activeChannel?.channelType === "stream";
|
||||
const effectiveSurfaceTab = canShowTasksSurface
|
||||
? activeSurfaceTab
|
||||
: "messages";
|
||||
useResetChannelSurfaceTabOnRouteOpen({
|
||||
activeChannelId,
|
||||
openThreadHeadId,
|
||||
setActiveSurfaceTab,
|
||||
targetMessageId,
|
||||
});
|
||||
React.useEffect(() => {
|
||||
if (!canShowTasksSurface && activeSurfaceTab === "tasks") {
|
||||
setActiveSurfaceTab("messages");
|
||||
}
|
||||
}, [activeSurfaceTab, canShowTasksSurface]);
|
||||
const effectiveOpenThreadHeadId =
|
||||
optimisticOpenThreadHeadId === undefined
|
||||
? openThreadHeadId
|
||||
@@ -325,6 +335,11 @@ export function ChannelScreen({
|
||||
const messageProfilesQuery = useUsersBatchQuery(messageProfilePubkeys, {
|
||||
enabled: messageProfilePubkeys.length > 0,
|
||||
});
|
||||
const messageProfilesReady =
|
||||
messageProfilePubkeys.length === 0 ||
|
||||
(!messageProfilesQuery.isPending &&
|
||||
!messageProfilesQuery.isFetching &&
|
||||
!messageProfilesQuery.isPlaceholderData);
|
||||
const channelMembersQuery = useChannelMembersQuery(activeChannel?.id ?? null);
|
||||
const channelMembers = channelMembersQuery.data;
|
||||
const managedAgentsQuery = useManagedAgentsQuery();
|
||||
@@ -744,71 +759,15 @@ export function ChannelScreen({
|
||||
setProfilePanelPubkey,
|
||||
],
|
||||
);
|
||||
const handledAgentConversationRouteTargetRef = React.useRef<string | null>(
|
||||
null,
|
||||
);
|
||||
React.useEffect(() => {
|
||||
if (!targetAgentConversationReplyId) {
|
||||
handledAgentConversationRouteTargetRef.current = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const targetKey = `${activeChannelId ?? "none"}:${targetAgentConversationReplyId}`;
|
||||
if (handledAgentConversationRouteTargetRef.current === targetKey) {
|
||||
return;
|
||||
}
|
||||
if (!activeChannel || activeChannel.channelType === "forum") {
|
||||
return;
|
||||
}
|
||||
|
||||
const agentReply =
|
||||
timelineMessages.find(
|
||||
(message) => message.id === targetAgentConversationReplyId,
|
||||
) ?? null;
|
||||
const agentReplyPubkey = agentReply?.pubkey;
|
||||
if (!agentReply || !agentReplyPubkey) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rootId = agentReply.rootId ?? agentReply.parentId ?? agentReply.id;
|
||||
const contextMessages = timelineMessages.filter(
|
||||
(candidate) =>
|
||||
candidate.id === rootId ||
|
||||
candidate.id === agentReply.id ||
|
||||
candidate.rootId === rootId ||
|
||||
candidate.parentId === rootId,
|
||||
);
|
||||
const parentMessage = agentReply.parentId
|
||||
? (timelineMessages.find(
|
||||
(candidate) => candidate.id === agentReply.parentId,
|
||||
) ?? null)
|
||||
: null;
|
||||
const threadRootMessage =
|
||||
timelineMessages.find((candidate) => candidate.id === rootId) ?? null;
|
||||
|
||||
handledAgentConversationRouteTargetRef.current = targetKey;
|
||||
void goChannel(activeChannel.id, { replace: true }).then(() => {
|
||||
openAgentConversation(
|
||||
{
|
||||
agentName: agentReply.author,
|
||||
agentPubkey: agentReplyPubkey,
|
||||
agentReply,
|
||||
channel: activeChannel,
|
||||
contextMessages,
|
||||
parentMessage,
|
||||
threadRootMessage,
|
||||
},
|
||||
{ publishMarker: false },
|
||||
);
|
||||
});
|
||||
}, [
|
||||
useAgentConversationRouteTarget({
|
||||
activeChannel,
|
||||
activeChannelId,
|
||||
goChannel,
|
||||
messageProfilesReady,
|
||||
openAgentConversation,
|
||||
targetAgentConversationReplyId,
|
||||
timelineMessages,
|
||||
]);
|
||||
});
|
||||
const mainTimelineTargetMessageId = useChannelRouteTarget({
|
||||
activeChannel,
|
||||
activeChannelId,
|
||||
@@ -938,7 +897,7 @@ export function ChannelScreen({
|
||||
activeChannel={activeChannel}
|
||||
activeChannelEphemeralDisplay={activeChannelEphemeralDisplay}
|
||||
activeChannelTitle={activeChannelTitle}
|
||||
activeSurfaceTab={activeSurfaceTab}
|
||||
activeSurfaceTab={effectiveSurfaceTab}
|
||||
actionsVariant={shouldCompactHeaderActions ? "compact" : "inline"}
|
||||
activeDmAvatarUrl={activeDmAvatarUrl}
|
||||
activeDmHeaderParticipants={activeDmHeaderParticipants}
|
||||
@@ -964,9 +923,9 @@ export function ChannelScreen({
|
||||
activeDmAvatarUrl,
|
||||
activeDmHeaderParticipants,
|
||||
activeDmPresenceStatus,
|
||||
activeSurfaceTab,
|
||||
channelHeaderChromeRef,
|
||||
currentPubkey,
|
||||
effectiveSurfaceTab,
|
||||
handleSurfaceTabChange,
|
||||
isAddBotOpen,
|
||||
joinChannelMutation.isPending,
|
||||
@@ -1098,7 +1057,7 @@ export function ChannelScreen({
|
||||
profilePanelView={profilePanelView}
|
||||
personaLookup={personaLookup}
|
||||
profiles={messageProfiles}
|
||||
surfaceTab={activeSurfaceTab}
|
||||
surfaceTab={effectiveSurfaceTab}
|
||||
onSurfaceTabChange={handleSurfaceTabChange}
|
||||
firstUnreadMessageId={firstUnreadMessageId}
|
||||
unreadCount={unreadCount}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
import * as React from "react";
|
||||
|
||||
import type { useAppNavigation } from "@/app/navigation/useAppNavigation";
|
||||
import type { OpenAgentConversationInput } from "@/features/agents/agentConversations";
|
||||
import type { TimelineMessage } from "@/features/messages/types";
|
||||
import type { Channel } from "@/shared/api/types";
|
||||
|
||||
type GoChannel = ReturnType<typeof useAppNavigation>["goChannel"];
|
||||
type OpenAgentConversation = (
|
||||
input: OpenAgentConversationInput,
|
||||
options?: { publishMarker?: boolean },
|
||||
) => void;
|
||||
|
||||
type UseAgentConversationRouteTargetOptions = {
|
||||
activeChannel: Channel | null;
|
||||
activeChannelId: string | null;
|
||||
goChannel: GoChannel;
|
||||
messageProfilesReady: boolean;
|
||||
openAgentConversation: OpenAgentConversation;
|
||||
targetAgentConversationReplyId: string | null;
|
||||
timelineMessages: readonly TimelineMessage[];
|
||||
};
|
||||
|
||||
export function useAgentConversationRouteTarget({
|
||||
activeChannel,
|
||||
activeChannelId,
|
||||
goChannel,
|
||||
messageProfilesReady,
|
||||
openAgentConversation,
|
||||
targetAgentConversationReplyId,
|
||||
timelineMessages,
|
||||
}: UseAgentConversationRouteTargetOptions) {
|
||||
const handledRouteTargetRef = React.useRef<string | null>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!targetAgentConversationReplyId) {
|
||||
handledRouteTargetRef.current = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const targetKey = `${activeChannelId ?? "none"}:${targetAgentConversationReplyId}`;
|
||||
if (handledRouteTargetRef.current === targetKey) {
|
||||
return;
|
||||
}
|
||||
if (!activeChannel || activeChannel.channelType === "forum") {
|
||||
return;
|
||||
}
|
||||
if (!messageProfilesReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
const agentReply =
|
||||
timelineMessages.find(
|
||||
(message) => message.id === targetAgentConversationReplyId,
|
||||
) ?? null;
|
||||
const agentReplyPubkey = agentReply?.pubkey;
|
||||
if (!agentReply || !agentReplyPubkey) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rootId = agentReply.rootId ?? agentReply.parentId ?? agentReply.id;
|
||||
const contextMessages = timelineMessages.filter(
|
||||
(candidate) =>
|
||||
candidate.id === rootId ||
|
||||
candidate.id === agentReply.id ||
|
||||
candidate.rootId === rootId ||
|
||||
candidate.parentId === rootId,
|
||||
);
|
||||
const parentMessage = agentReply.parentId
|
||||
? (timelineMessages.find(
|
||||
(candidate) => candidate.id === agentReply.parentId,
|
||||
) ?? null)
|
||||
: null;
|
||||
const threadRootMessage =
|
||||
timelineMessages.find((candidate) => candidate.id === rootId) ?? null;
|
||||
|
||||
handledRouteTargetRef.current = targetKey;
|
||||
void goChannel(activeChannel.id, { replace: true }).then(() => {
|
||||
openAgentConversation(
|
||||
{
|
||||
agentName: agentReply.author,
|
||||
agentPubkey: agentReplyPubkey,
|
||||
agentReply,
|
||||
channel: activeChannel,
|
||||
contextMessages,
|
||||
parentMessage,
|
||||
threadRootMessage,
|
||||
},
|
||||
{ publishMarker: false },
|
||||
);
|
||||
});
|
||||
}, [
|
||||
activeChannel,
|
||||
activeChannelId,
|
||||
goChannel,
|
||||
messageProfilesReady,
|
||||
openAgentConversation,
|
||||
targetAgentConversationReplyId,
|
||||
timelineMessages,
|
||||
]);
|
||||
}
|
||||
Reference in New Issue
Block a user