From c65fd6e2b07de4843a692d0336bdd1be45449761 Mon Sep 17 00:00:00 2001 From: Taylor Ho Date: Thu, 21 May 2026 19:54:51 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20optimistic=20remove=20=E2=80=94=20agent?= =?UTF-8?q?=20vanishes=20instantly=20from=20sidebar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirror of the attach optimistic update. onMutate filters the member out of the cache immediately, rolls back on error, invalidates on settle to reconcile with server. --- desktop/src/features/channels/hooks.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/desktop/src/features/channels/hooks.ts b/desktop/src/features/channels/hooks.ts index dab02e486f..a81d05d243 100644 --- a/desktop/src/features/channels/hooks.ts +++ b/desktop/src/features/channels/hooks.ts @@ -29,12 +29,14 @@ import type { AddChannelMembersInput, Channel, ChannelDetail, + ChannelMember, CreateChannelInput, OpenDmInput, SetChannelPurposeInput, SetChannelTopicInput, UpdateChannelInput, } from "@/shared/api/types"; +import { normalizePubkey } from "@/shared/lib/pubkey"; export const channelsQueryKey = ["channels"] as const; const channelDetailQueryKey = (channelId: string) => @@ -410,6 +412,25 @@ export function useRemoveChannelMemberMutation(channelId: string | null) { await removeChannelMemberWithManagedAgentCleanup(channelId, pubkey); }, + onMutate: async (pubkey) => { + if (!channelId) return; + const membersKey = channelMembersQueryKey(channelId); + await queryClient.cancelQueries({ queryKey: membersKey }); + const previous = + queryClient.getQueryData(membersKey) ?? []; + queryClient.setQueryData( + membersKey, + previous.filter( + (m) => normalizePubkey(m.pubkey) !== normalizePubkey(pubkey), + ), + ); + return { previous, membersKey }; + }, + onError: (_err, _vars, context) => { + if (context?.membersKey) { + queryClient.setQueryData(context.membersKey, context.previous); + } + }, onSettled: async () => { await Promise.all([ invalidateChannelState(queryClient, channelId),