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

Rename chat (#673)

Fixes #102
上级 c5fdbeb9
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
interface DeleteChatDialogProps {
isOpen: boolean;
onOpenChange: (open: boolean) => void;
onConfirmDelete: () => void;
chatTitle?: string;
}
export function DeleteChatDialog({
isOpen,
onOpenChange,
onConfirmDelete,
chatTitle,
}: DeleteChatDialogProps) {
return (
<AlertDialog open={isOpen} onOpenChange={onOpenChange}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete Chat</AlertDialogTitle>
<AlertDialogDescription>
Are you sure you want to delete "{chatTitle || "this chat"}"? This
action cannot be undone and all messages in this chat will be
permanently lost.
<br />
<br />
<strong>Note:</strong> Any code changes that have already been
accepted will be kept.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={onConfirmDelete}
className="bg-red-600 text-white hover:bg-red-700 dark:bg-red-600 dark:text-white dark:hover:bg-red-700"
>
Delete Chat
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
import { useState } from "react";
import { IpcClient } from "@/ipc/ipc_client";
import { showError, showSuccess } from "@/lib/toast";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
interface RenameChatDialogProps {
chatId: number;
currentTitle: string;
isOpen: boolean;
onOpenChange: (open: boolean) => void;
onRename: () => void;
}
export function RenameChatDialog({
chatId,
currentTitle,
isOpen,
onOpenChange,
onRename,
}: RenameChatDialogProps) {
const [newTitle, setNewTitle] = useState("");
// Reset title when dialog opens
const handleOpenChange = (open: boolean) => {
if (open) {
setNewTitle(currentTitle || "");
} else {
setNewTitle("");
}
onOpenChange(open);
};
const handleSave = async () => {
if (!newTitle.trim()) {
return;
}
try {
await IpcClient.getInstance().updateChat({
chatId,
title: newTitle.trim(),
});
showSuccess("Chat renamed successfully");
// Call the parent's onRename callback to refresh the chat list
onRename();
// Close the dialog
handleOpenChange(false);
} catch (error) {
showError(`Failed to rename chat: ${(error as any).toString()}`);
}
};
const handleClose = () => {
handleOpenChange(false);
};
return (
<Dialog open={isOpen} onOpenChange={handleOpenChange}>
<DialogContent>
<DialogHeader>
<DialogTitle>Rename Chat</DialogTitle>
<DialogDescription>Enter a new name for this chat.</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="chat-title" className="text-right">
Title
</Label>
<Input
id="chat-title"
value={newTitle}
onChange={(e) => setNewTitle(e.target.value)}
className="col-span-3"
placeholder="Enter chat title..."
onKeyDown={(e) => {
if (e.key === "Enter") {
handleSave();
}
}}
/>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={handleClose}>
Cancel
</Button>
<Button onClick={handleSave} disabled={!newTitle.trim()}>
Save
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
......@@ -9,6 +9,7 @@ import { createLoggedHandler } from "./safe_handle";
import log from "electron-log";
import { getDyadAppPath } from "../../paths/paths";
import { UpdateChatParams } from "../ipc_types";
const logger = log.scope("chat_handlers");
const handle = createLoggedHandler(logger);
......@@ -107,6 +108,10 @@ export function registerChatHandlers() {
await db.delete(chats).where(eq(chats.id, chatId));
});
handle("update-chat", async (_, { chatId, title }: UpdateChatParams) => {
await db.update(chats).set({ title }).where(eq(chats.id, chatId));
});
handle("delete-messages", async (_, chatId: number): Promise<void> => {
await db.delete(messages).where(eq(messages.chatId, chatId));
});
......
......@@ -49,6 +49,7 @@ import type {
IsVercelProjectAvailableParams,
SaveVercelAccessTokenParams,
VercelProject,
UpdateChatParams,
} from "./ipc_types";
import type { AppChatContext, ProposalResult } from "@/lib/schemas";
import { showError } from "@/lib/toast";
......@@ -351,6 +352,10 @@ export class IpcClient {
return this.ipcRenderer.invoke("create-chat", appId);
}
public async updateChat(params: UpdateChatParams): Promise<void> {
return this.ipcRenderer.invoke("update-chat", params);
}
public async deleteChat(chatId: number): Promise<void> {
await this.ipcRenderer.invoke("delete-chat", chatId);
}
......
......@@ -316,3 +316,8 @@ export interface VercelProject {
name: string;
framework: string | null;
}
export interface UpdateChatParams {
chatId: number;
title: string;
}
......@@ -79,6 +79,7 @@ const validInvokeChannels = [
"get-system-platform",
"upload-to-signed-url",
"delete-chat",
"update-chat",
"delete-messages",
"start-chat-stream",
"does-release-note-exist",
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论