From 03cf6b82106322111ee9c680e889f79ddde17e4c Mon Sep 17 00:00:00 2001 From: npub14vtk7pvazqrq9639qu7e560wnqtl0d53ca4gjuvq6jzf3k2el23qqlwa7f Date: Fri, 12 Jun 2026 15:05:23 -0700 Subject: [PATCH] Gate Follow button behind Pulse feature flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The people-follow graph (kind:3) is only consumed inside Pulse — the Following feed filter. With Pulse off there's nowhere to consume the graph, so the Follow/Unfollow affordance on UserProfilePanel went nowhere meaningful. Gate the action with useFeatureEnabled("pulse"), threading a showFollowAction flag through ProfileSummaryView into ProfilePrimaryActions. When Pulse is disabled the Follow/Unfollow button is hidden entirely; Message and Edit actions are unaffected. Unrelated thread-following (features/messages, localStorage-backed) is deliberately left untouched. Co-authored-by: tho <80c5f18be5aafa62cf6198c6335963ba3306b595288117c8ea2f805fc9bdc94a@sprout-oss.stage.blox.sqprod.co> Signed-off-by: tho <80c5f18be5aafa62cf6198c6335963ba3306b595288117c8ea2f805fc9bdc94a@sprout-oss.stage.blox.sqprod.co> --- .../features/profile/ui/UserProfilePanel.tsx | 8 +++ .../profile/ui/UserProfilePanelSections.tsx | 67 ++++++++++--------- 2 files changed, 45 insertions(+), 30 deletions(-) diff --git a/desktop/src/features/profile/ui/UserProfilePanel.tsx b/desktop/src/features/profile/ui/UserProfilePanel.tsx index ba65d4559..6ad8ee50a 100644 --- a/desktop/src/features/profile/ui/UserProfilePanel.tsx +++ b/desktop/src/features/profile/ui/UserProfilePanel.tsx @@ -14,6 +14,7 @@ import { import { EditAgentDialog } from "@/features/agents/ui/EditAgentDialog"; import { useChannelsQuery } from "@/features/channels/hooks"; import { usePresenceQuery } from "@/features/presence/hooks"; +import { useFeatureEnabled } from "@/shared/features"; import { useContactListQuery, useFollowMutation, @@ -183,6 +184,12 @@ export function UserProfilePanel({ const isSelf = currentPubkey !== undefined && pubkeyLower === currentPubkey.toLowerCase(); const canViewActivity = isOwner === true && Boolean(onOpenAgentSession); + // The people-follow graph (kind:3) is only surfaced for consumption inside + // Pulse. When Pulse is off there's nowhere to consume the graph, so we hide + // the Follow affordance entirely rather than let users write follows that go + // nowhere. (Thread-following in features/messages is unrelated localStorage + // state and is not gated here.) + const showFollowAction = useFeatureEnabled("pulse"); const isFollowing = !isSelf && (contactListQuery.data?.contacts.some( @@ -320,6 +327,7 @@ export function UserProfilePanel({ profile={profile} pubkey={pubkey} relayAgent={relayAgent} + showFollowAction={showFollowAction} unfollowMutation={unfollowMutation} userStatus={userStatus} /> diff --git a/desktop/src/features/profile/ui/UserProfilePanelSections.tsx b/desktop/src/features/profile/ui/UserProfilePanelSections.tsx index 05a97e82f..1043bb3a4 100644 --- a/desktop/src/features/profile/ui/UserProfilePanelSections.tsx +++ b/desktop/src/features/profile/ui/UserProfilePanelSections.tsx @@ -82,6 +82,7 @@ export type ProfileSummaryViewProps = { profile: ReturnType["data"]; pubkey: string; relayAgent: RelayAgent | undefined; + showFollowAction: boolean; unfollowMutation: ReturnType; userStatus: { text: string; emoji: string } | null | undefined; }; @@ -113,6 +114,7 @@ export function ProfileSummaryView({ profile, pubkey, relayAgent, + showFollowAction, unfollowMutation, userStatus, }: ProfileSummaryViewProps) { @@ -157,6 +159,7 @@ export function ProfileSummaryView({ isFollowing={isFollowing} onMessage={onOpenDm ? handleMessage : undefined} pubkey={pubkey} + showFollowAction={showFollowAction} unfollowMutation={unfollowMutation} /> ) : null} @@ -372,6 +375,7 @@ function ProfilePrimaryActions({ onEditAgent, onMessage, pubkey, + showFollowAction, unfollowMutation, }: { canEditAgent: boolean; @@ -380,40 +384,43 @@ function ProfilePrimaryActions({ onEditAgent: () => void; onMessage?: () => void; pubkey: string; + showFollowAction: boolean; unfollowMutation: ReturnType; }) { return (
- {isFollowing ? ( - - unfollowMutation.mutate(pubkey, { - onError: (error) => - toast.error( - `Unfollow failed: ${error instanceof Error ? error.message : String(error)}`, - ), - }) - } - /> - ) : ( - - followMutation.mutate(pubkey, { - onError: (error) => - toast.error( - `Follow failed: ${error instanceof Error ? error.message : String(error)}`, - ), - }) - } - /> - )} + {showFollowAction ? ( + isFollowing ? ( + + unfollowMutation.mutate(pubkey, { + onError: (error) => + toast.error( + `Unfollow failed: ${error instanceof Error ? error.message : String(error)}`, + ), + }) + } + /> + ) : ( + + followMutation.mutate(pubkey, { + onError: (error) => + toast.error( + `Follow failed: ${error instanceof Error ? error.message : String(error)}`, + ), + }) + } + /> + ) + ) : null} {onMessage ? (