Unverified 提交 633baeff authored 作者: Will Chen's avatar Will Chen 提交者: GitHub

Add "Start new chat" button to error box for Dyad Pro users (#2494)

## Summary Added a "Start new chat" button to the ChatErrorBox component that appears for Dyad Pro enabled users. This provides a quick way to recover from certain chat errors by creating a fresh conversation. ## Key Changes - **ChatErrorBox.tsx**: - Added `MessageSquarePlus` icon import from lucide-react - Imported Tooltip components for better UX - Added `onStartNewChat` optional callback prop - Rendered a new "Start new chat" button with tooltip when Dyad Pro is enabled and callback is provided - **ChatInput.tsx**: - Imported `useChats`, `useRouter`, and toast utilities - Added `handleNewChat` function that: - Creates a new chat via IPC - Updates the selected chat ID atom - Navigates to the new chat - Invalidates the chats cache - Shows error toast on failure - Passed `handleNewChat` to ChatErrorBox's `onStartNewChat` prop ## Implementation Details - The button only appears when both `isDyadProEnabled` is true AND `onStartNewChat` callback is provided - Includes a helpful tooltip: "Starting a new chat can fix some issues" - Styled consistently with existing UI (blue-600 background, white text, hover effects) - Gracefully handles errors during chat creation with user-facing toast notifications - Falls back to home page navigation if appId is unavailable https://claude.ai/code/session_016vbjv8b4hs5fG52yKHv4oZ <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/dyad-sh/dyad/pull/2494"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds a “Start new chat” button to the chat error box for Dyad Pro users to quickly recover from errors. Clicking it creates a fresh chat, navigates to it, refreshes the chat list, and handles failures gracefully. - **New Features** - Button shows only when Dyad Pro is enabled and a callback is provided. - Creates a new chat via IPC, selects it, navigates to /chat, and invalidates the chats cache. - Includes a tooltip (“Starting a new chat can fix some issues”); shows a toast on failure and falls back to home if no appId. <sup>Written for commit f71be0aa8c08cdd258bc59daa21939cf91528c62. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk UI/UX change that wires an extra navigation/mutation path (IPC chat creation + query invalidation) behind an error-state button for Pro users. > > **Overview** > Adds a Pro-only recovery action in `ChatErrorBox`: a new **“Start new chat”** button (with tooltip) shown only when `isDyadProEnabled` and an `onStartNewChat` callback are provided. > > Wires this action from `ChatInput` via a new `handleNewChat` flow that creates a chat over IPC, updates the selected chat atom, navigates to the new chat route, invalidates the chats cache, and shows a toast if creation fails (fallback navigation to `/` when no `appId`). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f71be0aa8c08cdd258bc59daa21939cf91528c62. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: 's avatarClaude <noreply@anthropic.com>
上级 a410ecc3
...@@ -4,18 +4,26 @@ import { ...@@ -4,18 +4,26 @@ import {
X, X,
ExternalLink as ExternalLinkIcon, ExternalLink as ExternalLinkIcon,
CircleArrowUp, CircleArrowUp,
MessageSquarePlus,
} from "lucide-react"; } from "lucide-react";
import ReactMarkdown from "react-markdown"; import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm"; import remarkGfm from "remark-gfm";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
export function ChatErrorBox({ export function ChatErrorBox({
onDismiss, onDismiss,
error, error,
isDyadProEnabled, isDyadProEnabled,
onStartNewChat,
}: { }: {
onDismiss: () => void; onDismiss: () => void;
error: string; error: string;
isDyadProEnabled: boolean; isDyadProEnabled: boolean;
onStartNewChat?: () => void;
}) { }) {
if (error.includes("doesn't have a free quota tier")) { if (error.includes("doesn't have a free quota tier")) {
return ( return (
...@@ -138,6 +146,22 @@ export function ChatErrorBox({ ...@@ -138,6 +146,22 @@ export function ChatErrorBox({
Upgrade to Dyad Pro Upgrade to Dyad Pro
</ExternalLink> </ExternalLink>
)} )}
{isDyadProEnabled && onStartNewChat && (
<Tooltip>
<TooltipTrigger asChild>
<button
onClick={onStartNewChat}
className="cursor-pointer inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium shadow-sm focus:outline-none focus:ring-2 bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500"
>
<span>Start new chat</span>
<MessageSquarePlus size={18} />
</button>
</TooltipTrigger>
<TooltipContent>
Starting a new chat can fix some issues
</TooltipContent>
</Tooltip>
)}
<ExternalLink href="https://www.dyad.sh/docs/faq"> <ExternalLink href="https://www.dyad.sh/docs/faq">
Read docs Read docs
</ExternalLink> </ExternalLink>
......
...@@ -80,6 +80,9 @@ import { ...@@ -80,6 +80,9 @@ import {
shouldShowContextLimitBanner, shouldShowContextLimitBanner,
} from "./ContextLimitBanner"; } from "./ContextLimitBanner";
import { useCountTokens } from "@/hooks/useCountTokens"; import { useCountTokens } from "@/hooks/useCountTokens";
import { useChats } from "@/hooks/useChats";
import { useRouter } from "@tanstack/react-router";
import { showError as showErrorToast } from "@/lib/toast";
const showTokenBarAtom = atom(false); const showTokenBarAtom = atom(false);
...@@ -128,6 +131,9 @@ export function ChatInput({ chatId }: { chatId?: number }) { ...@@ -128,6 +131,9 @@ export function ChatInput({ chatId }: { chatId?: number }) {
const chatTodos = chatId ? (agentTodosByChatId.get(chatId) ?? []) : []; const chatTodos = chatId ? (agentTodosByChatId.get(chatId) ?? []) : [];
const { checkProblems } = useCheckProblems(appId); const { checkProblems } = useCheckProblems(appId);
const { refreshAppIframe } = useRunApp(); const { refreshAppIframe } = useRunApp();
const { navigate } = useRouter();
const setSelectedChatId = useSetAtom(selectedChatIdAtom);
const { invalidateChats } = useChats(appId);
// Use the attachments hook // Use the attachments hook
const { const {
attachments, attachments,
...@@ -254,6 +260,26 @@ export function ChatInput({ chatId }: { chatId?: number }) { ...@@ -254,6 +260,26 @@ export function ChatInput({ chatId }: { chatId?: number }) {
setShowError(false); setShowError(false);
}; };
const handleNewChat = async () => {
if (appId) {
try {
const newChatId = await ipc.chat.createChat(appId);
setSelectedChatId(newChatId);
navigate({
to: "/chat",
search: { id: newChatId },
});
await invalidateChats();
} catch (err) {
showErrorToast(
`Failed to create new chat: ${(err as Error).toString()}`,
);
}
} else {
navigate({ to: "/" });
}
};
const handleApprove = async () => { const handleApprove = async () => {
if (!chatId || !messageId || isApproving || isRejecting || isStreaming) if (!chatId || !messageId || isApproving || isRejecting || isStreaming)
return; return;
...@@ -328,6 +354,7 @@ export function ChatInput({ chatId }: { chatId?: number }) { ...@@ -328,6 +354,7 @@ export function ChatInput({ chatId }: { chatId?: number }) {
onDismiss={dismissError} onDismiss={dismissError}
error={error} error={error}
isDyadProEnabled={settings.enableDyadPro ?? false} isDyadProEnabled={settings.enableDyadPro ?? false}
onStartNewChat={handleNewChat}
/> />
)} )}
{/* Display loading or error state for proposal */} {/* Display loading or error state for proposal */}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论