feat(desktop): polish system message and toast copy

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) <noreply@anthropic.com>
This commit is contained in:
Clay Delk
2026-07-20 14:18:26 -04:00
parent 00ecf2cac7
commit f5f3102108
53 changed files with 170 additions and 151 deletions

View File

@@ -720,7 +720,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: () => {
@@ -729,8 +729,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}`,
),
});
},

View File

@@ -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;

View File

@@ -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([

View File

@@ -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`,
);
}
}

View File

@@ -67,7 +67,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;
@@ -322,7 +326,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;
@@ -459,6 +467,7 @@ function MemberActionsMenu({
onTimeout(
member,
Math.floor(Date.now() / 1000) + preset.seconds,
preset.label,
)
}
>

View File

@@ -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],
);

View File

@@ -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");
}
}

View File

@@ -72,7 +72,7 @@ export function CommunityIconSettingsCard({
toast.error(
error instanceof Error
? error.message
: "Couldn’t update the community icon.",
: "Couldn’t update the community icon",
);
}
}

View File

@@ -23,7 +23,7 @@ const MIGRATION_TOAST_KEY = "buzz-legacy-nest-migrated-notified";
export function useNestNotifications(): void {
useEffect(() => {
const unlistenReposError = listen<string>("repos-dir-error", (event) => {
toast.error("Repos directory not applied", {
toast.error("Couldn't apply the repos directory", {
description: event.payload,
});
});

View File

@@ -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",
);
},
},

View File

@@ -119,7 +119,7 @@ function RelayMemberRow({
toast.error(
error instanceof Error
? error.message
: "Couldn’t update this community member.",
: "Couldn’t update membership",
);
}
}
@@ -187,7 +187,7 @@ function RelayMemberRow({
pubkey: member.pubkey,
role: "admin",
}),
"Made community admin",
`Promoted ${displayName} to admin`,
)
}
>
@@ -203,7 +203,7 @@ function RelayMemberRow({
pubkey: member.pubkey,
role: "member",
}),
"Made community member",
`Demoted ${displayName} to member`,
)
}
>
@@ -219,7 +219,7 @@ function RelayMemberRow({
onClick={() =>
void mutateWithToast(
() => removeMutation.mutateAsync(member.pubkey),
"Removed community member",
`Removed ${displayName} from the community`,
)
}
>

View File

@@ -75,7 +75,7 @@ export function ConfirmRemoveDialog({
toast.error(
error instanceof Error
? error.message
: "Failed to remove member",
: "Couldn't remove member",
);
},
});

View File

@@ -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",
);
}
},

View File

@@ -32,6 +32,6 @@ export function formatHuddleActionError(
}
return action === "join"
? "Couldn’t join the huddle."
: "Couldn’t start the huddle.";
? "Couldn’t join the huddle"
: "Couldn’t start the huddle";
}

View File

@@ -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)}`,
),
},
);

View File

@@ -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);

View File

@@ -681,7 +681,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}`);
},
});
}

View File

@@ -522,7 +522,7 @@ function describeSystemEvent(
title: membershipTitle,
action: (
<>
was added by{" "}
added by{" "}
<ProfileName pubkey={payload.actor} underlineOnHover>
{resolveDisplayLabel(payload.actor, currentPubkey, profiles)}
</ProfileName>
@@ -566,7 +566,7 @@ function describeSystemEvent(
title: membershipTitle,
action: (
<>
was added by{" "}
added by{" "}
<ProfileName pubkey={payload.actor} underlineOnHover>
{resolveDisplayLabel(payload.actor, currentPubkey, profiles)}
</ProfileName>

View File

@@ -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);

View File

@@ -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",
);
}
},

View File

@@ -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"),
},
);
};

View File

@@ -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;

View File

@@ -464,14 +464,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]);
@@ -486,14 +486,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]);
@@ -505,11 +505,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]);
@@ -572,18 +572,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;
}
@@ -598,19 +598,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",
);
}
},
@@ -632,11 +632,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();

View File

@@ -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");
}
}

View File

@@ -667,7 +667,7 @@ function ProfilePrimaryActions({
followToggleMutation.mutate(pubkey, {
onError: (error) =>
toast.error(
`${isFollowing ? "Unfollow" : "Follow"} failed: ${error.message}`,
`Couldn't ${isFollowing ? "unfollow" : "follow"}: ${error.message}`,
),
});
};

View File

@@ -337,7 +337,7 @@ export function UserProfilePopover({
toast.error(
error instanceof Error
? error.message
: "Failed to open direct message.",
: "Couldn’t open direct message",
);
} finally {
if (isMountedRef.current) {
@@ -471,7 +471,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) {

View File

@@ -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",
);
},
},

View File

@@ -37,7 +37,7 @@ export function useAgentLifecycleActions({
if (managedAgent.backend.type === "local") {
clearActiveTurnsForAgentOnStop(managedAgent.pubkey);
}
toast.success(result.noticeMessage ?? `Stopped ${managedAgent.name}.`);
toast.success(result.noticeMessage ?? `Stopped ${managedAgent.name}`);
return;
}
@@ -47,12 +47,14 @@ export function useAgentLifecycleActions({
});
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",
);
}
}, [

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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]);

View File

@@ -339,13 +339,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.
@@ -585,7 +585,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);
},
@@ -600,7 +600,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) {

View File

@@ -190,10 +190,10 @@ export function ProjectIssueDetail({
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;
}

View File

@@ -702,14 +702,14 @@ export function ProjectPullRequestFilesChangedPanel({
setActiveAnchor(null);
toast.success(
decision === "request-changes"
? "Changes requested."
: "Line comment posted.",
? "Changes requested"
: "Line comment posted",
);
} catch (error) {
toast.error(
error instanceof Error
? error.message
: "Failed to post line comment.",
: "Failed to post line comment",
);
throw error;
}

View File

@@ -546,12 +546,12 @@ export function ProjectPullRequestDetail({
});
toast.success(
decision === "request-changes"
? "Changes requested."
: "Comment posted.",
? "Changes requested"
: "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;
}

View File

@@ -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);

View File

@@ -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");

View File

@@ -90,16 +90,16 @@ export function PullRequestReviewCard({
});
toast.success(
status === "draft"
? "Converted to draft."
? "Converted to draft"
: status === "closed"
? "Pull request closed."
? "Pull request closed"
: pullRequest.status === "Closed"
? "Pull request reopened."
: "Marked as ready for review.",
? "Pull request reopened"
: "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",
);
}
},
@@ -147,8 +147,8 @@ export function PullRequestReviewCard({
const handleApprove = React.useCallback(async () => {
const approved = await runReviewDecision(
approvePullRequest,
"Pull request approved.",
"Failed to approve.",
"Pull request approved",
"Failed to approve",
approvalSummary,
);
if (approved) {

View File

@@ -113,10 +113,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;

View File

@@ -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 },
);
}

View File

@@ -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",
);
}
},

View File

@@ -48,7 +48,7 @@ export function RemindMeLaterDialog({
onOpenChange(false);
setNote("");
},
onError: () => toast.error("Failed to create reminder"),
onError: () => toast.error("Couldn't create reminder"),
},
);
};

View File

@@ -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"),
});
};

View File

@@ -78,7 +78,7 @@ export function ChannelTemplatesSettingsCard() {
},
onError: (error) => {
toast.error(
error instanceof Error ? error.message : "Failed to duplicate",
error instanceof Error ? error.message : "Couldn't duplicate",
);
},
});
@@ -92,9 +92,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");
},
});
}
@@ -375,7 +373,7 @@ function TemplateFormDialog({
},
onError: (error) => {
toast.error(
error instanceof Error ? error.message : "Failed to update",
error instanceof Error ? error.message : "Couldn't update",
);
},
});
@@ -394,7 +392,7 @@ function TemplateFormDialog({
},
onError: (error) => {
toast.error(
error instanceof Error ? error.message : "Failed to create",
error instanceof Error ? error.message : "Couldn't create",
);
},
});

View File

@@ -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",
);
}
}

View File

@@ -123,7 +123,7 @@ export function SignOutSection() {
setIsPending(false);
setIsOpen(false);
resetDialogState();
toast.error(err instanceof Error ? err.message : "Sign out failed.");
toast.error(err instanceof Error ? err.message : "Couldn’t sign out");
});
}

View File

@@ -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");
});
}

View File

@@ -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(() => {});

View File

@@ -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");
});
},
},

View File

@@ -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);
}

View File

@@ -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);
},
);

View File

@@ -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",
);
});
},
});