diff --git a/surfsense_web/components/layout/index.ts b/surfsense_web/components/layout/index.ts index 18f8cc9d3..57b675088 100644 --- a/surfsense_web/components/layout/index.ts +++ b/surfsense_web/components/layout/index.ts @@ -4,7 +4,6 @@ export type { ChatItem, IconRailProps, NavItem, - NoteItem, PageUsage, SearchSpace, SidebarSectionProps, @@ -21,7 +20,6 @@ export { MobileSidebarTrigger, NavIcon, NavSection, - NoteListItem, PageUsageDisplay, SearchSpaceAvatar, Sidebar, diff --git a/surfsense_web/components/layout/providers/LayoutDataProvider.tsx b/surfsense_web/components/layout/providers/LayoutDataProvider.tsx index 135a3d445..7b4159b13 100644 --- a/surfsense_web/components/layout/providers/LayoutDataProvider.tsx +++ b/surfsense_web/components/layout/providers/LayoutDataProvider.tsx @@ -1,7 +1,7 @@ "use client"; import { useQuery, useQueryClient } from "@tanstack/react-query"; -import { useAtomValue, useSetAtom } from "jotai"; +import { useAtomValue } from "jotai"; import { Logs, SquareLibrary, Trash2 } from "lucide-react"; import { useParams, usePathname, useRouter } from "next/navigation"; import { useTranslations } from "next-intl"; diff --git a/surfsense_web/components/layout/types/layout.types.ts b/surfsense_web/components/layout/types/layout.types.ts index f8d06ab73..51b06daa3 100644 --- a/surfsense_web/components/layout/types/layout.types.ts +++ b/surfsense_web/components/layout/types/layout.types.ts @@ -31,14 +31,6 @@ export interface ChatItem { isOwnThread?: boolean; } -export interface NoteItem { - id: number; - name: string; - url: string; - isActive?: boolean; - isReindexing?: boolean; -} - export interface PageUsage { pagesUsed: number; pagesLimit: number; @@ -74,7 +66,8 @@ export interface ChatsSectionProps { activeChatId?: number | null; onChatSelect: (chat: ChatItem) => void; onChatDelete?: (chat: ChatItem) => void; - onViewAllChats?: () => void; + onViewAllSharedChats?: () => void; + onViewAllPrivateChats?: () => void; searchSpaceId?: string; } @@ -104,7 +97,8 @@ export interface SidebarProps { onNewChat: () => void; onChatSelect: (chat: ChatItem) => void; onChatDelete?: (chat: ChatItem) => void; - onViewAllChats?: () => void; + onViewAllSharedChats?: () => void; + onViewAllPrivateChats?: () => void; user: User; theme?: string; onSettings?: () => void; diff --git a/surfsense_web/components/layout/ui/index.ts b/surfsense_web/components/layout/ui/index.ts index bd3d54838..875e3b746 100644 --- a/surfsense_web/components/layout/ui/index.ts +++ b/surfsense_web/components/layout/ui/index.ts @@ -8,7 +8,6 @@ export { MobileSidebar, MobileSidebarTrigger, NavSection, - NoteListItem, PageUsageDisplay, Sidebar, SidebarCollapseButton, diff --git a/surfsense_web/components/layout/ui/sidebar/AllChatsSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/AllChatsSidebar.tsx deleted file mode 100644 index 4b85808e5..000000000 --- a/surfsense_web/components/layout/ui/sidebar/AllChatsSidebar.tsx +++ /dev/null @@ -1,488 +0,0 @@ -"use client"; - -import { useQuery, useQueryClient } from "@tanstack/react-query"; -import { format } from "date-fns"; -import { - ArchiveIcon, - Globe, - Loader2, - Lock, - MessageCircleMore, - MoreHorizontal, - RotateCcwIcon, - Search, - Trash2, - Users, - X, -} from "lucide-react"; -import { AnimatePresence, motion } from "motion/react"; -import { useParams, useRouter } from "next/navigation"; -import { useTranslations } from "next-intl"; -import { useCallback, useEffect, useMemo, useState } from "react"; -import { createPortal } from "react-dom"; -import { toast } from "sonner"; -import { Button } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { Input } from "@/components/ui/input"; -import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; -import { useDebouncedValue } from "@/hooks/use-debounced-value"; -import { - deleteThread, - fetchThreads, - searchThreads, - type ThreadListItem, - updateThread, -} from "@/lib/chat/thread-persistence"; -import { cn } from "@/lib/utils"; - -type TabType = "shared" | "private"; - -interface AllChatsSidebarProps { - open: boolean; - onOpenChange: (open: boolean) => void; - searchSpaceId: string; - onCloseMobileSidebar?: () => void; -} - -export function AllChatsSidebar({ - open, - onOpenChange, - searchSpaceId, - onCloseMobileSidebar, -}: AllChatsSidebarProps) { - const t = useTranslations("sidebar"); - const router = useRouter(); - const params = useParams(); - const queryClient = useQueryClient(); - - // Get the current chat ID from URL to check if user is deleting the currently open chat - const currentChatId = Array.isArray(params.chat_id) - ? Number(params.chat_id[0]) - : params.chat_id - ? Number(params.chat_id) - : null; - const [deletingThreadId, setDeletingThreadId] = useState(null); - const [archivingThreadId, setArchivingThreadId] = useState(null); - const [searchQuery, setSearchQuery] = useState(""); - const [activeTab, setActiveTab] = useState("shared"); - const [mounted, setMounted] = useState(false); - const [openDropdownId, setOpenDropdownId] = useState(null); - const debouncedSearchQuery = useDebouncedValue(searchQuery, 300); - - const isSearchMode = !!debouncedSearchQuery.trim(); - - // Handle mounting for portal - useEffect(() => { - setMounted(true); - }, []); - - // Handle escape key - useEffect(() => { - const handleEscape = (e: KeyboardEvent) => { - if (e.key === "Escape" && open) { - onOpenChange(false); - } - }; - document.addEventListener("keydown", handleEscape); - return () => document.removeEventListener("keydown", handleEscape); - }, [open, onOpenChange]); - - // Lock body scroll when open - useEffect(() => { - if (open) { - document.body.style.overflow = "hidden"; - } else { - document.body.style.overflow = ""; - } - return () => { - document.body.style.overflow = ""; - }; - }, [open]); - - // Fetch all threads (when not searching) - const { - data: threadsData, - error: threadsError, - isLoading: isLoadingThreads, - } = useQuery({ - queryKey: ["all-threads", searchSpaceId], - queryFn: () => fetchThreads(Number(searchSpaceId)), - enabled: !!searchSpaceId && open && !isSearchMode, - }); - - // Search threads (when searching) - const { - data: searchData, - error: searchError, - isLoading: isLoadingSearch, - } = useQuery({ - queryKey: ["search-threads", searchSpaceId, debouncedSearchQuery], - queryFn: () => searchThreads(Number(searchSpaceId), debouncedSearchQuery.trim()), - enabled: !!searchSpaceId && open && isSearchMode, - }); - - // Split threads into shared and private based on visibility - const { sharedChats, privateChats } = useMemo(() => { - let allThreads: ThreadListItem[] = []; - - if (isSearchMode) { - allThreads = searchData ?? []; - } else if (threadsData) { - // Combine active and archived threads for filtering - allThreads = [...threadsData.threads, ...threadsData.archived_threads]; - } - - const shared: ThreadListItem[] = []; - const privateChatsList: ThreadListItem[] = []; - - for (const thread of allThreads) { - if (thread.visibility === "SEARCH_SPACE") { - shared.push(thread); - } else { - privateChatsList.push(thread); - } - } - - return { sharedChats: shared, privateChats: privateChatsList }; - }, [threadsData, searchData, isSearchMode]); - - // Get threads for current tab - const threads = activeTab === "shared" ? sharedChats : privateChats; - - // Handle thread navigation - const handleThreadClick = useCallback( - (threadId: number) => { - router.push(`/dashboard/${searchSpaceId}/new-chat/${threadId}`); - onOpenChange(false); - // Also close the main sidebar on mobile - onCloseMobileSidebar?.(); - }, - [router, onOpenChange, searchSpaceId, onCloseMobileSidebar] - ); - - // Handle thread deletion - const handleDeleteThread = useCallback( - async (threadId: number) => { - setDeletingThreadId(threadId); - try { - await deleteThread(threadId); - toast.success(t("chat_deleted") || "Chat deleted successfully"); - queryClient.invalidateQueries({ queryKey: ["all-threads", searchSpaceId] }); - queryClient.invalidateQueries({ queryKey: ["search-threads", searchSpaceId] }); - queryClient.invalidateQueries({ queryKey: ["threads", searchSpaceId] }); - - // If the deleted chat is currently open, close sidebar first then redirect - if (currentChatId === threadId) { - onOpenChange(false); - // Wait for sidebar close animation to complete before navigating - setTimeout(() => { - router.push(`/dashboard/${searchSpaceId}/new-chat`); - }, 250); - } - } catch (error) { - console.error("Error deleting thread:", error); - toast.error(t("error_deleting_chat") || "Failed to delete chat"); - } finally { - setDeletingThreadId(null); - } - }, - [queryClient, searchSpaceId, t, currentChatId, router, onOpenChange] - ); - - // Handle thread archive/unarchive - const handleToggleArchive = useCallback( - async (threadId: number, currentlyArchived: boolean) => { - setArchivingThreadId(threadId); - try { - await updateThread(threadId, { archived: !currentlyArchived }); - toast.success( - currentlyArchived - ? t("chat_unarchived") || "Chat restored" - : t("chat_archived") || "Chat archived" - ); - queryClient.invalidateQueries({ queryKey: ["all-threads", searchSpaceId] }); - queryClient.invalidateQueries({ queryKey: ["search-threads", searchSpaceId] }); - queryClient.invalidateQueries({ queryKey: ["threads", searchSpaceId] }); - } catch (error) { - console.error("Error archiving thread:", error); - toast.error(t("error_archiving_chat") || "Failed to archive chat"); - } finally { - setArchivingThreadId(null); - } - }, - [queryClient, searchSpaceId, t] - ); - - // Clear search - const handleClearSearch = useCallback(() => { - setSearchQuery(""); - }, []); - - const isLoading = isSearchMode ? isLoadingSearch : isLoadingThreads; - const error = isSearchMode ? searchError : threadsError; - - // Get counts for tabs - const sharedCount = sharedChats.length; - const privateCount = privateChats.length; - - if (!mounted) return null; - - return createPortal( - - {open && ( - <> - {/* Backdrop */} - onOpenChange(false)} - aria-hidden="true" - /> - - {/* Panel */} - - {/* Header */} -
-
-

{t("all_chats") || "All Chats"}

- -
- - {/* Search Input */} -
- - setSearchQuery(e.target.value)} - className="pl-9 pr-8 h-9" - /> - {searchQuery && ( - - )} -
-
- - {/* Tab toggle for shared/private chats */} -
- - -
- - {/* Scrollable Content */} -
- {isLoading ? ( -
- -
- ) : error ? ( -
- {t("error_loading_chats") || "Error loading chats"} -
- ) : threads.length > 0 ? ( -
- {threads.map((thread) => { - const isDeleting = deletingThreadId === thread.id; - const isArchiving = archivingThreadId === thread.id; - const isBusy = isDeleting || isArchiving; - const isActive = currentChatId === thread.id; - const isShared = thread.visibility === "SEARCH_SPACE"; - - return ( -
- {/* Main clickable area for navigation */} - - - - - -
-

- {t("updated") || "Updated"}:{" "} - {format(new Date(thread.updatedAt), "MMM d, yyyy 'at' h:mm a")} -

- {thread.archived && ( -

Archived

- )} -
-
-
- - {/* Actions dropdown */} - setOpenDropdownId(isOpen ? thread.id : null)} - > - - - - - handleToggleArchive(thread.id, thread.archived)} - disabled={isArchiving} - > - {thread.archived ? ( - <> - - {t("unarchive") || "Restore"} - - ) : ( - <> - - {t("archive") || "Archive"} - - )} - - - handleDeleteThread(thread.id)} - className="text-destructive focus:text-destructive" - > - - {t("delete") || "Delete"} - - - -
- ); - })} -
- ) : isSearchMode ? ( -
- -

- {t("no_chats_found") || "No chats found"} -

-

- {t("try_different_search") || "Try a different search term"} -

-
- ) : ( -
- {activeTab === "shared" ? ( - <> - -

- {t("no_shared_chats") || "No shared chats"} -

-

- Share a chat to collaborate with your team -

- - ) : ( - <> - -

- {t("no_chats") || "No private chats"} -

-

- {t("start_new_chat_hint") || "Start a new chat from the chat page"} -

- - )} -
- )} -
-
- - )} -
, - document.body - ); -} diff --git a/surfsense_web/components/layout/ui/sidebar/AllNotesSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/AllNotesSidebar.tsx deleted file mode 100644 index 67d1b4ba6..000000000 --- a/surfsense_web/components/layout/ui/sidebar/AllNotesSidebar.tsx +++ /dev/null @@ -1,407 +0,0 @@ -"use client"; - -import { useQuery, useQueryClient } from "@tanstack/react-query"; -import { format } from "date-fns"; -import { FileText, Loader2, MoreHorizontal, Plus, Search, Trash2, X } from "lucide-react"; -import { AnimatePresence, motion } from "motion/react"; -import { useParams, useRouter } from "next/navigation"; -import { useTranslations } from "next-intl"; -import { useCallback, useEffect, useMemo, useState } from "react"; -import { createPortal } from "react-dom"; -import { Button } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { Input } from "@/components/ui/input"; -import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; -import { useDebouncedValue } from "@/hooks/use-debounced-value"; -import { documentsApiService } from "@/lib/apis/documents-api.service"; -import { notesApiService } from "@/lib/apis/notes-api.service"; -import { cn } from "@/lib/utils"; - -interface AllNotesSidebarProps { - open: boolean; - onOpenChange: (open: boolean) => void; - searchSpaceId: string; - onAddNote?: () => void; - onCloseMobileSidebar?: () => void; -} - -export function AllNotesSidebar({ - open, - onOpenChange, - searchSpaceId, - onAddNote, - onCloseMobileSidebar, -}: AllNotesSidebarProps) { - const t = useTranslations("sidebar"); - const router = useRouter(); - const params = useParams(); - const queryClient = useQueryClient(); - - // Get the current note ID from URL to highlight the open note - const currentNoteId = params.note_id ? Number(params.note_id) : null; - const [deletingNoteId, setDeletingNoteId] = useState(null); - const [searchQuery, setSearchQuery] = useState(""); - const [mounted, setMounted] = useState(false); - const [openDropdownId, setOpenDropdownId] = useState(null); - const debouncedSearchQuery = useDebouncedValue(searchQuery, 300); - - // Handle mounting for portal - useEffect(() => { - setMounted(true); - }, []); - - // Handle escape key - useEffect(() => { - const handleEscape = (e: KeyboardEvent) => { - if (e.key === "Escape" && open) { - onOpenChange(false); - } - }; - document.addEventListener("keydown", handleEscape); - return () => document.removeEventListener("keydown", handleEscape); - }, [open, onOpenChange]); - - // Lock body scroll when open - useEffect(() => { - if (open) { - document.body.style.overflow = "hidden"; - } else { - document.body.style.overflow = ""; - } - return () => { - document.body.style.overflow = ""; - }; - }, [open]); - - // Fetch all notes (when no search query) - const { - data: notesData, - error: notesError, - isLoading: isLoadingNotes, - } = useQuery({ - queryKey: ["all-notes", searchSpaceId], - queryFn: () => - notesApiService.getNotes({ - search_space_id: Number(searchSpaceId), - page_size: 1000, - }), - enabled: !!searchSpaceId && open && !debouncedSearchQuery, - }); - - // Search notes (when there's a search query) - const { - data: searchData, - error: searchError, - isLoading: isSearching, - } = useQuery({ - queryKey: ["search-notes", searchSpaceId, debouncedSearchQuery], - queryFn: () => - documentsApiService.searchDocuments({ - queryParams: { - search_space_id: Number(searchSpaceId), - document_types: ["NOTE"], - title: debouncedSearchQuery, - page_size: 100, - }, - }), - enabled: !!searchSpaceId && open && !!debouncedSearchQuery, - }); - - // Handle note navigation - const handleNoteClick = useCallback( - (noteId: number, noteSearchSpaceId: number) => { - router.push(`/dashboard/${noteSearchSpaceId}/editor/${noteId}`); - onOpenChange(false); - // Also close the main sidebar on mobile - onCloseMobileSidebar?.(); - }, - [router, onOpenChange, onCloseMobileSidebar] - ); - - // Handle note deletion - const handleDeleteNote = useCallback( - async (noteId: number, noteSearchSpaceId: number) => { - setDeletingNoteId(noteId); - try { - await notesApiService.deleteNote({ - search_space_id: noteSearchSpaceId, - note_id: noteId, - }); - queryClient.invalidateQueries({ queryKey: ["all-notes", searchSpaceId] }); - queryClient.invalidateQueries({ queryKey: ["notes", searchSpaceId] }); - queryClient.invalidateQueries({ queryKey: ["search-notes", searchSpaceId] }); - } catch (error) { - console.error("Error deleting note:", error); - } finally { - setDeletingNoteId(null); - } - }, - [queryClient, searchSpaceId] - ); - - // Clear search - const handleClearSearch = useCallback(() => { - setSearchQuery(""); - }, []); - - // Determine which data to show - const isSearchMode = !!debouncedSearchQuery; - const isLoading = isSearchMode ? isSearching : isLoadingNotes; - const error = isSearchMode ? searchError : notesError; - - // Transform and sort notes data - handle both regular notes and search results - const notes = useMemo(() => { - let notesList: { - id: number; - title: string; - search_space_id: number; - created_at: string; - updated_at?: string | null; - }[]; - - if (isSearchMode && searchData?.items) { - notesList = searchData.items.map((doc) => ({ - id: doc.id, - title: doc.title, - search_space_id: doc.search_space_id, - created_at: doc.created_at, - updated_at: doc.updated_at, - })); - } else { - notesList = notesData?.items ?? []; - } - - // Sort notes by updated_at (most recent first), fallback to created_at - return [...notesList].sort((a, b) => { - const dateA = a.updated_at - ? new Date(a.updated_at).getTime() - : new Date(a.created_at).getTime(); - const dateB = b.updated_at - ? new Date(b.updated_at).getTime() - : new Date(b.created_at).getTime(); - return dateB - dateA; // Descending order (most recent first) - }); - }, [isSearchMode, searchData, notesData]); - - if (!mounted) return null; - - return createPortal( - - {open && ( - <> - {/* Backdrop */} - onOpenChange(false)} - aria-hidden="true" - /> - - {/* Panel */} - - {/* Header */} -
-
-

{t("all_notes") || "All Notes"}

- -
- - {/* Search Input */} -
- - setSearchQuery(e.target.value)} - className="pl-9 pr-8 h-9" - /> - {searchQuery && ( - - )} -
-
- - {/* Scrollable Content */} -
- {isLoading ? ( -
- -
- ) : error ? ( -
- {t("error_loading_notes") || "Error loading notes"} -
- ) : notes.length > 0 ? ( -
- {notes.map((note) => { - const isDeleting = deletingNoteId === note.id; - const isActive = currentNoteId === note.id; - - return ( -
- {/* Main clickable area for navigation */} - - - - - -
-

- {t("created") || "Created"}:{" "} - {format(new Date(note.created_at), "MMM d, yyyy 'at' h:mm a")} -

- {note.updated_at && ( -

- {t("updated") || "Updated"}:{" "} - {format(new Date(note.updated_at), "MMM d, yyyy 'at' h:mm a")} -

- )} -
-
-
- - {/* Actions dropdown - separate from main click area */} - setOpenDropdownId(isOpen ? note.id : null)} - > - - - - - handleDeleteNote(note.id, note.search_space_id)} - className="text-destructive focus:text-destructive" - > - - {t("delete") || "Delete"} - - - -
- ); - })} -
- ) : isSearchMode ? ( -
- -

- {t("no_results_found") || "No notes found"} -

-

- {t("try_different_search") || "Try a different search term"} -

-
- ) : ( -
- -

- {t("no_notes") || "No notes yet"} -

- {onAddNote && ( - - )} -
- )} -
- - {/* Footer with Add Note button */} - {onAddNote && notes.length > 0 && ( -
- -
- )} -
- - )} -
, - document.body - ); -} diff --git a/surfsense_web/components/layout/ui/sidebar/NoteListItem.tsx b/surfsense_web/components/layout/ui/sidebar/NoteListItem.tsx deleted file mode 100644 index 0491ebcca..000000000 --- a/surfsense_web/components/layout/ui/sidebar/NoteListItem.tsx +++ /dev/null @@ -1,76 +0,0 @@ -"use client"; - -import { FileText, Loader2, MoreHorizontal } from "lucide-react"; -import { useTranslations } from "next-intl"; -import { Button } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { cn } from "@/lib/utils"; - -interface NoteListItemProps { - name: string; - isActive?: boolean; - isReindexing?: boolean; - onClick?: () => void; - onDelete?: () => void; -} - -export function NoteListItem({ - name, - isActive, - isReindexing, - onClick, - onDelete, -}: NoteListItemProps) { - const t = useTranslations("sidebar"); - - return ( -
- - - {/* Actions dropdown */} -
- - - - - - { - e.stopPropagation(); - onDelete?.(); - }} - className="text-destructive focus:text-destructive" - > - {t("delete")} - - - -
-
- ); -} diff --git a/surfsense_web/components/layout/ui/sidebar/index.ts b/surfsense_web/components/layout/ui/sidebar/index.ts index 89d542629..282e4740b 100644 --- a/surfsense_web/components/layout/ui/sidebar/index.ts +++ b/surfsense_web/components/layout/ui/sidebar/index.ts @@ -1,10 +1,8 @@ -export { AllChatsSidebar } from "./AllChatsSidebar"; export { AllPrivateChatsSidebar } from "./AllPrivateChatsSidebar"; export { AllSharedChatsSidebar } from "./AllSharedChatsSidebar"; export { ChatListItem } from "./ChatListItem"; export { MobileSidebar, MobileSidebarTrigger } from "./MobileSidebar"; export { NavSection } from "./NavSection"; -export { NoteListItem } from "./NoteListItem"; export { PageUsageDisplay } from "./PageUsageDisplay"; export { Sidebar } from "./Sidebar"; export { SidebarCollapseButton } from "./SidebarCollapseButton"; diff --git a/surfsense_web/messages/en.json b/surfsense_web/messages/en.json index f46535ba7..ebc56acca 100644 --- a/surfsense_web/messages/en.json +++ b/surfsense_web/messages/en.json @@ -631,40 +631,21 @@ "sidebar": { "chats": "Private Chats", "shared_chats": "Shared Chats", - "recent_chats": "Recent Chats", "search_chats": "Search chats...", "no_chats_found": "No chats found", - "no_recent_chats": "No recent chats", "no_shared_chats": "No shared chats", - "view_all_chats": "View all chats", "view_all_shared_chats": "View all shared chats", "view_all_private_chats": "View all private chats", - "all_chats": "All Chats", - "all_chats_description": "Browse and manage all your chats", "no_chats": "No chats yet", "start_new_chat_hint": "Start a new chat", "error_loading_chats": "Error loading chats", "chat_deleted": "Chat deleted successfully", "error_deleting_chat": "Failed to delete chat", - "search_space": "Search Space", - "notes": "Notes", - "all_notes": "All Notes", - "all_notes_description": "Browse and manage all your notes", - "search_notes": "Search notes...", - "no_results_found": "No notes found", - "try_different_search": "Try a different search term", - "no_notes": "No notes yet", - "create_new_note": "Create a new note", - "error_loading_notes": "Error loading notes", - "loading": "Loading...", - "deleting": "Deleting...", "delete": "Delete", - "created": "Created", + "try_different_search": "Try a different search term", "updated": "Updated", "more_options": "More options", "clear_search": "Clear search", - "view_all_notes": "View all notes", - "add_note": "Add note", "archive": "Archive", "unarchive": "Restore", "chat_archived": "Chat archived", diff --git a/surfsense_web/messages/zh.json b/surfsense_web/messages/zh.json index 59dc0ca20..fe13de4c0 100644 --- a/surfsense_web/messages/zh.json +++ b/surfsense_web/messages/zh.json @@ -631,40 +631,27 @@ "sidebar": { "chats": "私人对话", "shared_chats": "共享对话", - "recent_chats": "最近对话", "search_chats": "搜索对话...", "no_chats_found": "未找到对话", - "no_recent_chats": "暂无最近对话", "no_shared_chats": "暂无共享对话", - "view_all_chats": "查看所有对话", "view_all_shared_chats": "查看所有共享对话", "view_all_private_chats": "查看所有私人对话", - "all_chats": "所有对话", - "all_chats_description": "浏览和管理您的所有对话", "no_chats": "暂无对话", "start_new_chat_hint": "开始新对话", "error_loading_chats": "加载对话时出错", "chat_deleted": "对话删除成功", "error_deleting_chat": "删除对话失败", - "search_space": "搜索空间", - "notes": "笔记", - "all_notes": "所有笔记", - "all_notes_description": "浏览和管理您的所有笔记", - "search_notes": "搜索笔记...", - "no_results_found": "未找到笔记", - "try_different_search": "尝试其他搜索词", - "no_notes": "暂无笔记", - "create_new_note": "创建新笔记", - "error_loading_notes": "加载笔记时出错", - "loading": "加载中...", - "deleting": "删除中...", "delete": "删除", - "created": "创建时间", + "try_different_search": "尝试其他搜索词", "updated": "更新时间", "more_options": "更多选项", "clear_search": "清除搜索", - "view_all_notes": "查看所有笔记", - "add_note": "添加笔记", + "archive": "归档", + "unarchive": "恢复", + "chat_archived": "对话已归档", + "chat_unarchived": "对话已恢复", + "no_archived_chats": "暂无已归档对话", + "error_archiving_chat": "归档对话失败", "new_chat": "新对话", "select_search_space": "选择搜索空间", "manage_members": "管理成员",