mirror of
https://github.com/block/buzz.git
synced 2026-11-02 15:31:27 +00:00
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:
@@ -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}`,
|
||||
),
|
||||
});
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
>
|
||||
|
||||
@@ -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],
|
||||
);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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`,
|
||||
)
|
||||
}
|
||||
>
|
||||
|
||||
@@ -75,7 +75,7 @@ export function ConfirmRemoveDialog({
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Failed to remove member",
|
||||
: "Couldn't remove member",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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)}`,
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}`);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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"),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}`,
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
}
|
||||
}, [
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -48,7 +48,7 @@ export function RemindMeLaterDialog({
|
||||
onOpenChange(false);
|
||||
setNote("");
|
||||
},
|
||||
onError: () => toast.error("Failed to create reminder"),
|
||||
onError: () => toast.error("Couldn't create reminder"),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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"),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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(() => {});
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user