From f1a05a38d0649d9fa83f8f37d22f33ad3b850e2f Mon Sep 17 00:00:00 2001 From: Clay Delk Date: Mon, 20 Jul 2026 14:18:26 -0400 Subject: [PATCH 1/2] feat(desktop): polish system message and toast copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sweep the desktop toast surface for a consistent voice: - error toasts use "Couldn't …" instead of "Failed to …" (git/PR service toasts keep "Failed" as more accurate for that surface) - drop terminal periods on single-clause toasts; keep them only on multi-sentence messages - name the member in relay promote/demote/remove confirmations - archive toasts say "in this community" instead of "on this relay" - clearer copy for repos-directory, DM agent-mention, storage-full, and stop-turn toasts - "added by" (not "was added by") in membership rows, fixing the "You was added by" grammar bug - template apply names the agents that failed; member timeout echoes the chosen duration error.message/err.message branches are preserved throughout; only fallback literals changed. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../agents/ui/AgentInstanceEditDialog.tsx | 6 +-- .../features/agents/useOpenAgentActivity.ts | 2 +- .../channel-templates/useApplyTemplate.ts | 17 ++++++-- .../channels/ui/AgentSessionThreadPanel.tsx | 6 +-- .../channels/ui/MembersSidebarMemberCard.tsx | 13 +++++- .../ui/useMembersSidebarModeration.ts | 8 ++-- desktop/src/features/chat/ui/ChatHeader.tsx | 2 +- .../ui/CommunityIconSettingsCard.tsx | 6 +-- .../communities/useNestNotifications.ts | 2 +- .../ui/CommunityMembersCard.tsx | 2 +- .../ui/CommunityMembersSettingsCard.tsx | 16 +++---- .../ui/ConfirmRemoveDialog.tsx | 2 +- .../ui/CustomEmojiSettingsCard.tsx | 10 ++--- .../huddle/components/HuddleAttachment.tsx | 2 +- .../src/features/identity-archive/hooks.ts | 8 ++-- .../ui/LocalArchiveSettingsCard.tsx | 22 +++++----- desktop/src/features/messages/hooks.ts | 2 +- .../features/messages/ui/SystemMessageRow.tsx | 4 +- .../messages/ui/WaveMessageAttachment.tsx | 2 +- .../messages/ui/useMentionSendFlow.ts | 10 ++--- .../ui/MessageModerationMenuItems.tsx | 4 +- .../moderation/ui/ReportMessageDialog.tsx | 2 +- .../features/onboarding/ui/ProfileStep.tsx | 2 +- .../features/profile/ui/UserProfilePanel.tsx | 42 ++++++++++--------- .../ui/UserProfilePanelPersonaSubmit.ts | 12 +++--- .../profile/ui/UserProfilePanelSections.tsx | 2 +- .../profile/ui/UserProfilePopover.tsx | 8 ++-- .../ui/UserProfileSnapshotExportDialog.tsx | 4 +- .../features/profile/ui/useProfileDmAction.ts | 4 +- .../projects/ui/CreateProjectIssueDialog.tsx | 2 +- .../projects/ui/CreatePullRequestDialog.tsx | 2 +- .../projects/ui/MergePullRequestButton.tsx | 12 +++--- .../projects/ui/ProjectDetailScreen.tsx | 8 ++-- .../projects/ui/ProjectIssuesPanel.tsx | 4 +- .../ProjectPullRequestFilesChangedPanel.tsx | 4 +- .../projects/ui/ProjectPullRequestsPanel.tsx | 4 +- .../projects/ui/ProjectsAgentPromptPage.tsx | 2 +- .../src/features/projects/ui/ProjectsView.tsx | 2 +- .../projects/ui/PullRequestReviewCard.tsx | 14 +++---- .../projects/ui/PullRequestReviewersRow.tsx | 4 +- .../projects/ui/useOpenProjectTerminal.ts | 2 +- .../src/features/pulse/lib/useNoteActions.ts | 8 ++-- .../reminders/ui/RemindMeLaterDialog.tsx | 2 +- .../features/reminders/ui/RemindersPanel.tsx | 6 +-- .../ui/ChannelTemplatesSettingsCard.tsx | 10 ++--- .../settings/ui/ModerationQueueCard.tsx | 2 +- .../settings/ui/ProfileSettingsCard.tsx | 2 +- desktop/src/shared/lib/clipboard.ts | 2 +- desktop/src/shared/lib/localStorageQuota.ts | 4 +- desktop/src/shared/ui/markdown.tsx | 6 +-- desktop/src/shared/ui/markdown/CodeBlock.tsx | 2 +- desktop/src/shared/ui/markdown/FileCard.tsx | 3 +- desktop/src/shared/ui/useVideoContextMenu.tsx | 4 +- 53 files changed, 173 insertions(+), 160 deletions(-) diff --git a/desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx b/desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx index 8be5f4719b..55e63a8b8f 100644 --- a/desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx +++ b/desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx @@ -737,7 +737,7 @@ export function AgentInstanceEditDialog({ // explicitly instead of relying on the user to know the policy. if (!isManagedAgentActive(result.agent)) { const startedName = result.agent.name; - toast(`${startedName} saved while stopped.`, { + toast(`Changes saved. ${startedName} is still stopped.`, { action: { label: "Start now", onClick: () => { @@ -746,8 +746,8 @@ export function AgentInstanceEditDialog({ onError: (error) => toast.error( error instanceof Error - ? `${startedName} failed to start: ${error.message}` - : `${startedName} failed to start.`, + ? `Couldn't start ${startedName}: ${error.message}` + : `Couldn't start ${startedName}`, ), }); }, diff --git a/desktop/src/features/agents/useOpenAgentActivity.ts b/desktop/src/features/agents/useOpenAgentActivity.ts index e8cfc0e8ff..90e2dc3286 100644 --- a/desktop/src/features/agents/useOpenAgentActivity.ts +++ b/desktop/src/features/agents/useOpenAgentActivity.ts @@ -10,7 +10,7 @@ import { getAgentWorkingState } from "./agentWorkingSignal"; import { useRelayAgentsQuery } from "./hooks"; const INACCESSIBLE_ACTIVITY_MESSAGE = - "This agent is active in a channel you haven't joined, so its activity can't be opened from here."; + "Can't open activity. It's in a channel you haven't joined."; /** * Can the viewer actually open this channel? Joined channels always; diff --git a/desktop/src/features/channel-templates/useApplyTemplate.ts b/desktop/src/features/channel-templates/useApplyTemplate.ts index 1f7d066fad..326cf15cca 100644 --- a/desktop/src/features/channel-templates/useApplyTemplate.ts +++ b/desktop/src/features/channel-templates/useApplyTemplate.ts @@ -16,6 +16,18 @@ import { useChannelTemplatesQuery } from "@/features/channel-templates/hooks"; import { setCanvas } from "@/shared/api/tauri"; import type { ChannelTemplate } from "@/shared/api/types"; +/** + * Format a list of failed agent names for a warning toast: up to three names + * are listed in full, then it falls back to "and N others" to keep the toast + * short. Mirrors the typing-indicator convention in TypingIndicatorRow. + */ +function formatFailedAgentNames(names: readonly string[]): string { + if (names.length === 1) return names[0]; + if (names.length === 2) return `${names[0]} and ${names[1]}`; + if (names.length === 3) return `${names[0]}, ${names[1]}, and ${names[2]}`; + return `${names[0]}, ${names[1]}, and ${names.length - 2} others`; +} + /** * TemplateBackend omits `config` — supply an empty object for provider backends. */ @@ -135,10 +147,9 @@ export function useApplyTemplate() { const result = await createChannelManagedAgents(channelId, inputs); if (result.failures.length > 0) { const { toast } = await import("sonner"); + const failedNames = result.failures.map((failure) => failure.name); toast.warning( - result.failures.length === 1 - ? "1 agent from the template could not be created" - : `${result.failures.length} agents from the template could not be created`, + `Couldn't add ${formatFailedAgentNames(failedNames)} from the template`, ); } await Promise.all([ diff --git a/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx b/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx index a907f87245..64ac2cf6ae 100644 --- a/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx +++ b/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx @@ -246,14 +246,12 @@ export function AgentSessionThreadPanel({ try { await cancelManagedAgentTurn(agent.pubkey, channel.id); - toast.success( - `Stop signal sent to ${agent.name}. It may take a moment to respond.`, - ); + toast.success(`Stopping ${agent.name}'s turn. This may take a moment.`); } catch (error) { toast.error( error instanceof Error ? error.message - : `Failed to stop ${agent.name}'s current turn.`, + : `Couldn't stop ${agent.name}'s current turn`, ); } } diff --git a/desktop/src/features/channels/ui/MembersSidebarMemberCard.tsx b/desktop/src/features/channels/ui/MembersSidebarMemberCard.tsx index 8234517432..2a5055406b 100644 --- a/desktop/src/features/channels/ui/MembersSidebarMemberCard.tsx +++ b/desktop/src/features/channels/ui/MembersSidebarMemberCard.tsx @@ -56,7 +56,11 @@ type MembersSidebarMemberCardProps = { onManagedAgentAction: (agent: ManagedAgent) => void; onOpenProfile?: (pubkey: string) => void; onRemoveMember: (member: ChannelMember) => void; - onTimeout: (member: ChannelMember, expiresAtSecs: number) => void; + onTimeout: ( + member: ChannelMember, + expiresAtSecs: number, + durationLabel: string, + ) => void; onUnban: (member: ChannelMember) => void; onUntimeout: (member: ChannelMember) => void; onViewActivity?: (pubkey: string) => void; @@ -307,7 +311,11 @@ function MemberActionsMenu({ onEditRespondTo?: (agent: ManagedAgent) => void; onManagedAgentAction: (agent: ManagedAgent) => void; onRemoveMember: (member: ChannelMember) => void; - onTimeout: (member: ChannelMember, expiresAtSecs: number) => void; + onTimeout: ( + member: ChannelMember, + expiresAtSecs: number, + durationLabel: string, + ) => void; onUnban: (member: ChannelMember) => void; onUntimeout: (member: ChannelMember) => void; onViewActivity?: (pubkey: string) => void; @@ -439,6 +447,7 @@ function MemberActionsMenu({ onTimeout( member, Math.floor(Date.now() / 1000) + preset.seconds, + preset.label, ) } > diff --git a/desktop/src/features/channels/ui/useMembersSidebarModeration.ts b/desktop/src/features/channels/ui/useMembersSidebarModeration.ts index 04c4f1a70b..8ee2e6e408 100644 --- a/desktop/src/features/channels/ui/useMembersSidebarModeration.ts +++ b/desktop/src/features/channels/ui/useMembersSidebarModeration.ts @@ -55,7 +55,9 @@ export function useMembersSidebarModeration(open: boolean) { toast.success(success); } catch (error) { toast.error( - error instanceof Error ? error.message : "Moderation action failed", + error instanceof Error + ? error.message + : "Couldn't complete that action", ); } }, @@ -81,14 +83,14 @@ export function useMembersSidebarModeration(open: boolean) { ); const onTimeout = React.useCallback( - (member: ChannelMember, expiresAtSecs: number) => + (member: ChannelMember, expiresAtSecs: number, durationLabel: string) => void runModerationAction( () => timeoutMutation.mutateAsync({ pubkey: member.pubkey, expiresAt: expiresAtSecs, }), - "Member timed out", + `Member timed out for ${durationLabel}`, ), [timeoutMutation, runModerationAction], ); diff --git a/desktop/src/features/chat/ui/ChatHeader.tsx b/desktop/src/features/chat/ui/ChatHeader.tsx index 9ced506751..d9924a1017 100644 --- a/desktop/src/features/chat/ui/ChatHeader.tsx +++ b/desktop/src/features/chat/ui/ChatHeader.tsx @@ -108,7 +108,7 @@ export function ChatHeader({ await writeTextToClipboard(value); toast.success("Channel name copied"); } catch { - toast.error("Failed to copy channel name"); + toast.error("Couldn't copy channel name"); } } diff --git a/desktop/src/features/communities/ui/CommunityIconSettingsCard.tsx b/desktop/src/features/communities/ui/CommunityIconSettingsCard.tsx index 4f557fd8a3..ed757ec75d 100644 --- a/desktop/src/features/communities/ui/CommunityIconSettingsCard.tsx +++ b/desktop/src/features/communities/ui/CommunityIconSettingsCard.tsx @@ -42,7 +42,7 @@ export function CommunityIconSettingsCard() { async function handleFile(file: File) { if (!ICON_IMAGE_TYPES.includes(file.type)) { - toast.error("Choose a PNG, JPG, GIF, or WebP image."); + toast.error("Choose a PNG, JPG, GIF, or WebP image"); return; } try { @@ -53,7 +53,7 @@ export function CommunityIconSettingsCard() { toast.error( error instanceof Error ? error.message - : "Failed to update the community icon.", + : "Couldn't update the community icon", ); } } @@ -66,7 +66,7 @@ export function CommunityIconSettingsCard() { toast.error( error instanceof Error ? error.message - : "Failed to remove the community icon.", + : "Couldn't remove the community icon", ); } } diff --git a/desktop/src/features/communities/useNestNotifications.ts b/desktop/src/features/communities/useNestNotifications.ts index d93bb89ad2..aa617ba3cc 100644 --- a/desktop/src/features/communities/useNestNotifications.ts +++ b/desktop/src/features/communities/useNestNotifications.ts @@ -23,7 +23,7 @@ const MIGRATION_TOAST_KEY = "buzz-legacy-nest-migrated-notified"; export function useNestNotifications(): void { useEffect(() => { const unlistenReposError = listen("repos-dir-error", (event) => { - toast.error("Repos directory not applied", { + toast.error("Couldn't apply the repos directory", { description: event.payload, }); }); diff --git a/desktop/src/features/community-members/ui/CommunityMembersCard.tsx b/desktop/src/features/community-members/ui/CommunityMembersCard.tsx index fdc75f3d18..57c3b340fe 100644 --- a/desktop/src/features/community-members/ui/CommunityMembersCard.tsx +++ b/desktop/src/features/community-members/ui/CommunityMembersCard.tsx @@ -205,7 +205,7 @@ export function CommunityMembersCard({ }, onError: (error) => { toast.error( - error instanceof Error ? error.message : "Failed to change role", + error instanceof Error ? error.message : "Couldn't change role", ); }, }, diff --git a/desktop/src/features/community-members/ui/CommunityMembersSettingsCard.tsx b/desktop/src/features/community-members/ui/CommunityMembersSettingsCard.tsx index 4572ad0017..632131e1cf 100644 --- a/desktop/src/features/community-members/ui/CommunityMembersSettingsCard.tsx +++ b/desktop/src/features/community-members/ui/CommunityMembersSettingsCard.tsx @@ -146,9 +146,7 @@ function RelayMemberRow({ toast.success(success); } catch (error) { toast.error( - error instanceof Error - ? error.message - : "Community membership update failed", + error instanceof Error ? error.message : "Couldn't update membership", ); } } @@ -196,7 +194,7 @@ function RelayMemberRow({ pubkey: member.pubkey, role: "admin", }), - "Promoted relay admin", + `Promoted ${displayName} to admin`, ) } size="icon" @@ -218,7 +216,7 @@ function RelayMemberRow({ pubkey: member.pubkey, role: "member", }), - "Demoted to relay member", + `Demoted ${displayName} to member`, ) } size="icon" @@ -237,7 +235,7 @@ function RelayMemberRow({ onClick={() => void mutateWithToast( () => removeMutation.mutateAsync(member.pubkey), - "Removed relay member", + `Removed ${displayName} from the community`, ) } size="icon" @@ -339,14 +337,12 @@ export function CommunityMembersSettingsCard({ if (!canAdd) return; try { await addMutation.mutateAsync({ pubkey: normalizedInput, role }); - toast.success( - role === "admin" ? "Added relay admin" : "Added relay member", - ); + toast.success(role === "admin" ? "Added as admin" : "Added as member"); setPubkeyInput(""); setRole("member"); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to add relay member", + error instanceof Error ? error.message : "Couldn't add member", ); } } diff --git a/desktop/src/features/community-members/ui/ConfirmRemoveDialog.tsx b/desktop/src/features/community-members/ui/ConfirmRemoveDialog.tsx index 64735a5d56..007a1635e6 100644 --- a/desktop/src/features/community-members/ui/ConfirmRemoveDialog.tsx +++ b/desktop/src/features/community-members/ui/ConfirmRemoveDialog.tsx @@ -75,7 +75,7 @@ export function ConfirmRemoveDialog({ toast.error( error instanceof Error ? error.message - : "Failed to remove member", + : "Couldn't remove member", ); }, }); diff --git a/desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx b/desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx index 4e189a7953..4b52826ea5 100644 --- a/desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx +++ b/desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx @@ -62,7 +62,7 @@ export function CustomEmojiSettingsCard() { return; } if (!blob.type.startsWith("image/")) { - toast.error("Choose an image file for custom emoji."); + toast.error("Choose an image file for custom emoji"); return; } setPendingUpload({ url: blob.url, filename: blob.filename ?? null }); @@ -74,9 +74,7 @@ export function CustomEmojiSettingsCard() { } } catch (error) { toast.error( - error instanceof Error - ? error.message - : "Failed to upload emoji image.", + error instanceof Error ? error.message : "Couldn't upload emoji image", ); } finally { setIsUploading(false); @@ -95,7 +93,7 @@ export function CustomEmojiSettingsCard() { toast.success(`Added :${stored}:`); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to add emoji.", + error instanceof Error ? error.message : "Couldn't add emoji", ); } }, [normalized, pendingUpload, setEmoji]); @@ -112,7 +110,7 @@ export function CustomEmojiSettingsCard() { toast.success(`Removed :${shortcode}:`); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to remove emoji.", + error instanceof Error ? error.message : "Couldn't remove emoji", ); } }, diff --git a/desktop/src/features/huddle/components/HuddleAttachment.tsx b/desktop/src/features/huddle/components/HuddleAttachment.tsx index 80e446f798..aa1aa1a979 100644 --- a/desktop/src/features/huddle/components/HuddleAttachment.tsx +++ b/desktop/src/features/huddle/components/HuddleAttachment.tsx @@ -222,7 +222,7 @@ export function HuddleAttachment({ void queryClient.invalidateQueries({ queryKey: ["channels"] }); } catch (error) { const message = - error instanceof Error ? error.message : "Failed to join huddle"; + error instanceof Error ? error.message : "Couldn't join the huddle"; toast.error(message); } finally { setIsJoining(false); diff --git a/desktop/src/features/identity-archive/hooks.ts b/desktop/src/features/identity-archive/hooks.ts index 8149eff7b7..6b5bad0d09 100644 --- a/desktop/src/features/identity-archive/hooks.ts +++ b/desktop/src/features/identity-archive/hooks.ts @@ -153,10 +153,10 @@ export function useIdentityArchive( archiveMutation.mutate( { targetPubkey }, { - onSuccess: () => toast.success("Archived on this relay"), + onSuccess: () => toast.success("Archived in this community"), onError: (error) => toast.error( - `Archive failed: ${error instanceof Error ? error.message : String(error)}`, + `Couldn't archive: ${error instanceof Error ? error.message : String(error)}`, ), }, ); @@ -167,10 +167,10 @@ export function useIdentityArchive( unarchiveMutation.mutate( { targetPubkey }, { - onSuccess: () => toast.success("Unarchived on this relay"), + onSuccess: () => toast.success("Unarchived in this community"), onError: (error) => toast.error( - `Unarchive failed: ${error instanceof Error ? error.message : String(error)}`, + `Couldn't unarchive: ${error instanceof Error ? error.message : String(error)}`, ), }, ); diff --git a/desktop/src/features/local-archive/ui/LocalArchiveSettingsCard.tsx b/desktop/src/features/local-archive/ui/LocalArchiveSettingsCard.tsx index fbf8c506eb..a9e7ed94a4 100644 --- a/desktop/src/features/local-archive/ui/LocalArchiveSettingsCard.tsx +++ b/desktop/src/features/local-archive/ui/LocalArchiveSettingsCard.tsx @@ -302,10 +302,10 @@ function AddSubscriptionForm({ channels, onSaved, onCancel }: AddFormProps) { request.kinds, ); onSaved(); - toast.success("Archive subscription created."); + toast.success("Archive subscription created"); } catch (err) { toast.error( - err instanceof Error ? err.message : "Failed to create subscription.", + err instanceof Error ? err.message : "Couldn't create the subscription", ); } finally { setIsAdding(false); @@ -441,10 +441,12 @@ export function LocalArchiveSettingsCard() { try { await deleteSaveSubscription(scopeType, scopeValue); await reload(); - toast.success("Archive subscription removed."); + toast.success("Archive subscription removed"); } catch (err) { toast.error( - err instanceof Error ? err.message : "Failed to remove subscription.", + err instanceof Error + ? err.message + : "Couldn't remove the subscription", ); } finally { setDeletingKey(null); @@ -475,15 +477,15 @@ export function LocalArchiveSettingsCard() { } toast.success( checked - ? "Observer feed archive enabled." - : "Observer feed archive disabled.", + ? "Observer feed archive enabled" + : "Observer feed archive disabled", ); await reload(); } catch (err) { toast.error( err instanceof Error ? err.message - : "Failed to update observer archive.", + : "Couldn't update the observer archive", ); } finally { setObserverToggling(false); @@ -505,15 +507,15 @@ export function LocalArchiveSettingsCard() { setExplicitAgentMetricArchiveChoice(pubkey, checked); toast.success( checked - ? "Agent turn metric archive enabled." - : "Agent turn metric archive disabled.", + ? "Agent turn metric archive enabled" + : "Agent turn metric archive disabled", ); await reload(); } catch (err) { toast.error( err instanceof Error ? err.message - : "Failed to update agent metric archive.", + : "Couldn't update the agent metric archive", ); } finally { setMetricToggling(false); diff --git a/desktop/src/features/messages/hooks.ts b/desktop/src/features/messages/hooks.ts index 3d34d07d1f..7d72306c04 100644 --- a/desktop/src/features/messages/hooks.ts +++ b/desktop/src/features/messages/hooks.ts @@ -670,7 +670,7 @@ export function useDeleteMessageMutation(channel: Channel | null) { ); }, onError: (error) => { - toast.error(`Failed to delete message: ${error.message}`); + toast.error(`Couldn't delete message: ${error.message}`); }, }); } diff --git a/desktop/src/features/messages/ui/SystemMessageRow.tsx b/desktop/src/features/messages/ui/SystemMessageRow.tsx index 4410964dd9..0fbb9508d3 100644 --- a/desktop/src/features/messages/ui/SystemMessageRow.tsx +++ b/desktop/src/features/messages/ui/SystemMessageRow.tsx @@ -522,7 +522,7 @@ function describeSystemEvent( title: membershipTitle, action: ( <> - was added by{" "} + added by{" "} {resolveDisplayLabel(payload.actor, currentPubkey, profiles)} @@ -566,7 +566,7 @@ function describeSystemEvent( title: membershipTitle, action: ( <> - was added by{" "} + added by{" "} {resolveDisplayLabel(payload.actor, currentPubkey, profiles)} diff --git a/desktop/src/features/messages/ui/WaveMessageAttachment.tsx b/desktop/src/features/messages/ui/WaveMessageAttachment.tsx index 0012d0b140..481edc8de8 100644 --- a/desktop/src/features/messages/ui/WaveMessageAttachment.tsx +++ b/desktop/src/features/messages/ui/WaveMessageAttachment.tsx @@ -46,7 +46,7 @@ export function WaveMessageAttachment({ await queryClient.invalidateQueries({ queryKey: channelsQueryKey }); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to start huddle.", + error instanceof Error ? error.message : "Couldn't start the huddle", ); } }, diff --git a/desktop/src/features/messages/ui/useMentionSendFlow.ts b/desktop/src/features/messages/ui/useMentionSendFlow.ts index 6d4e007cd4..84e2797be2 100644 --- a/desktop/src/features/messages/ui/useMentionSendFlow.ts +++ b/desktop/src/features/messages/ui/useMentionSendFlow.ts @@ -142,7 +142,7 @@ function isProviderBackedAgent(agent: ManagedAgent) { } const DM_THREAD_AGENT_MENTION_ERROR = - "Agents must already be in a DM to be mentioned in its threads. Start a new conversation that includes the agent."; + "You can only mention agents already in this DM. Start a new conversation to add them."; const DM_THREAD_MEMBERS_LOADING_ERROR = "Checking conversation members. Try again in a moment."; @@ -490,8 +490,8 @@ export function useMentionSendFlow({ if (agentReadiness.errors.length > 0) { const message = agentReadiness.errors.length === 1 - ? `Could not start agent mention: ${agentReadiness.errors[0]}` - : `Could not start agent mentions: ${agentReadiness.errors.join( + ? `Couldn't start agent mention: ${agentReadiness.errors[0]}` + : `Couldn't start agent mentions: ${agentReadiness.errors.join( "; ", )}`; setNonMemberPromptError(message); @@ -680,8 +680,8 @@ export function useMentionSendFlow({ if (personaMentionResult.errors.length > 0) { const message = personaMentionResult.errors.length === 1 - ? `Could not create agent mention: ${personaMentionResult.errors[0]}` - : `Could not create agent mentions: ${personaMentionResult.errors.join( + ? `Couldn't create agent mention: ${personaMentionResult.errors[0]}` + : `Couldn't create agent mentions: ${personaMentionResult.errors.join( "; ", )}`; setNonMemberPromptError(message); diff --git a/desktop/src/features/moderation/ui/MessageModerationMenuItems.tsx b/desktop/src/features/moderation/ui/MessageModerationMenuItems.tsx index e61f63b687..c4f89629c2 100644 --- a/desktop/src/features/moderation/ui/MessageModerationMenuItems.tsx +++ b/desktop/src/features/moderation/ui/MessageModerationMenuItems.tsx @@ -94,7 +94,9 @@ export function MessageModerationMenuItems({ toast.success(success); } catch (error) { toast.error( - error instanceof Error ? error.message : "Moderation action failed", + error instanceof Error + ? error.message + : "Couldn't complete that action", ); } }, diff --git a/desktop/src/features/moderation/ui/ReportMessageDialog.tsx b/desktop/src/features/moderation/ui/ReportMessageDialog.tsx index 1cbc71c90d..ceb8dfebd6 100644 --- a/desktop/src/features/moderation/ui/ReportMessageDialog.tsx +++ b/desktop/src/features/moderation/ui/ReportMessageDialog.tsx @@ -67,7 +67,7 @@ export function ReportMessageDialog({ toast.success("Report submitted to community moderators"); onOpenChange(false); }, - onError: () => toast.error("Failed to submit report"), + onError: () => toast.error("Couldn't submit report"), }, ); }; diff --git a/desktop/src/features/onboarding/ui/ProfileStep.tsx b/desktop/src/features/onboarding/ui/ProfileStep.tsx index 69da9b8f7c..6158c83fb2 100644 --- a/desktop/src/features/onboarding/ui/ProfileStep.tsx +++ b/desktop/src/features/onboarding/ui/ProfileStep.tsx @@ -123,7 +123,7 @@ function OnboardingRelayConnectionErrorCard({ .catch((error) => { hadActiveReconnectRef.current = false; const detail = error instanceof Error ? error.message : String(error); - toast.error(`Could not reconnect to the relay. ${detail}`); + toast.error(`Couldn't reconnect to the relay. ${detail}`); }) .finally(() => { reconnectActionPendingRef.current = false; diff --git a/desktop/src/features/profile/ui/UserProfilePanel.tsx b/desktop/src/features/profile/ui/UserProfilePanel.tsx index 09e8d51487..cbba282db9 100644 --- a/desktop/src/features/profile/ui/UserProfilePanel.tsx +++ b/desktop/src/features/profile/ui/UserProfilePanel.tsx @@ -462,7 +462,7 @@ export function UserProfilePanel({ relayAgents: relayAgentsQuery.data ?? [], stopManagedAgent: stopAgentMutation.mutateAsync, }); - toast.success(result.noticeMessage ?? `Stopped ${managedAgent.name}.`); + toast.success(result.noticeMessage ?? `Stopped ${managedAgent.name}`); return; } @@ -472,12 +472,14 @@ export function UserProfilePanel({ }); toast.success( managedAgent.backend.type === "provider" - ? `Deploying ${managedAgent.name}.` - : `Started ${managedAgent.name}.`, + ? `Deploying ${managedAgent.name}` + : `Started ${managedAgent.name}`, ); } catch (error) { toast.error( - error instanceof Error ? error.message : "Agent action failed.", + error instanceof Error + ? error.message + : "Couldn't complete that action", ); } }, [ @@ -496,14 +498,14 @@ export function UserProfilePanel({ if (created.spawnError) { toast.error(created.spawnError); } else { - toast.success(`Started ${created.agent.name}.`); + toast.success(`Started ${created.agent.name}`); } if (created.profileSyncError) { toast.warning(created.profileSyncError); } } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to start agent.", + error instanceof Error ? error.message : "Couldn't start the agent", ); } }, [createManagedAgentForPersona, resolvedPersona]); @@ -518,14 +520,14 @@ export function UserProfilePanel({ }); toast.success( updated.startOnAppLaunch - ? `Will start ${updated.name} automatically.` - : `${updated.name} will stay manual-start only.`, + ? `Will start ${updated.name} automatically` + : `${updated.name} will stay manual-start only`, ); } catch (error) { toast.error( error instanceof Error ? error.message - : "Failed to update startup preference.", + : "Couldn't update the startup preference", ); } }, [managedAgent, startOnLaunchMutation.mutateAsync]); @@ -537,11 +539,11 @@ export function UserProfilePanel({ const result = await deleteManagedAgentRecord(managedAgent); if (result.cancelled) return; - toast.success(`Deleted ${managedAgent.name}.`); + toast.success(`Deleted ${managedAgent.name}`); onClose(); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to delete agent.", + error instanceof Error ? error.message : "Couldn't delete agent", ); } }, [deleteManagedAgentRecord, managedAgent, onClose]); @@ -604,18 +606,18 @@ export function UserProfilePanel({ id: resolvedPersona.id, active: false, }); - toast.success(`Removed ${resolvedPersona.displayName} from My Agents.`); + toast.success(`Removed ${resolvedPersona.displayName} from My Agents`); onClose(); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to delete agent.", + error instanceof Error ? error.message : "Couldn't delete agent", ); } return; } if (resolvedPersona.sourceTeam) { - toast.error("This agent is managed by a team."); + toast.error("This agent is managed by a team"); return; } @@ -630,19 +632,19 @@ export function UserProfilePanel({ const handleConfirmDeletePersona = React.useCallback( async (personaToConfirm: AgentPersona) => { if (personaToConfirm.sourceTeam) { - toast.error("This agent is managed by a team."); + toast.error("This agent is managed by a team"); setPersonaToDelete(null); return; } try { await deletePersonaMutation.mutateAsync(personaToConfirm.id); - toast.success(`Deleted ${personaToConfirm.displayName}.`); + toast.success(`Deleted ${personaToConfirm.displayName}`); setPersonaToDelete(null); onClose(); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to delete agent.", + error instanceof Error ? error.message : "Couldn't delete agent", ); } }, @@ -664,11 +666,11 @@ export function UserProfilePanel({ const handleAddedToChannel = React.useCallback( (channel: Channel, result: AttachManagedAgentToChannelResult) => { if (result.started) { - toast.success(`Added ${result.agent.name} to ${channel.name}.`); + toast.success(`Added ${result.agent.name} to ${channel.name}`); } else if (result.membershipAdded) { - toast.success(`Added ${result.agent.name} to ${channel.name}.`); + toast.success(`Added ${result.agent.name} to ${channel.name}`); } else { - toast.success(`${result.agent.name} is already in ${channel.name}.`); + toast.success(`${result.agent.name} is already in ${channel.name}`); } void managedAgentsQuery.refetch(); void relayAgentsQuery.refetch(); diff --git a/desktop/src/features/profile/ui/UserProfilePanelPersonaSubmit.ts b/desktop/src/features/profile/ui/UserProfilePanelPersonaSubmit.ts index eff9a1af10..2fc0d41c04 100644 --- a/desktop/src/features/profile/ui/UserProfilePanelPersonaSubmit.ts +++ b/desktop/src/features/profile/ui/UserProfilePanelPersonaSubmit.ts @@ -100,7 +100,7 @@ export async function submitProfilePersonaDialog({ `${result.agent.name} was updated, but profile sync failed: ${result.profileSyncError}`, ); } - toast.success(`Updated ${input.displayName}.`); + toast.success(`Updated ${input.displayName}`); } else { const persona = await createPersona(input); try { @@ -110,7 +110,7 @@ export async function submitProfilePersonaDialog({ `${persona.displayName} was created, but it did not start: ${created.spawnError}`, ); } else { - toast.success(`Created and started ${created.agent.name}.`); + toast.success(`Created and started ${created.agent.name}`); } if (created.profileSyncError) { toast.warning( @@ -120,16 +120,14 @@ export async function submitProfilePersonaDialog({ } catch (error) { toast.error( error instanceof Error - ? `${persona.displayName} was created, but the agent instance could not be created: ${error.message}` - : `${persona.displayName} was created, but the agent instance could not be created.`, + ? `${persona.displayName} was created, but the agent instance couldn't be created: ${error.message}` + : `${persona.displayName} was created, but the agent instance couldn't be created.`, ); } } onDone(); } catch (error) { - toast.error( - error instanceof Error ? error.message : "Failed to save agent.", - ); + toast.error(error instanceof Error ? error.message : "Couldn't save agent"); } } diff --git a/desktop/src/features/profile/ui/UserProfilePanelSections.tsx b/desktop/src/features/profile/ui/UserProfilePanelSections.tsx index 2a46dcc7a5..2fbd894e97 100644 --- a/desktop/src/features/profile/ui/UserProfilePanelSections.tsx +++ b/desktop/src/features/profile/ui/UserProfilePanelSections.tsx @@ -654,7 +654,7 @@ function ProfilePrimaryActions({ followToggleMutation.mutate(pubkey, { onError: (error) => toast.error( - `${isFollowing ? "Unfollow" : "Follow"} failed: ${error.message}`, + `Couldn't ${isFollowing ? "unfollow" : "follow"}: ${error.message}`, ), }); }; diff --git a/desktop/src/features/profile/ui/UserProfilePopover.tsx b/desktop/src/features/profile/ui/UserProfilePopover.tsx index 9161bac302..cb7903dbab 100644 --- a/desktop/src/features/profile/ui/UserProfilePopover.tsx +++ b/desktop/src/features/profile/ui/UserProfilePopover.tsx @@ -334,9 +334,7 @@ export function UserProfilePopover({ } } catch (error) { toast.error( - error instanceof Error - ? error.message - : "Failed to open direct message.", + error instanceof Error ? error.message : "Couldn't open direct message", ); } finally { if (isMountedRef.current) { @@ -375,7 +373,7 @@ export function UserProfilePopover({ } } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to start huddle.", + error instanceof Error ? error.message : "Couldn't start huddle", ); } finally { if (isMountedRef.current) { @@ -472,7 +470,7 @@ export function UserProfilePopover({ } } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to send wave.", + error instanceof Error ? error.message : "Couldn't send wave", ); } finally { if (isMountedRef.current) { diff --git a/desktop/src/features/profile/ui/UserProfileSnapshotExportDialog.tsx b/desktop/src/features/profile/ui/UserProfileSnapshotExportDialog.tsx index 003c12c812..9de7bff7d1 100644 --- a/desktop/src/features/profile/ui/UserProfileSnapshotExportDialog.tsx +++ b/desktop/src/features/profile/ui/UserProfileSnapshotExportDialog.tsx @@ -33,7 +33,7 @@ export function UserProfileSnapshotExportDialog({ { onSuccess: (saved) => { if (saved) { - toast.success(`Exported ${persona.displayName}.`); + toast.success(`Exported ${persona.displayName}`); onOpenChange(false); } }, @@ -41,7 +41,7 @@ export function UserProfileSnapshotExportDialog({ toast.error( error instanceof Error ? error.message - : "Failed to export agent snapshot.", + : "Couldn't export agent snapshot", ); }, }, diff --git a/desktop/src/features/profile/ui/useProfileDmAction.ts b/desktop/src/features/profile/ui/useProfileDmAction.ts index 0d5811333a..0f3e4afaa9 100644 --- a/desktop/src/features/profile/ui/useProfileDmAction.ts +++ b/desktop/src/features/profile/ui/useProfileDmAction.ts @@ -32,9 +32,7 @@ export function useProfileDmAction({ } catch (error) { if (!isMountedRef.current) return; toast.error( - error instanceof Error - ? error.message - : "Failed to open direct message.", + error instanceof Error ? error.message : "Couldn't open direct message", ); setIsOpeningDm(false); return; diff --git a/desktop/src/features/projects/ui/CreateProjectIssueDialog.tsx b/desktop/src/features/projects/ui/CreateProjectIssueDialog.tsx index af28693bb4..d3c9537c03 100644 --- a/desktop/src/features/projects/ui/CreateProjectIssueDialog.tsx +++ b/desktop/src/features/projects/ui/CreateProjectIssueDialog.tsx @@ -39,7 +39,7 @@ export function CreateProjectIssueDialog({ async function handleCreate(input: CreateProjectWorkItemDialogInput) { if (!project) throw new Error("Choose a repository."); const issueId = await createMutation.mutateAsync(input); - toast.success("Issue created."); + toast.success("Issue created"); await onCreated(project, issueId); } diff --git a/desktop/src/features/projects/ui/CreatePullRequestDialog.tsx b/desktop/src/features/projects/ui/CreatePullRequestDialog.tsx index d64d132aed..11af95f1e5 100644 --- a/desktop/src/features/projects/ui/CreatePullRequestDialog.tsx +++ b/desktop/src/features/projects/ui/CreatePullRequestDialog.tsx @@ -138,7 +138,7 @@ export function CreatePullRequestDialog({ mergeBase: sourceSyncQuery.data?.mergeBase ?? null, reviewers: [], }); - toast.success("Pull request created."); + toast.success("Pull request created"); await onCreated(project, pullRequestId); } diff --git a/desktop/src/features/projects/ui/MergePullRequestButton.tsx b/desktop/src/features/projects/ui/MergePullRequestButton.tsx index 133c41d043..ba0588bb76 100644 --- a/desktop/src/features/projects/ui/MergePullRequestButton.tsx +++ b/desktop/src/features/projects/ui/MergePullRequestButton.tsx @@ -105,9 +105,7 @@ export function MergePullRequestButton({ setConfirmOpen(false); } toast.error( - error instanceof Error - ? error.message - : "Failed to merge pull request.", + error instanceof Error ? error.message : "Failed to merge pull request", ); } }, [mergeMutation, pullRequest]); @@ -138,12 +136,12 @@ export function MergePullRequestButton({ recoveryRef: result.recoveryRef, targetRef: result.targetRef, }); - toast.success("Recovery commit fetched and terminal opened."); + toast.success("Recovery commit fetched and terminal opened"); } catch (error) { toast.error( error instanceof Error ? error.message - : "Failed to prepare merge recovery.", + : "Failed to prepare merge recovery", ); } finally { setIsPreparingRecovery(false); @@ -164,12 +162,12 @@ export function MergePullRequestButton({ statusEvent: unpublishedStatusEvent, }); setUnpublishedStatusState(null); - toast.success("Published merged pull request status."); + toast.success("Published merged pull request status"); } catch (error) { toast.error( error instanceof Error ? error.message - : "Failed to publish merged pull request status.", + : "Failed to publish merged pull request status", ); } }, [publishMergedMutation, unpublishedStatusEvent]); diff --git a/desktop/src/features/projects/ui/ProjectDetailScreen.tsx b/desktop/src/features/projects/ui/ProjectDetailScreen.tsx index f67d535513..5dc75dcf1a 100644 --- a/desktop/src/features/projects/ui/ProjectDetailScreen.tsx +++ b/desktop/src/features/projects/ui/ProjectDetailScreen.tsx @@ -278,13 +278,13 @@ export function ProjectDetailScreen(props: ProjectDetailScreenProps) { ]); const error = results.find((result) => result.error)?.error; if (error) { - toast.error("Could not fetch repository.", { + toast.error("Couldn't fetch repository", { description: error instanceof Error ? error.message : "The Git fetch failed.", }); return; } - toast.success("Remote state refreshed."); + toast.success("Remote state refreshed"); }, [repoSnapshotQuery, repoStateQuery, repoSyncStatusQuery]); // Compact branch + remote/local controls shared by the readme and Files // tab headers. @@ -515,7 +515,7 @@ export function ProjectDetailScreen(props: ProjectDetailScreenProps) { const handleCreateIssue = React.useCallback( async ({ body, title }: CreateIssueDialogInput) => { const issueId = await createIssueMutation.mutateAsync({ body, title }); - toast.success("Issue created."); + toast.success("Issue created"); await issuesQuery.refetch(); setSelectedIssueId(issueId); }, @@ -530,7 +530,7 @@ export function ProjectDetailScreen(props: ProjectDetailScreenProps) { mergeBase: repoSyncStatusQuery.data?.mergeBase ?? null, }); toast.success( - updated ? "Pull request updated." : "Pull request is already current.", + updated ? "Pull request updated" : "Pull request is already current", ); await pullRequestsQuery.refetch(); } catch (error) { diff --git a/desktop/src/features/projects/ui/ProjectIssuesPanel.tsx b/desktop/src/features/projects/ui/ProjectIssuesPanel.tsx index 861645a248..d3558f7291 100644 --- a/desktop/src/features/projects/ui/ProjectIssuesPanel.tsx +++ b/desktop/src/features/projects/ui/ProjectIssuesPanel.tsx @@ -193,10 +193,10 @@ function IssueDetail({ mediaTags, mentionPubkeys, }); - toast.success("Comment posted."); + toast.success("Comment posted"); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to post comment.", + error instanceof Error ? error.message : "Failed to post comment", ); throw error; } diff --git a/desktop/src/features/projects/ui/ProjectPullRequestFilesChangedPanel.tsx b/desktop/src/features/projects/ui/ProjectPullRequestFilesChangedPanel.tsx index ba94db68e8..a70947a305 100644 --- a/desktop/src/features/projects/ui/ProjectPullRequestFilesChangedPanel.tsx +++ b/desktop/src/features/projects/ui/ProjectPullRequestFilesChangedPanel.tsx @@ -641,12 +641,12 @@ export function ProjectPullRequestFilesChangedPanel({ pullRequest, }); setActiveAnchor(null); - toast.success("Line comment posted."); + toast.success("Line comment posted"); } catch (error) { toast.error( error instanceof Error ? error.message - : "Failed to post line comment.", + : "Failed to post line comment", ); throw error; } diff --git a/desktop/src/features/projects/ui/ProjectPullRequestsPanel.tsx b/desktop/src/features/projects/ui/ProjectPullRequestsPanel.tsx index 4e2dbb2a53..a3a472db7e 100644 --- a/desktop/src/features/projects/ui/ProjectPullRequestsPanel.tsx +++ b/desktop/src/features/projects/ui/ProjectPullRequestsPanel.tsx @@ -479,10 +479,10 @@ function PullRequestDetail({ mentionPubkeys, pullRequest, }); - toast.success("Comment posted."); + toast.success("Comment posted"); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to post comment.", + error instanceof Error ? error.message : "Failed to post comment", ); throw error; } diff --git a/desktop/src/features/projects/ui/ProjectsAgentPromptPage.tsx b/desktop/src/features/projects/ui/ProjectsAgentPromptPage.tsx index 29705425f6..be4502868a 100644 --- a/desktop/src/features/projects/ui/ProjectsAgentPromptPage.tsx +++ b/desktop/src/features/projects/ui/ProjectsAgentPromptPage.tsx @@ -397,7 +397,7 @@ export function ProjectsAgentPromptPage({ richText.clearContent(); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to reach the agent", + error instanceof Error ? error.message : "Couldn't reach agent", ); } finally { setIsSending(false); diff --git a/desktop/src/features/projects/ui/ProjectsView.tsx b/desktop/src/features/projects/ui/ProjectsView.tsx index 2f22bfe0c1..ff4afba191 100644 --- a/desktop/src/features/projects/ui/ProjectsView.tsx +++ b/desktop/src/features/projects/ui/ProjectsView.tsx @@ -603,7 +603,7 @@ export function ProjectsView() { isCreating={createProjectMutation.isPending} onCreate={async (input) => { const project = await createProjectMutation.mutateAsync(input); - toast.success(`Project "${project.name}" created.`); + toast.success(`Project "${project.name}" created`); // Land on the list that actually shows the new project — the // Overview only surfaces the top few most-active repositories. handleRepositoryScopeChange("all"); diff --git a/desktop/src/features/projects/ui/PullRequestReviewCard.tsx b/desktop/src/features/projects/ui/PullRequestReviewCard.tsx index bf2f074a8b..51aca9978f 100644 --- a/desktop/src/features/projects/ui/PullRequestReviewCard.tsx +++ b/desktop/src/features/projects/ui/PullRequestReviewCard.tsx @@ -86,12 +86,12 @@ export function PullRequestReviewCard({ await updatePullRequestStatus({ pullRequest, status }); toast.success( status === "draft" - ? "Converted to draft." - : "Marked as ready for review.", + ? "Converted to draft" + : "Marked as ready for review", ); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to update status.", + error instanceof Error ? error.message : "Failed to update status", ); } }, @@ -135,16 +135,16 @@ export function PullRequestReviewCard({ const handleApprove = React.useCallback(async () => { await runReviewDecision( approvePullRequest, - "Pull request approved.", - "Failed to approve.", + "Pull request approved", + "Failed to approve", ); }, [approvePullRequest, runReviewDecision]); const handleRequestChanges = React.useCallback(async () => { await runReviewDecision( requestPullRequestChanges, - "Changes requested.", - "Failed to request changes.", + "Changes requested", + "Failed to request changes", ); }, [requestPullRequestChanges, runReviewDecision]); diff --git a/desktop/src/features/projects/ui/PullRequestReviewersRow.tsx b/desktop/src/features/projects/ui/PullRequestReviewersRow.tsx index 63c5be94b1..9d180dad67 100644 --- a/desktop/src/features/projects/ui/PullRequestReviewersRow.tsx +++ b/desktop/src/features/projects/ui/PullRequestReviewersRow.tsx @@ -106,10 +106,10 @@ export function PullRequestReviewersRow({ }); setPickerOpen(false); setReviewerQuery(""); - toast.success("Review requested."); + toast.success("Review requested"); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to request review.", + error instanceof Error ? error.message : "Failed to request review", ); } finally { requestInFlightRef.current = false; diff --git a/desktop/src/features/projects/ui/useOpenProjectTerminal.ts b/desktop/src/features/projects/ui/useOpenProjectTerminal.ts index 64d2415536..6defabed6a 100644 --- a/desktop/src/features/projects/ui/useOpenProjectTerminal.ts +++ b/desktop/src/features/projects/ui/useOpenProjectTerminal.ts @@ -43,7 +43,7 @@ export function useOpenProjectTerminal(reposDir?: string | null) { } } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to open terminal", + error instanceof Error ? error.message : "Couldn't open the terminal", { id: toastId }, ); } diff --git a/desktop/src/features/pulse/lib/useNoteActions.ts b/desktop/src/features/pulse/lib/useNoteActions.ts index 8178cdc53a..a88bf67234 100644 --- a/desktop/src/features/pulse/lib/useNoteActions.ts +++ b/desktop/src/features/pulse/lib/useNoteActions.ts @@ -98,7 +98,7 @@ export function usePulseNoteActions({ queryClient.setQueryData(reactionQueryKey, previousReactions); toast.error( - error instanceof Error ? error.message : "Failed to update reaction", + error instanceof Error ? error.message : "Couldn't update reaction", ); } finally { setPendingUpvoteNoteIds((current) => @@ -135,7 +135,7 @@ export function usePulseNoteActions({ }); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to post reply", + error instanceof Error ? error.message : "Couldn't post reply", ); throw error; } @@ -148,7 +148,7 @@ export function usePulseNoteActions({ await writeTextToClipboard(buildNoteShareUri(note)); toast.success("Copied note link"); } catch { - toast.error("Failed to copy note link"); + toast.error("Couldn't copy note link"); } }, []); @@ -164,7 +164,7 @@ export function usePulseNoteActions({ }); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to open DM", + error instanceof Error ? error.message : "Couldn't open DM", ); } }, diff --git a/desktop/src/features/reminders/ui/RemindMeLaterDialog.tsx b/desktop/src/features/reminders/ui/RemindMeLaterDialog.tsx index 2833eee45f..bcdc936eba 100644 --- a/desktop/src/features/reminders/ui/RemindMeLaterDialog.tsx +++ b/desktop/src/features/reminders/ui/RemindMeLaterDialog.tsx @@ -48,7 +48,7 @@ export function RemindMeLaterDialog({ onOpenChange(false); setNote(""); }, - onError: () => toast.error("Failed to create reminder"), + onError: () => toast.error("Couldn't create reminder"), }, ); }; diff --git a/desktop/src/features/reminders/ui/RemindersPanel.tsx b/desktop/src/features/reminders/ui/RemindersPanel.tsx index 651768a251..630971cb1f 100644 --- a/desktop/src/features/reminders/ui/RemindersPanel.tsx +++ b/desktop/src/features/reminders/ui/RemindersPanel.tsx @@ -72,7 +72,7 @@ function ReminderRow({ const handleComplete = () => { complete.mutate(reminder, { onSuccess: () => toast.success("Reminder completed"), - onError: () => toast.error("Failed to complete reminder"), + onError: () => toast.error("Couldn't complete reminder"), }); }; @@ -81,7 +81,7 @@ function ReminderRow({ { reminder, notBefore }, { onSuccess: () => toast.success("Reminder snoozed"), - onError: () => toast.error("Failed to snooze reminder"), + onError: () => toast.error("Couldn't snooze reminder"), }, ); }; @@ -89,7 +89,7 @@ function ReminderRow({ const handleCancel = () => { cancel.mutate(reminder, { onSuccess: () => toast.success("Reminder cancelled"), - onError: () => toast.error("Failed to cancel reminder"), + onError: () => toast.error("Couldn't cancel reminder"), }); }; diff --git a/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx b/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx index 6c149aaab0..49f23b46a0 100644 --- a/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx +++ b/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx @@ -77,7 +77,7 @@ export function ChannelTemplatesSettingsCard() { }, onError: (error) => { toast.error( - error instanceof Error ? error.message : "Failed to duplicate", + error instanceof Error ? error.message : "Couldn't duplicate", ); }, }); @@ -91,9 +91,7 @@ export function ChannelTemplatesSettingsCard() { setDeleteTarget(null); }, onError: (error) => { - toast.error( - error instanceof Error ? error.message : "Failed to delete", - ); + toast.error(error instanceof Error ? error.message : "Couldn't delete"); }, }); } @@ -368,7 +366,7 @@ function TemplateFormDialog({ }, onError: (error) => { toast.error( - error instanceof Error ? error.message : "Failed to update", + error instanceof Error ? error.message : "Couldn't update", ); }, }); @@ -387,7 +385,7 @@ function TemplateFormDialog({ }, onError: (error) => { toast.error( - error instanceof Error ? error.message : "Failed to create", + error instanceof Error ? error.message : "Couldn't create", ); }, }); diff --git a/desktop/src/features/settings/ui/ModerationQueueCard.tsx b/desktop/src/features/settings/ui/ModerationQueueCard.tsx index ca9adf980d..6e3cdd7668 100644 --- a/desktop/src/features/settings/ui/ModerationQueueCard.tsx +++ b/desktop/src/features/settings/ui/ModerationQueueCard.tsx @@ -414,7 +414,7 @@ function QueueTab() { ); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to resolve the report", + error instanceof Error ? error.message : "Couldn't resolve the report", ); } } diff --git a/desktop/src/features/settings/ui/ProfileSettingsCard.tsx b/desktop/src/features/settings/ui/ProfileSettingsCard.tsx index d09a4fed64..0e3bd587c4 100644 --- a/desktop/src/features/settings/ui/ProfileSettingsCard.tsx +++ b/desktop/src/features/settings/ui/ProfileSettingsCard.tsx @@ -1013,7 +1013,7 @@ export function ProfileSettingsCard({ setIsSignOutPending(false); setIsSignOutOpen(false); toast.error( - err instanceof Error ? err.message : "Sign out failed.", + err instanceof Error ? err.message : "Couldn't sign out", ); }); }} diff --git a/desktop/src/shared/lib/clipboard.ts b/desktop/src/shared/lib/clipboard.ts index 93e2bed44e..25a06fa259 100644 --- a/desktop/src/shared/lib/clipboard.ts +++ b/desktop/src/shared/lib/clipboard.ts @@ -17,6 +17,6 @@ export function copyTextToClipboard( toast.success(successMessage); }) .catch(() => { - toast.error("Failed to copy to clipboard"); + toast.error("Couldn't copy to clipboard"); }); } diff --git a/desktop/src/shared/lib/localStorageQuota.ts b/desktop/src/shared/lib/localStorageQuota.ts index bf194a6cc8..39dab9f1a5 100644 --- a/desktop/src/shared/lib/localStorageQuota.ts +++ b/desktop/src/shared/lib/localStorageQuota.ts @@ -38,9 +38,9 @@ function notifyStorageFull(): void { // Dynamic import keeps this module usable from node unit tests. import("sonner") .then(({ toast }) => { - toast.error("Local storage is full", { + toast.error("Storage is full", { description: - "Buzz could not save some local data — read positions may not persist across restarts.", + "Buzz couldn't save some data. Recent changes may be lost when you restart.", }); }) .catch(() => {}); diff --git a/desktop/src/shared/ui/markdown.tsx b/desktop/src/shared/ui/markdown.tsx index b1f9623f3e..6afe400ea6 100644 --- a/desktop/src/shared/ui/markdown.tsx +++ b/desktop/src/shared/ui/markdown.tsx @@ -1165,7 +1165,7 @@ function ImageBlock({ alt, dim, resolvedSrc, src, thumbSrc }: ImageBlockProps) { toast.success("Copied to clipboard"); }) .catch((err: unknown) => { - const msg = err instanceof Error ? err.message : "Copy failed"; + const msg = err instanceof Error ? err.message : "Couldn't copy"; toast.error(msg); }); }, []); @@ -1176,7 +1176,7 @@ function ImageBlock({ alt, dim, resolvedSrc, src, thumbSrc }: ImageBlockProps) { if (!downloadSrc) return; invokeTauri("download_image", { url: downloadSrc }).catch( (err: unknown) => { - const msg = err instanceof Error ? err.message : "Download failed"; + const msg = err instanceof Error ? err.message : "Couldn't download"; toast.error(msg); }, ); @@ -1332,7 +1332,7 @@ function ExternalLinkAnchor({ onSelect: () => { closeMenu(); void openUrl(href).catch(() => { - toast.error("Failed to open link"); + toast.error("Couldn't open link"); }); }, }, diff --git a/desktop/src/shared/ui/markdown/CodeBlock.tsx b/desktop/src/shared/ui/markdown/CodeBlock.tsx index 06f9fb4c4b..faa3777d61 100644 --- a/desktop/src/shared/ui/markdown/CodeBlock.tsx +++ b/desktop/src/shared/ui/markdown/CodeBlock.tsx @@ -87,7 +87,7 @@ export function MarkdownCodeBlock({ toast.success("Copied code to clipboard"); } catch (error) { console.error("Failed to copy code block", error); - toast.error("Failed to copy code"); + toast.error("Couldn't copy code"); } finally { setIsCopying(false); } diff --git a/desktop/src/shared/ui/markdown/FileCard.tsx b/desktop/src/shared/ui/markdown/FileCard.tsx index 889847193e..4015662e34 100644 --- a/desktop/src/shared/ui/markdown/FileCard.tsx +++ b/desktop/src/shared/ui/markdown/FileCard.tsx @@ -49,7 +49,8 @@ export function FileCard({ onClick={() => { invokeTauri("download_file", { url: href, filename }).catch( (err: unknown) => { - const msg = err instanceof Error ? err.message : "Download failed"; + const msg = + err instanceof Error ? err.message : "Couldn't download"; toast.error(msg); }, ); diff --git a/desktop/src/shared/ui/useVideoContextMenu.tsx b/desktop/src/shared/ui/useVideoContextMenu.tsx index ec6c5791f7..91f1998dd7 100644 --- a/desktop/src/shared/ui/useVideoContextMenu.tsx +++ b/desktop/src/shared/ui/useVideoContextMenu.tsx @@ -55,7 +55,9 @@ export function useVideoContextMenu( url: downloadUrl, filename: resolveVideoDownloadFilename(filename), }).catch((err: unknown) => { - toast.error(err instanceof Error ? err.message : "Download failed"); + toast.error( + err instanceof Error ? err.message : "Couldn't download", + ); }); }, }); From 403b17aebb8878b79595116cb969fd7f6c6afa51 Mon Sep 17 00:00:00 2001 From: Clay Delk Date: Mon, 20 Jul 2026 17:01:08 -0400 Subject: [PATCH 2/2] feat(desktop): polish destructive confirmation dialog copy Standardize confirmation dialogs: community terminology, question-form titles, sentence-case buttons, specific "Delete {noun}" actions, contracted "can't be undone", and consequence-led bodies. Also add cleared-topic and cleared-purpose system messages. Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitignore | 3 +++ .../agents/ui/PersonaDeleteDialog.tsx | 12 +++++------ .../features/agents/ui/TeamDeleteDialog.tsx | 6 +++--- .../ui/ConfirmRemoveDialog.tsx | 2 +- .../features/forum/ui/DeleteConfirmDialog.tsx | 2 +- .../src/features/messages/ui/DraftsPanel.tsx | 4 ++-- .../features/messages/ui/MessageActionBar.tsx | 4 ++-- .../features/messages/ui/SystemMessageRow.tsx | 20 +++++++++++++++---- .../onboarding/ui/MachineOnboardingFlow.tsx | 2 +- .../features/onboarding/ui/OnboardingFlow.tsx | 2 +- .../profile/ui/ArchiveConfirmDialog.tsx | 6 +++--- .../profile/ui/UserProfileAgentActions.tsx | 2 +- .../src/features/projects/ui/ProjectCards.tsx | 2 +- .../ui/ChannelTemplatesSettingsCard.tsx | 8 ++++---- .../settings/ui/ProfileSettingsCard.tsx | 8 ++++---- .../sidebar/ui/ChannelSectionDialogs.tsx | 12 +++++------ .../workflows/ui/WorkflowDeleteDialog.tsx | 6 +++--- .../e2e/agent-lifecycle-feedback.spec.ts | 18 ++++++++--------- 18 files changed, 67 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index 65ddcaf1c4..0e181a5604 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,9 @@ blob-report/ # Node modules (pnpm workspace hoists to root) node_modules/ +# pnpm content-addressable store (local cache, not portable) +.pnpm-store/ + # Root npm lockfiles are accidental; desktop uses pnpm in /desktop. /package-lock.json diff --git a/desktop/src/features/agents/ui/PersonaDeleteDialog.tsx b/desktop/src/features/agents/ui/PersonaDeleteDialog.tsx index fd9da43751..f9c3125ae4 100644 --- a/desktop/src/features/agents/ui/PersonaDeleteDialog.tsx +++ b/desktop/src/features/agents/ui/PersonaDeleteDialog.tsx @@ -32,16 +32,16 @@ export function personaDeleteDescription( instanceCount: number, ): string { if (!persona) { - return "Delete this agent."; + return "This agent will be removed."; } if (instanceCount === 0) { - return `Delete ${persona.displayName}.`; + return `${persona.displayName} will be removed.`; } const cascade = instanceCount === 1 - ? "Also deletes 1 agent instance and archives its identity on the relay, so it no longer appears in member lists or mention suggestions." - : `Also deletes ${instanceCount} agent instances and archives their identities on the relay, so they no longer appear in member lists or mention suggestions.`; - return `Delete ${persona.displayName}. ${cascade}`; + ? "Its 1 agent instance is also deleted and its identity archived in the community, so it no longer appears in member lists or mention suggestions." + : `Its ${instanceCount} agent instances are also deleted and their identities archived in the community, so they no longer appear in member lists or mention suggestions.`; + return `${persona.displayName} will be removed. ${cascade}`; } export function PersonaDeleteDialog({ @@ -76,7 +76,7 @@ export function PersonaDeleteDialog({ type="button" variant="destructive" > - Delete + Delete agent diff --git a/desktop/src/features/agents/ui/TeamDeleteDialog.tsx b/desktop/src/features/agents/ui/TeamDeleteDialog.tsx index 383f92c4a5..03bc53980e 100644 --- a/desktop/src/features/agents/ui/TeamDeleteDialog.tsx +++ b/desktop/src/features/agents/ui/TeamDeleteDialog.tsx @@ -31,8 +31,8 @@ export function TeamDeleteDialog({ Delete team? {team - ? `Delete "${team.name}". Already-deployed agents are not affected, but this team template will no longer be available.` - : "Delete this team."} + ? `"${team.name}" will no longer be available as a template. Already-deployed agents aren't affected.` + : "This team template will no longer be available."} @@ -51,7 +51,7 @@ export function TeamDeleteDialog({ type="button" variant="destructive" > - Delete + Delete team diff --git a/desktop/src/features/community-members/ui/ConfirmRemoveDialog.tsx b/desktop/src/features/community-members/ui/ConfirmRemoveDialog.tsx index 007a1635e6..a8fdaf819e 100644 --- a/desktop/src/features/community-members/ui/ConfirmRemoveDialog.tsx +++ b/desktop/src/features/community-members/ui/ConfirmRemoveDialog.tsx @@ -43,7 +43,7 @@ export function ConfirmRemoveDialog({ Remove {label}? - This will immediately revoke their access to the relay. + This will immediately revoke their access to the community. {member ? ( Delete {label}? - This will permanently delete this {label} and cannot be undone. + This will permanently delete this {label} and can't be undone. diff --git a/desktop/src/features/messages/ui/DraftsPanel.tsx b/desktop/src/features/messages/ui/DraftsPanel.tsx index 5a506a0a83..d019d03326 100644 --- a/desktop/src/features/messages/ui/DraftsPanel.tsx +++ b/desktop/src/features/messages/ui/DraftsPanel.tsx @@ -312,9 +312,9 @@ export function SendConfirmDialog({ > - Send message + Send message? - Are you sure you want to send this message to {destination}? + This message will be sent to {destination}. diff --git a/desktop/src/features/messages/ui/MessageActionBar.tsx b/desktop/src/features/messages/ui/MessageActionBar.tsx index ba45bc62fb..a57b0e8aa2 100644 --- a/desktop/src/features/messages/ui/MessageActionBar.tsx +++ b/desktop/src/features/messages/ui/MessageActionBar.tsx @@ -285,7 +285,7 @@ function MoreActionsMenu({ Delete message? - This will permanently delete this message and cannot be undone. + This will permanently delete this message and can't be undone. @@ -300,7 +300,7 @@ function MoreActionsMenu({ type="button" variant="destructive" > - Delete + Delete message diff --git a/desktop/src/features/messages/ui/SystemMessageRow.tsx b/desktop/src/features/messages/ui/SystemMessageRow.tsx index 0fbb9508d3..b1d4377e3f 100644 --- a/desktop/src/features/messages/ui/SystemMessageRow.tsx +++ b/desktop/src/features/messages/ui/SystemMessageRow.tsx @@ -584,16 +584,28 @@ function describeSystemEvent( title: actorName, action: <>removed {targetName} from the channel, }; - case "topic_changed": + case "topic_changed": { + const topic = payload.topic?.trim(); return { title: actorName, - action: <>changed the topic to “{payload.topic}”, + action: topic ? ( + <>changed the topic to “{topic}” + ) : ( + "cleared the channel topic" + ), }; - case "purpose_changed": + } + case "purpose_changed": { + const purpose = payload.purpose?.trim(); return { title: actorName, - action: <>changed the purpose to “{payload.purpose}”, + action: purpose ? ( + <>changed the purpose to “{purpose}” + ) : ( + "cleared the channel purpose" + ), }; + } case "channel_created": return { title: actorName, diff --git a/desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx b/desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx index 2d040ff348..fe24fccc69 100644 --- a/desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx +++ b/desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx @@ -151,7 +151,7 @@ export function MachineOnboardingFlow({ const replaceLostIdentity = React.useCallback(async () => { const confirmed = window.confirm( - "This will create a new identity and abandon your previous key. This cannot be undone. Continue?", + "This will create a new identity and abandon your previous key. This can't be undone. Continue?", ); if (!confirmed) return; diff --git a/desktop/src/features/onboarding/ui/OnboardingFlow.tsx b/desktop/src/features/onboarding/ui/OnboardingFlow.tsx index 01a226e3de..5c5be70063 100644 --- a/desktop/src/features/onboarding/ui/OnboardingFlow.tsx +++ b/desktop/src/features/onboarding/ui/OnboardingFlow.tsx @@ -407,7 +407,7 @@ export function OnboardingFlow({ // RelaunchRequiredScreen. No navigation needed here. const handleLostModeBack = React.useCallback(async () => { const confirmed = window.confirm( - "This will create a new identity and abandon your previous key. This cannot be undone. Continue?", + "This will create a new identity and abandon your previous key. This can't be undone. Continue?", ); if (!confirmed) { return; diff --git a/desktop/src/features/profile/ui/ArchiveConfirmDialog.tsx b/desktop/src/features/profile/ui/ArchiveConfirmDialog.tsx index 2f750543db..e6afaa9e02 100644 --- a/desktop/src/features/profile/ui/ArchiveConfirmDialog.tsx +++ b/desktop/src/features/profile/ui/ArchiveConfirmDialog.tsx @@ -39,7 +39,7 @@ export function ArchiveConfirmDialog({ {title} - Archiving hides {subject} from the space. + Archiving hides {subject} from the community. {/* The list + closing paragraph sit outside AlertDialogDescription on @@ -51,8 +51,8 @@ export function ArchiveConfirmDialog({
  • This only affects{" "} - this space — - not their account anywhere else + this community{" "} + — not their account anywhere else
  • You can unarchive them at any time to restore them
  • diff --git a/desktop/src/features/profile/ui/UserProfileAgentActions.tsx b/desktop/src/features/profile/ui/UserProfileAgentActions.tsx index 81db3405b2..3e2b44918b 100644 --- a/desktop/src/features/profile/ui/UserProfileAgentActions.tsx +++ b/desktop/src/features/profile/ui/UserProfileAgentActions.tsx @@ -310,7 +310,7 @@ function AgentDeleteConfirmDialog({ - Delete this agent? + Delete agent? Deleting this agent stops and removes the agent from this community. diff --git a/desktop/src/features/projects/ui/ProjectCards.tsx b/desktop/src/features/projects/ui/ProjectCards.tsx index 52308f7a05..5a38355287 100644 --- a/desktop/src/features/projects/ui/ProjectCards.tsx +++ b/desktop/src/features/projects/ui/ProjectCards.tsx @@ -363,7 +363,7 @@ function ProjectActionsMenu({ Delete project? Delete {project.name} from Projects for everyone. This can only be - done for projects you own and cannot be undone. + done for projects you own and can't be undone. diff --git a/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx b/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx index 49f23b46a0..264f55e302 100644 --- a/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx +++ b/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx @@ -165,10 +165,10 @@ export function ChannelTemplatesSettingsCard() { > - Delete template + Delete template? - Are you sure you want to delete "{deleteTarget?.name}"? - This action cannot be undone. + Delete "{deleteTarget?.name}". This can't be + undone. @@ -177,7 +177,7 @@ export function ChannelTemplatesSettingsCard() { className="bg-destructive text-destructive-foreground hover:bg-destructive/90" onClick={handleDelete} > - Delete + Delete template diff --git a/desktop/src/features/settings/ui/ProfileSettingsCard.tsx b/desktop/src/features/settings/ui/ProfileSettingsCard.tsx index 0e3bd587c4..18e58f4ec6 100644 --- a/desktop/src/features/settings/ui/ProfileSettingsCard.tsx +++ b/desktop/src/features/settings/ui/ProfileSettingsCard.tsx @@ -965,7 +965,7 @@ export function ProfileSettingsCard({

    Sign out

    Removes your identity key and all local app data from this device. - Back up your private key (nsec) first — this cannot be undone. + Back up your private key (nsec) first — this can't be undone.

    @@ -1018,7 +1018,7 @@ export function ProfileSettingsCard({ }); }} > - {isSignOutPending ? "Signing out…" : "Sign Out"} + {isSignOutPending ? "Signing out…" : "Sign out"}
    diff --git a/desktop/src/features/sidebar/ui/ChannelSectionDialogs.tsx b/desktop/src/features/sidebar/ui/ChannelSectionDialogs.tsx index 6b054fa600..78c2578c76 100644 --- a/desktop/src/features/sidebar/ui/ChannelSectionDialogs.tsx +++ b/desktop/src/features/sidebar/ui/ChannelSectionDialogs.tsx @@ -249,14 +249,14 @@ export function DeleteSectionAlertDialog({ channelCount === 1 ? "1 channel" : `${channelCount} channels`; const description = channelCount === 0 - ? `Delete section "${sectionName}"? It has no channels.` - : `Delete section "${sectionName}"? Its ${channelLabel} will move back to the default Channels group.`; + ? `"${sectionName}" has no channels.` + : `Its ${channelLabel} will move back to the default Channels group.`; return ( - Delete section + Delete section? {description} @@ -265,7 +265,7 @@ export function DeleteSectionAlertDialog({ className="bg-destructive text-destructive-foreground hover:bg-destructive/90" onClick={onConfirm} > - Delete + Delete section @@ -294,9 +294,9 @@ export function LeaveChannelAlertDialog({ - Leave channel + Leave channel? - {`Leave "${channelName}"? You'll stop receiving its messages and can rejoin later.`} + {`You'll stop receiving messages from "${channelName}" and can rejoin later.`} diff --git a/desktop/src/features/workflows/ui/WorkflowDeleteDialog.tsx b/desktop/src/features/workflows/ui/WorkflowDeleteDialog.tsx index db07470f2c..423071977b 100644 --- a/desktop/src/features/workflows/ui/WorkflowDeleteDialog.tsx +++ b/desktop/src/features/workflows/ui/WorkflowDeleteDialog.tsx @@ -31,8 +31,8 @@ export function WorkflowDeleteDialog({ Delete workflow? {workflow - ? `Delete "${workflow.name}". This will stop all future triggers and remove the workflow permanently.` - : "Delete this workflow."} + ? `"${workflow.name}" will stop triggering and be removed permanently.` + : "This workflow will be removed permanently."} @@ -51,7 +51,7 @@ export function WorkflowDeleteDialog({ type="button" variant="destructive" > - Delete + Delete workflow diff --git a/desktop/tests/e2e/agent-lifecycle-feedback.spec.ts b/desktop/tests/e2e/agent-lifecycle-feedback.spec.ts index 6200975889..f0e5cce851 100644 --- a/desktop/tests/e2e/agent-lifecycle-feedback.spec.ts +++ b/desktop/tests/e2e/agent-lifecycle-feedback.spec.ts @@ -1,8 +1,8 @@ /** * E2E screenshots + regression tests for agent-lifecycle feedback (PR #1766): * - * 1. Persona delete confirm dialog shows "Also deletes N agent instance(s)." - * when the persona has linked managed-agent instances. + * 1. Persona delete confirm dialog discloses that N linked agent instance(s) + * are also deleted when the persona has linked managed-agent instances. * 2. Global-config save reports "Saved. Restarted N agents." when running agents * were restarted. * 3. Global-config save reports plain "Saved." when no agents were restarted; @@ -75,7 +75,7 @@ test.describe("agent lifecycle feedback screenshots", () => { }); }); - // Shot 01: persona delete confirm dialog — "Also deletes 2 agent instance(s)." + // Shot 01: persona delete confirm dialog — 2 linked agent instances. // Seeds a custom persona with two linked managed agents so instanceCount = 2. // Triggers the delete confirm from the persona's "..." actions menu. test("01-delete-cascade-copy", async ({ page }) => { @@ -124,9 +124,9 @@ test.describe("agent lifecycle feedback screenshots", () => { await expect(dialog).toBeVisible({ timeout: 5_000 }); // Core assertion: the cascade copy shows the correct instance count - // (plural) and discloses the relay-side archival (PR #2135). + // (plural) and discloses the identity archival (PR #2135). await expect(dialog).toContainText( - "Also deletes 2 agent instances and archives their identities on the relay", + "Its 2 agent instances are also deleted and their identities archived in the community", ); await waitForAnimations(page); @@ -215,7 +215,7 @@ test.describe("agent lifecycle feedback screenshots", () => { }); }); - // Shot 04: persona delete confirm dialog — singular "Also deletes 1 agent instance." + // Shot 04: persona delete confirm dialog — singular 1 linked agent instance. // One linked instance → singular copy (no extra "s"). test("04-delete-cascade-singular", async ({ page }) => { await installMockBridge(page, { @@ -253,7 +253,7 @@ test.describe("agent lifecycle feedback screenshots", () => { // Singular copy ("instance", "its identity") plus the archival disclosure. await expect(dialog).toContainText( - "Also deletes 1 agent instance and archives its identity on the relay", + "Its 1 agent instance is also deleted and its identity archived in the community", ); await waitForAnimations(page); @@ -263,7 +263,7 @@ test.describe("agent lifecycle feedback screenshots", () => { }); // Shot 05: persona delete confirm dialog — zero linked instances. - // No managed agents linked to the persona → "Also deletes…" line absent. + // No managed agents linked to the persona → cascade line absent. test("05-delete-cascade-zero-instances", async ({ page }) => { await installMockBridge(page, { personas: [ @@ -292,7 +292,7 @@ test.describe("agent lifecycle feedback screenshots", () => { await expect(dialog).toBeVisible({ timeout: 5_000 }); // No linked instances → no cascade warning. - await expect(dialog).not.toContainText("Also deletes"); + await expect(dialog).not.toContainText("agent instance"); }); // Shot 06: global config save — singular "Saved. Restarted 1 agent."