From ad94e927b5a542f9fa6051bffc1eddb56161fcd7 Mon Sep 17 00:00:00 2001 From: Wes Date: Mon, 6 Jul 2026 15:45:13 -0600 Subject: [PATCH] fix(desktop): stop edit-channel dialog hanging on "Saving..." MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dialog only closes after mutateAsync resolves, but React Query also awaits onSettled — which awaited a full ["channels"] list refetch (the expensive get_channels fan-out) before settling. With many channels, or any stalled relay round-trip, the dialog stayed on "Saving..." forever even though the kind:9002 write had already landed. Mirror the #1360 create-channel fix for the remaining blocking paths: - useUpdateChannelMutation: invalidate with refetchType "none" — onSuccess already caches the relay-returned ChannelDetail in both the list and detail queries, so no immediate refetch is needed. - useSetChannelTopicMutation / useSetChannelPurposeMutation: keep the invalidation (these return void, so a refetch is still wanted) but fire-and-forget instead of awaiting it. Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co> Signed-off-by: Wes --- desktop/src/features/channels/hooks.ts | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/desktop/src/features/channels/hooks.ts b/desktop/src/features/channels/hooks.ts index 91e6aebd62f..2c41ff1e741 100644 --- a/desktop/src/features/channels/hooks.ts +++ b/desktop/src/features/channels/hooks.ts @@ -268,8 +268,20 @@ export function useUpdateChannelMutation(channelId: string | null) { ), ); }, - onSettled: async () => { - await invalidateChannelState(queryClient, channelId); + onSettled: () => { + // refetchType "none": onSuccess already cached the relay-returned detail; + // awaiting the full channel-list refetch kept the edit dialog stuck on + // "Saving..." (same failure #1360 fixed for create). + void queryClient.invalidateQueries({ + queryKey: channelsQueryKey, + refetchType: "none", + }); + if (channelId) { + void queryClient.invalidateQueries({ + queryKey: channelDetailQueryKey(channelId), + refetchType: "none", + }); + } }, }); } @@ -285,8 +297,9 @@ export function useSetChannelTopicMutation(channelId: string | null) { return setChannelTopic({ ...input, channelId }); }, - onSettled: async () => { - await invalidateChannelState(queryClient, channelId); + onSettled: () => { + // fire-and-forget: awaiting the channels-list refetch blocks the dialog + void invalidateChannelState(queryClient, channelId); }, }); } @@ -302,8 +315,9 @@ export function useSetChannelPurposeMutation(channelId: string | null) { return setChannelPurpose({ ...input, channelId }); }, - onSettled: async () => { - await invalidateChannelState(queryClient, channelId); + onSettled: () => { + // fire-and-forget: awaiting the channels-list refetch blocks the dialog + void invalidateChannelState(queryClient, channelId); }, }); }