mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-02 12:22:40 +02:00
Added chat renaming and auto naming by the active LLM
This commit is contained in:
parent
b176599c64
commit
d761ca1992
12 changed files with 287 additions and 36 deletions
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useAtomValue, useSetAtom } from "jotai";
|
||||
import { AlertTriangle, Inbox, LogOut, SquareLibrary, Trash2 } from "lucide-react";
|
||||
import { AlertTriangle, Inbox, LogOut, PencilIcon, SquareLibrary, Trash2 } from "lucide-react";
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useTheme } from "next-themes";
|
||||
|
|
@ -21,6 +21,7 @@ import {
|
|||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { isPageLimitExceededMetadata } from "@/contracts/types/inbox.types";
|
||||
import { useInbox } from "@/hooks/use-inbox";
|
||||
import { searchSpacesApiService } from "@/lib/apis/search-spaces-api.service";
|
||||
|
|
@ -207,6 +208,12 @@ export function LayoutDataProvider({
|
|||
const [chatToDelete, setChatToDelete] = useState<{ id: number; name: string } | null>(null);
|
||||
const [isDeletingChat, setIsDeletingChat] = useState(false);
|
||||
|
||||
// Rename dialog state
|
||||
const [showRenameChatDialog, setShowRenameChatDialog] = useState(false);
|
||||
const [chatToRename, setChatToRename] = useState<{ id: number; name: string } | null>(null);
|
||||
const [newChatTitle, setNewChatTitle] = useState("");
|
||||
const [isRenamingChat, setIsRenamingChat] = useState(false);
|
||||
|
||||
// Delete/Leave search space dialog state
|
||||
const [showDeleteSearchSpaceDialog, setShowDeleteSearchSpaceDialog] = useState(false);
|
||||
const [showLeaveSearchSpaceDialog, setShowLeaveSearchSpaceDialog] = useState(false);
|
||||
|
|
@ -421,6 +428,12 @@ export function LayoutDataProvider({
|
|||
setShowDeleteChatDialog(true);
|
||||
}, []);
|
||||
|
||||
const handleChatRename = useCallback((chat: ChatItem) => {
|
||||
setChatToRename({ id: chat.id, name: chat.name });
|
||||
setNewChatTitle(chat.name);
|
||||
setShowRenameChatDialog(true);
|
||||
}, []);
|
||||
|
||||
const handleChatArchive = useCallback(
|
||||
async (chat: ChatItem) => {
|
||||
const newArchivedState = !chat.archived;
|
||||
|
|
@ -501,6 +514,27 @@ export function LayoutDataProvider({
|
|||
}
|
||||
}, [chatToDelete, queryClient, searchSpaceId, router, currentChatId]);
|
||||
|
||||
// Rename handler
|
||||
const confirmRenameChat = useCallback(async () => {
|
||||
if (!chatToRename || !newChatTitle.trim()) return;
|
||||
setIsRenamingChat(true);
|
||||
try {
|
||||
await updateThread(chatToRename.id, { title: newChatTitle.trim() });
|
||||
toast.success(tSidebar("chat_renamed") || "Chat renamed");
|
||||
queryClient.invalidateQueries({ queryKey: ["threads", searchSpaceId] });
|
||||
queryClient.invalidateQueries({ queryKey: ["all-threads", searchSpaceId] });
|
||||
queryClient.invalidateQueries({ queryKey: ["search-threads", searchSpaceId] });
|
||||
} catch (error) {
|
||||
console.error("Error renaming thread:", error);
|
||||
toast.error(tSidebar("error_renaming_chat") || "Failed to rename chat");
|
||||
} finally {
|
||||
setIsRenamingChat(false);
|
||||
setShowRenameChatDialog(false);
|
||||
setChatToRename(null);
|
||||
setNewChatTitle("");
|
||||
}
|
||||
}, [chatToRename, newChatTitle, queryClient, searchSpaceId, tSidebar]);
|
||||
|
||||
// Page usage
|
||||
const pageUsage = user
|
||||
? {
|
||||
|
|
@ -529,6 +563,7 @@ export function LayoutDataProvider({
|
|||
activeChatId={currentChatId}
|
||||
onNewChat={handleNewChat}
|
||||
onChatSelect={handleChatSelect}
|
||||
onChatRename={handleChatRename}
|
||||
onChatDelete={handleChatDelete}
|
||||
onChatArchive={handleChatArchive}
|
||||
onViewAllSharedChats={handleViewAllSharedChats}
|
||||
|
|
@ -620,6 +655,57 @@ export function LayoutDataProvider({
|
|||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Rename Chat Dialog */}
|
||||
<Dialog open={showRenameChatDialog} onOpenChange={setShowRenameChatDialog}>
|
||||
<DialogContent className="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<PencilIcon className="h-5 w-5" />
|
||||
<span>{tSidebar("rename_chat") || "Rename Chat"}</span>
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
{tSidebar("rename_chat_description") || "Enter a new name for this conversation."}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Input
|
||||
value={newChatTitle}
|
||||
onChange={(e) => setNewChatTitle(e.target.value)}
|
||||
placeholder={tSidebar("chat_title_placeholder") || "Chat title"}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" && !isRenamingChat && newChatTitle.trim()) {
|
||||
confirmRenameChat();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<DialogFooter className="flex gap-2 sm:justify-end">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setShowRenameChatDialog(false)}
|
||||
disabled={isRenamingChat}
|
||||
>
|
||||
{tCommon("cancel")}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={confirmRenameChat}
|
||||
disabled={isRenamingChat || !newChatTitle.trim()}
|
||||
className="gap-2"
|
||||
>
|
||||
{isRenamingChat ? (
|
||||
<>
|
||||
<span className="h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" />
|
||||
{tSidebar("renaming") || "Renaming..."}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<PencilIcon className="h-4 w-4" />
|
||||
{tSidebar("rename") || "Rename"}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Delete Search Space Dialog */}
|
||||
<Dialog open={showDeleteSearchSpaceDialog} onOpenChange={setShowDeleteSearchSpaceDialog}>
|
||||
<DialogContent className="sm:max-w-md">
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ interface LayoutShellProps {
|
|||
activeChatId?: number | null;
|
||||
onNewChat: () => void;
|
||||
onChatSelect: (chat: ChatItem) => void;
|
||||
onChatRename?: (chat: ChatItem) => void;
|
||||
onChatDelete?: (chat: ChatItem) => void;
|
||||
onChatArchive?: (chat: ChatItem) => void;
|
||||
onViewAllSharedChats?: () => void;
|
||||
|
|
@ -90,6 +91,7 @@ export function LayoutShell({
|
|||
activeChatId,
|
||||
onNewChat,
|
||||
onChatSelect,
|
||||
onChatRename,
|
||||
onChatDelete,
|
||||
onChatArchive,
|
||||
onViewAllSharedChats,
|
||||
|
|
@ -147,6 +149,7 @@ export function LayoutShell({
|
|||
activeChatId={activeChatId}
|
||||
onNewChat={onNewChat}
|
||||
onChatSelect={onChatSelect}
|
||||
onChatRename={onChatRename}
|
||||
onChatDelete={onChatDelete}
|
||||
onChatArchive={onChatArchive}
|
||||
onViewAllSharedChats={onViewAllSharedChats}
|
||||
|
|
@ -215,6 +218,7 @@ export function LayoutShell({
|
|||
activeChatId={activeChatId}
|
||||
onNewChat={onNewChat}
|
||||
onChatSelect={onChatSelect}
|
||||
onChatRename={onChatRename}
|
||||
onChatDelete={onChatDelete}
|
||||
onChatArchive={onChatArchive}
|
||||
onViewAllSharedChats={onViewAllSharedChats}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { ArchiveIcon, MessageSquare, MoreHorizontal, RotateCcwIcon, Trash2 } from "lucide-react";
|
||||
import { ArchiveIcon, MessageSquare, MoreHorizontal, PencilIcon, RotateCcwIcon, Trash2 } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
|
|
@ -17,6 +17,7 @@ interface ChatListItemProps {
|
|||
isActive?: boolean;
|
||||
archived?: boolean;
|
||||
onClick?: () => void;
|
||||
onRename?: () => void;
|
||||
onArchive?: () => void;
|
||||
onDelete?: () => void;
|
||||
}
|
||||
|
|
@ -26,6 +27,7 @@ export function ChatListItem({
|
|||
isActive,
|
||||
archived,
|
||||
onClick,
|
||||
onRename,
|
||||
onArchive,
|
||||
onDelete,
|
||||
}: ChatListItemProps) {
|
||||
|
|
@ -57,15 +59,26 @@ export function ChatListItem({
|
|||
<span className="sr-only">{t("more_options")}</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" side="right">
|
||||
{onArchive && (
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onArchive();
|
||||
}}
|
||||
>
|
||||
{archived ? (
|
||||
<DropdownMenuContent align="end" side="right">
|
||||
{onRename && (
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onRename();
|
||||
}}
|
||||
>
|
||||
<PencilIcon className="mr-2 h-4 w-4" />
|
||||
<span>{t("rename") || "Rename"}</span>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{onArchive && (
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onArchive();
|
||||
}}
|
||||
>
|
||||
{archived ? (
|
||||
<>
|
||||
<RotateCcwIcon className="mr-2 h-4 w-4" />
|
||||
<span>{t("unarchive") || "Restore"}</span>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ interface MobileSidebarProps {
|
|||
activeChatId?: number | null;
|
||||
onNewChat: () => void;
|
||||
onChatSelect: (chat: ChatItem) => void;
|
||||
onChatRename?: (chat: ChatItem) => void;
|
||||
onChatDelete?: (chat: ChatItem) => void;
|
||||
onChatArchive?: (chat: ChatItem) => void;
|
||||
onViewAllSharedChats?: () => void;
|
||||
|
|
@ -64,6 +65,7 @@ export function MobileSidebar({
|
|||
activeChatId,
|
||||
onNewChat,
|
||||
onChatSelect,
|
||||
onChatRename,
|
||||
onChatDelete,
|
||||
onChatArchive,
|
||||
onViewAllSharedChats,
|
||||
|
|
@ -142,6 +144,7 @@ export function MobileSidebar({
|
|||
onOpenChange(false);
|
||||
}}
|
||||
onChatSelect={handleChatSelect}
|
||||
onChatRename={onChatRename}
|
||||
onChatDelete={onChatDelete}
|
||||
onChatArchive={onChatArchive}
|
||||
onViewAllSharedChats={onViewAllSharedChats}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ interface SidebarProps {
|
|||
activeChatId?: number | null;
|
||||
onNewChat: () => void;
|
||||
onChatSelect: (chat: ChatItem) => void;
|
||||
onChatRename?: (chat: ChatItem) => void;
|
||||
onChatDelete?: (chat: ChatItem) => void;
|
||||
onChatArchive?: (chat: ChatItem) => void;
|
||||
onViewAllSharedChats?: () => void;
|
||||
|
|
@ -51,6 +52,7 @@ export function Sidebar({
|
|||
activeChatId,
|
||||
onNewChat,
|
||||
onChatSelect,
|
||||
onChatRename,
|
||||
onChatDelete,
|
||||
onChatArchive,
|
||||
onViewAllSharedChats,
|
||||
|
|
@ -163,6 +165,7 @@ export function Sidebar({
|
|||
isActive={chat.id === activeChatId}
|
||||
archived={chat.archived}
|
||||
onClick={() => onChatSelect(chat)}
|
||||
onRename={() => onChatRename?.(chat)}
|
||||
onArchive={() => onChatArchive?.(chat)}
|
||||
onDelete={() => onChatDelete?.(chat)}
|
||||
/>
|
||||
|
|
@ -215,6 +218,7 @@ export function Sidebar({
|
|||
isActive={chat.id === activeChatId}
|
||||
archived={chat.archived}
|
||||
onClick={() => onChatSelect(chat)}
|
||||
onRename={() => onChatRename?.(chat)}
|
||||
onArchive={() => onChatArchive?.(chat)}
|
||||
onDelete={() => onChatDelete?.(chat)}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue