From bdadbc907ebc5dd9e1851c9064b0ba5818c0e233 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 10 Jun 2026 00:10:03 +0000 Subject: [PATCH 1/4] Remove legacy KV chat archive UI --- frontend/src/components/AccountMenu.tsx | 14 - frontend/src/components/ChatHistoryList.tsx | 276 ++------------ frontend/src/components/UnifiedChat.tsx | 22 -- frontend/src/routeTree.gen.ts | 45 --- frontend/src/routes/_auth.chat.$chatId.tsx | 380 -------------------- frontend/src/routes/_auth.tsx | 24 -- frontend/src/state/LocalStateContext.tsx | 202 +---------- frontend/src/state/LocalStateContextDef.ts | 30 -- 8 files changed, 34 insertions(+), 959 deletions(-) delete mode 100644 frontend/src/routes/_auth.chat.$chatId.tsx delete mode 100644 frontend/src/routes/_auth.tsx diff --git a/frontend/src/components/AccountMenu.tsx b/frontend/src/components/AccountMenu.tsx index 5a64ac458..a7a387a06 100644 --- a/frontend/src/components/AccountMenu.tsx +++ b/frontend/src/components/AccountMenu.tsx @@ -56,24 +56,12 @@ import packageJson from "../../package.json"; import { SIDEBAR_ACCOUNT_MENU_WIDTH_CLASS, SIDEBAR_LAYOUT_STYLE } from "@/constants/layout"; function ConfirmDeleteDialog() { - const { clearHistory } = useLocalState(); const os = useOpenSecret(); const queryClient = useQueryClient(); const navigate = useNavigate(); async function handleDeleteHistory() { - // 1. Delete archived chats (KV) try { - await clearHistory(); - console.log("History (KV) cleared"); - } catch (error) { - console.error("Error clearing history:", error); - // Continue to delete server conversations even if this fails - } - - // 2. Delete server conversations (API) if any exist - try { - // Check if we have any conversations to delete const conversations = await os.listConversations({ limit: 1 }); if (conversations.data && conversations.data.length > 0) { await os.deleteConversations(); @@ -84,9 +72,7 @@ function ConfirmDeleteDialog() { } // Always refresh UI and navigate home - queryClient.invalidateQueries({ queryKey: ["chatHistory"] }); queryClient.invalidateQueries({ queryKey: ["conversations"] }); - queryClient.invalidateQueries({ queryKey: ["archivedChats"] }); navigate({ to: "/" }); } diff --git a/frontend/src/components/ChatHistoryList.tsx b/frontend/src/components/ChatHistoryList.tsx index 36793387c..860636875 100644 --- a/frontend/src/components/ChatHistoryList.tsx +++ b/frontend/src/components/ChatHistoryList.tsx @@ -70,13 +70,6 @@ interface ChatHistoryListProps { containerRef?: React.RefObject; } -interface ArchivedChat { - id: string; - title: string; - updated_at: number; - created_at: number; -} - export function ChatHistoryList({ currentChatId, searchQuery = "", @@ -105,7 +98,6 @@ export function ChatHistoryList({ const [selectedChat, setSelectedChat] = useState<{ id: string; title: string } | null>(null); const [selectedProject, setSelectedProject] = useState(null); const [expandedProjectId, setExpandedProjectId] = useState(selectedProjectId); - const [isArchivedExpanded, setIsArchivedExpanded] = useState(false); const longPressTimerRef = useRef | null>(null); // Pagination states @@ -509,30 +501,6 @@ export function ChatHistoryList({ }; }, [hasMoreConversations, isLoadingMore, loadMoreConversations]); - // Fetch archived chats from KV store - const { data: archivedChats } = useQuery({ - queryKey: ["archivedChats"], - queryFn: async () => { - if (!opensecret?.get) return []; - - try { - const historyListStr = await opensecret.get("history_list"); - if (!historyListStr) return []; - - const historyList = JSON.parse(historyListStr) as ArchivedChat[]; - if (!Array.isArray(historyList)) return []; - - // Sort by updated_at descending (most recent first) - return historyList.sort((a, b) => (b.updated_at || 0) - (a.updated_at || 0)); - } catch (error) { - console.error("Error loading archived chats:", error); - return []; - } - }, - enabled: !!opensecret?.get, - retry: false - }); - const { data: conversationProjects = [] } = useQuery({ queryKey: ["conversationProjects", userId], queryFn: () => listAllConversationProjects(opensecret), @@ -639,21 +607,6 @@ export function ChatHistoryList({ ); }, [conversations, getConversationTitle, normalizedQuery]); - // Filter archived chats based on search query - const filteredArchivedChats = useMemo(() => { - if (!archivedChats) return []; - if (!normalizedQuery) return archivedChats; - - return archivedChats.filter((chat) => chat.title.toLowerCase().includes(normalizedQuery)); - }, [archivedChats, normalizedQuery]); - - // Auto-expand archived section when searching with results - useEffect(() => { - if (normalizedQuery && filteredArchivedChats.length > 0) { - setIsArchivedExpanded(true); - } - }, [normalizedQuery, filteredArchivedChats.length]); - const dispatchConversationMetadataUpdated = useCallback( (conversationId: string, updates: Record) => { window.dispatchEvent( @@ -668,48 +621,22 @@ export function ChatHistoryList({ // Handle conversation deletion via API const handleDeleteConversation = useCallback( async (conversationId: string) => { - const isArchived = archivedChats?.some((chat) => chat.id === conversationId); - - if (isArchived) { - if (!localState?.deleteChat) return; - try { - await localState.deleteChat(conversationId); - await queryClient.invalidateQueries({ queryKey: ["archivedChats"] }); + try { + await opensecret.deleteConversation(conversationId); + setConversations((prev) => prev.filter((conv) => conv.id !== conversationId)); + await invalidateConversationData(); - if (conversationId === currentChatId) { - router.navigate({ to: "/" }); - setSelectedProjectId(null); - } - } catch (error) { - console.error("Error deleting archived chat:", error); - } - } else { - try { - await opensecret.deleteConversation(conversationId); - setConversations((prev) => prev.filter((conv) => conv.id !== conversationId)); - await invalidateConversationData(); - - if (conversationId === currentChatId) { - const params = new URLSearchParams(window.location.search); - params.delete("conversation_id"); - window.history.replaceState({}, "", params.toString() ? `/?${params}` : "/"); - window.dispatchEvent(new Event("newchat")); - } - } catch (error) { - console.error("Error deleting conversation:", error); + if (conversationId === currentChatId) { + const params = new URLSearchParams(window.location.search); + params.delete("conversation_id"); + window.history.replaceState({}, "", params.toString() ? `/?${params}` : "/"); + window.dispatchEvent(new Event("newchat")); } + } catch (error) { + console.error("Error deleting conversation:", error); } }, - [ - archivedChats, - currentChatId, - invalidateConversationData, - localState, - opensecret, - queryClient, - router, - setSelectedProjectId - ] + [currentChatId, invalidateConversationData, opensecret] ); const MAX_SELECTION = 20; @@ -740,15 +667,8 @@ export function ChatHistoryList({ try { const idsToDelete = Array.from(selectedIds); - // Separate archived chats from API conversations - const archivedIds = idsToDelete.filter((id) => archivedChats?.some((chat) => chat.id === id)); - const conversationIds = idsToDelete.filter( - (id) => !archivedChats?.some((chat) => chat.id === id) - ); - - // Delete API conversations using batch delete - if (conversationIds.length > 0 && opensecret) { - const result = await opensecret.batchDeleteConversations(conversationIds); + if (opensecret) { + const result = await opensecret.batchDeleteConversations(idsToDelete); const deletedIds = new Set( result.data.filter((item) => item.deleted).map((item) => item.id) @@ -757,18 +677,6 @@ export function ChatHistoryList({ await invalidateConversationData(); } - // Delete archived chats individually - for (const id of archivedIds) { - if (localState?.deleteChat) { - await localState.deleteChat(id); - } - } - - // Refresh archived chats if any were deleted - if (archivedIds.length > 0) { - queryClient.invalidateQueries({ queryKey: ["archivedChats"] }); - } - // If current chat was deleted, navigate to home if (selectedIds.has(currentChatId || "")) { const params = new URLSearchParams(window.location.search); @@ -788,11 +696,8 @@ export function ChatHistoryList({ } }, [ selectedIds, - archivedChats, opensecret, invalidateConversationData, - localState, - queryClient, currentChatId, onSelectionChange, onExitSelectionMode @@ -1017,11 +922,6 @@ export function ChatHistoryList({ [getConversationTitle] ); - const handleOpenRenameDialogArchived = useCallback((chat: ArchivedChat) => { - setSelectedChat({ id: chat.id, title: chat.title }); - setIsRenameDialogOpen(true); - }, []); - const handleOpenDeleteDialog = useCallback( (conv: Conversation) => { setSelectedChat({ id: conv.id, title: getConversationTitle(conv) }); @@ -1030,11 +930,6 @@ export function ChatHistoryList({ [getConversationTitle] ); - const handleOpenDeleteDialogArchived = useCallback((chat: ArchivedChat) => { - setSelectedChat({ id: chat.id, title: chat.title }); - setIsDeleteDialogOpen(true); - }, []); - const handleOpenCreateProjectDialog = useCallback(() => { setSelectedProject(null); setProjectDialogMode("create"); @@ -1055,45 +950,25 @@ export function ChatHistoryList({ // Handle conversation renaming via API const handleRenameConversation = useCallback( async (conversationId: string, newTitle: string) => { - const isArchived = archivedChats?.some((chat) => chat.id === conversationId); - - if (isArchived) { - if (!localState?.renameChat) return; - try { - await localState.renameChat(conversationId, newTitle); - await queryClient.invalidateQueries({ queryKey: ["archivedChats"] }); - } catch (error) { - console.error("Error renaming archived chat:", error); - throw error; - } - } else { - try { - await opensecret.updateConversation(conversationId, { title: newTitle }); - setConversations((prev) => - prev.map((conv) => - conv.id === conversationId - ? { ...conv, metadata: { ...(conv.metadata ?? {}), title: newTitle } } - : conv - ) - ); - await invalidateConversationData(); - dispatchConversationMetadataUpdated(conversationId, { - metadata: { title: newTitle } - }); - } catch (error) { - console.error("Error renaming conversation:", error); - throw error; - } + try { + await opensecret.updateConversation(conversationId, { title: newTitle }); + setConversations((prev) => + prev.map((conv) => + conv.id === conversationId + ? { ...conv, metadata: { ...(conv.metadata ?? {}), title: newTitle } } + : conv + ) + ); + await invalidateConversationData(); + dispatchConversationMetadataUpdated(conversationId, { + metadata: { title: newTitle } + }); + } catch (error) { + console.error("Error renaming conversation:", error); + throw error; } }, - [ - archivedChats, - dispatchConversationMetadataUpdated, - invalidateConversationData, - localState, - opensecret, - queryClient - ] + [dispatchConversationMetadataUpdated, invalidateConversationData, opensecret] ); // Handle conversation selection @@ -1145,8 +1020,7 @@ export function ChatHistoryList({ filteredProjects.length === 0 && filteredExpandedProjectConversations.length === 0 && filteredPinnedConversations.length === 0 && - filteredRecentConversations.length === 0 && - filteredArchivedChats.length === 0 + filteredRecentConversations.length === 0 ) { return (
@@ -1450,92 +1324,6 @@ export function ChatHistoryList({
)} - {filteredArchivedChats && filteredArchivedChats.length > 0 && ( -
- - - {isArchivedExpanded && ( -
- {filteredArchivedChats.map((chat) => { - const isActive = chat.id === currentChatId; - const archivedTitlePaddingClass = "pr-8"; - return ( -
-
{ - setSelectedProjectId(null); - router.navigate({ to: "/chat/$chatId", params: { chatId: chat.id } }); - }} - className={`relative ${ROW_CONTENT_Z} min-w-0 flex-1 cursor-pointer py-1 pl-0 pr-2 ${ - isActive - ? "font-bold text-foreground" - : "text-foreground/95 group-hover:text-foreground" - }`} - > -
-
- {chat.title} -
-
-
- {new Date(chat.updated_at || chat.created_at).toLocaleDateString()} -
-
-
- -
- ); - })} -
- )} -
- )} - {!trimmedQuery && hasMoreConversations ? (