-
Notifications
You must be signed in to change notification settings - Fork 29
Add channel task surface #1324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: kennylopez-agent-tasks-navigation-integration
Are you sure you want to change the base?
Add channel task surface #1324
Changes from all commits
85655c0
c1cd1f1
82caa72
711fd65
7e7f20c
891e97a
354b1b8
9c2f9a9
5edb57e
69af99a
9deef79
86e6db1
cd636b3
2b8ced7
7576016
0c5ca1f
1495948
7ef2a4c
c3d6efa
80cfc27
846891b
445da25
5dba68b
97a3962
07b8f35
0558c09
7d174a3
c2132dd
51cc6be
3488c7f
d7c5b0d
b31c6e9
c1842df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import * as React from "react"; | ||
| import { useQueryClient } from "@tanstack/react-query"; | ||
|
|
||
| import { getCachedSearchHitEvent } from "@/app/navigation/searchHitEventCache"; | ||
| import { useAppNavigation } from "@/app/navigation/useAppNavigation"; | ||
|
|
@@ -8,21 +9,30 @@ import { | |
| getThreadReference, | ||
| isBroadcastReply, | ||
| } from "@/features/messages/lib/threading"; | ||
| import { mergeTimelineCacheMessages } from "@/features/messages/hooks"; | ||
| import { channelMessagesKey } from "@/features/messages/lib/messageQueryKeys"; | ||
| import { useProfileQuery } from "@/features/profile/hooks"; | ||
| import { relayClient } from "@/shared/api/relayClient"; | ||
| import { useIdentityQuery } from "@/shared/api/hooks"; | ||
| import { getEventById } from "@/shared/api/tauri"; | ||
| import type { RelayEvent } from "@/shared/api/types"; | ||
| import { | ||
| CHANNEL_TIMELINE_CONTENT_KINDS, | ||
| CHANNEL_TIMELINE_STATE_KINDS, | ||
| } from "@/shared/constants/kinds"; | ||
| import { ViewLoadingFallback } from "@/shared/ui/ViewLoadingFallback"; | ||
|
|
||
| type ChannelRouteScreenProps = { | ||
| channelId: string; | ||
| selectedPostId: string | null; | ||
| targetAgentConversationReplyId: string | null; | ||
| targetMessageId: string | null; | ||
| targetReplyId: string | null; | ||
| targetThreadRootId: string | null; | ||
| }; | ||
|
|
||
| const MAX_ROUTE_ANCESTOR_HOPS = 50; | ||
| const MAX_ROUTE_TASK_EVENTS = 1000; | ||
|
|
||
| async function fetchRouteEvent(eventId: string): Promise<RelayEvent | null> { | ||
| try { | ||
|
|
@@ -42,8 +52,10 @@ function getReplyParentId(event: RelayEvent): string | null { | |
| } | ||
|
|
||
| async function fetchRouteTargetEvents( | ||
| channelId: string, | ||
| eventIds: string[], | ||
| targetMessageId: string | null, | ||
| targetAgentConversationReplyId: string | null, | ||
| targetThreadRootId: string | null, | ||
| ): Promise<RelayEvent[]> { | ||
| const eventsById = new Map<string, RelayEvent>(); | ||
|
|
@@ -67,11 +79,37 @@ async function fetchRouteTargetEvents( | |
| } | ||
|
|
||
| const targetThreadRef = getThreadReference(targetEvent.tags); | ||
| const threadRootId = targetThreadRootId ?? targetThreadRef.rootId ?? null; | ||
| const threadRootId = | ||
| targetThreadRootId ?? | ||
| targetThreadRef.rootId ?? | ||
| (targetAgentConversationReplyId ? targetEvent.id : null); | ||
| if (threadRootId && !eventsById.has(threadRootId)) { | ||
| addEvent(await fetchRouteEvent(threadRootId)); | ||
| } | ||
|
|
||
| if (targetAgentConversationReplyId && threadRootId) { | ||
| try { | ||
| const taskEvents = await relayClient.fetchEvents({ | ||
| "#e": [threadRootId], | ||
| "#h": [channelId], | ||
| kinds: [ | ||
| ...CHANNEL_TIMELINE_CONTENT_KINDS, | ||
| ...CHANNEL_TIMELINE_STATE_KINDS, | ||
| ], | ||
| limit: MAX_ROUTE_TASK_EVENTS, | ||
| }); | ||
| for (const event of taskEvents) { | ||
| addEvent(event); | ||
| } | ||
|
klopez4212 marked this conversation as resolved.
|
||
| } catch (error) { | ||
| console.error( | ||
| "Failed to load route task conversation", | ||
| targetAgentConversationReplyId, | ||
| error, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| let parentId = getReplyParentId(targetEvent); | ||
| let guard = 0; | ||
| while ( | ||
|
|
@@ -93,13 +131,25 @@ async function fetchRouteTargetEvents( | |
| return [...eventsById.values()]; | ||
| } | ||
|
|
||
| function mergeRouteEvents( | ||
| currentEvents: RelayEvent[] | undefined, | ||
| routeEvents: RelayEvent[], | ||
| ): RelayEvent[] { | ||
| return routeEvents.reduce( | ||
| (messages, event) => mergeTimelineCacheMessages(messages, event), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Fresh evidence after the task-backfill fix is that the route-fetched events are seeded through Useful? React with 👍 / 👎. |
||
| currentEvents ?? [], | ||
| ); | ||
| } | ||
|
|
||
| export function ChannelRouteScreen({ | ||
| channelId, | ||
| selectedPostId, | ||
| targetAgentConversationReplyId, | ||
| targetMessageId, | ||
| targetReplyId, | ||
| targetThreadRootId, | ||
| }: ChannelRouteScreenProps) { | ||
| const queryClient = useQueryClient(); | ||
| const { closeForumPost, goForumPost } = useAppNavigation(); | ||
| const channelsQuery = useChannelsQuery(); | ||
| const identityQuery = useIdentityQuery(); | ||
|
|
@@ -140,14 +190,23 @@ export function ChannelRouteScreen({ | |
| // deep-linked message, the spliced event is the only copy — dropping it on | ||
| // param-clear blanks the timeline. Resetting on channel / forum-post change | ||
| // is handled by the effect below; here we only fetch when there's a target. | ||
| if ((!targetMessageId && !targetThreadRootId) || selectedPostId) { | ||
| if ( | ||
| (!targetAgentConversationReplyId && | ||
| !targetMessageId && | ||
| !targetThreadRootId) || | ||
| selectedPostId | ||
| ) { | ||
| return () => { | ||
| isCancelled = true; | ||
| }; | ||
| } | ||
|
|
||
| const cachedTarget = getCachedSearchHitEvent(targetMessageId); | ||
| if (cachedTarget) { | ||
| queryClient.setQueryData<RelayEvent[]>( | ||
| channelMessagesKey(channelId), | ||
| (currentEvents) => mergeRouteEvents(currentEvents, [cachedTarget]), | ||
| ); | ||
| setTargetMessageEvents((currentEvents) => | ||
| currentEvents.some((event) => event.id === cachedTarget.id) | ||
| ? currentEvents | ||
|
|
@@ -156,18 +215,25 @@ export function ChannelRouteScreen({ | |
| } | ||
|
|
||
| const eventIds = [ | ||
| targetAgentConversationReplyId, | ||
|
klopez4212 marked this conversation as resolved.
|
||
| targetMessageId, | ||
| targetThreadRootId && targetThreadRootId !== targetMessageId | ||
| ? targetThreadRootId | ||
| : null, | ||
| ].filter((eventId): eventId is string => eventId !== null); | ||
|
|
||
| void fetchRouteTargetEvents( | ||
| channelId, | ||
| eventIds, | ||
| targetMessageId, | ||
| targetAgentConversationReplyId ?? targetMessageId, | ||
| targetAgentConversationReplyId, | ||
| targetThreadRootId, | ||
| ).then((events) => { | ||
| if (!isCancelled) { | ||
| queryClient.setQueryData<RelayEvent[]>( | ||
| channelMessagesKey(channelId), | ||
| (currentEvents) => mergeRouteEvents(currentEvents, events), | ||
| ); | ||
| setTargetMessageEvents((currentEvents) => { | ||
| const eventsById = new Map<string, RelayEvent>(); | ||
| for (const event of [...currentEvents, ...events]) { | ||
|
|
@@ -181,7 +247,14 @@ export function ChannelRouteScreen({ | |
| return () => { | ||
| isCancelled = true; | ||
| }; | ||
| }, [selectedPostId, targetMessageId, targetThreadRootId]); | ||
| }, [ | ||
| selectedPostId, | ||
| channelId, | ||
| queryClient, | ||
| targetAgentConversationReplyId, | ||
| targetMessageId, | ||
| targetThreadRootId, | ||
| ]); | ||
|
|
||
| if (channelsQuery.isPending && !activeChannel) { | ||
| return ( | ||
|
|
@@ -204,6 +277,7 @@ export function ChannelRouteScreen({ | |
| void goForumPost(channelId, postId); | ||
| }} | ||
| selectedForumPostId={selectedPostId} | ||
| targetAgentConversationReplyId={targetAgentConversationReplyId} | ||
| targetForumReplyId={targetReplyId} | ||
| targetMessageEvents={targetMessageEvents} | ||
| targetMessageId={targetMessageId} | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.