@@ -486,7 +493,7 @@ export function AllPrivateChatsSidebarContent({
{showArchived
? t("no_archived_chats") || "No archived chats"
- : t("no_chats") || "No private chats"}
+ : t("no_chats") || "No chats"}
{!showArchived && (
@@ -545,21 +552,17 @@ export function AllPrivateChatsSidebarContent({
);
}
-export function AllPrivateChatsSidebar({
+export function AllChatsSidebar({
open,
onOpenChange,
searchSpaceId,
onCloseMobileSidebar,
-}: AllPrivateChatsSidebarProps) {
+}: AllChatsSidebarProps) {
const t = useTranslations("sidebar");
return (
-
-
+ void;
- searchSpaceId: string;
- onCloseMobileSidebar?: () => void;
-}
-
-interface AllSharedChatsSidebarProps extends AllSharedChatsSidebarContentProps {
- open: boolean;
-}
-
-export function AllSharedChatsSidebarContent({
- onOpenChange,
- searchSpaceId,
- onCloseMobileSidebar,
-}: AllSharedChatsSidebarContentProps) {
- const t = useTranslations("sidebar");
- const router = useRouter();
- const params = useParams();
- const queryClient = useQueryClient();
- const isMobile = useIsMobile();
- const removeChatTab = useSetAtom(removeChatTabAtom);
-
- 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 [showArchived, setShowArchived] = useState(false);
- const [openDropdownId, setOpenDropdownId] = useState(null);
- const [showRenameDialog, setShowRenameDialog] = useState(false);
- const [renamingThread, setRenamingThread] = useState<{ id: number; title: string } | null>(null);
- const [newTitle, setNewTitle] = useState("");
- const [isRenaming, setIsRenaming] = useState(false);
- const debouncedSearchQuery = useDebouncedValue(searchQuery, 300);
-
- const pendingThreadIdRef = useRef(null);
- const { handlers: longPressHandlers, wasLongPress } = useLongPress(
- useCallback(() => {
- if (pendingThreadIdRef.current !== null) {
- setOpenDropdownId(pendingThreadIdRef.current);
- }
- }, [])
- );
-
- const isSearchMode = !!debouncedSearchQuery.trim();
-
- const {
- data: threadsData,
- error: threadsError,
- isLoading: isLoadingThreads,
- } = useQuery({
- queryKey: ["all-threads", searchSpaceId],
- queryFn: () => fetchThreads(Number(searchSpaceId)),
- enabled: !!searchSpaceId && !isSearchMode,
- });
-
- const {
- data: searchData,
- error: searchError,
- isLoading: isLoadingSearch,
- } = useQuery({
- queryKey: ["search-threads", searchSpaceId, debouncedSearchQuery],
- queryFn: () => searchThreads(Number(searchSpaceId), debouncedSearchQuery.trim()),
- enabled: !!searchSpaceId && isSearchMode,
- });
-
- // Filter to only shared chats (SEARCH_SPACE visibility)
- const { activeChats, archivedChats } = useMemo(() => {
- if (isSearchMode) {
- const sharedSearchResults = (searchData ?? []).filter(
- (thread) => thread.visibility === "SEARCH_SPACE"
- );
- return {
- activeChats: sharedSearchResults.filter((t) => !t.archived),
- archivedChats: sharedSearchResults.filter((t) => t.archived),
- };
- }
-
- if (!threadsData) return { activeChats: [], archivedChats: [] };
-
- const activeShared = threadsData.threads.filter(
- (thread) => thread.visibility === "SEARCH_SPACE"
- );
- const archivedShared = threadsData.archived_threads.filter(
- (thread) => thread.visibility === "SEARCH_SPACE"
- );
-
- return { activeChats: activeShared, archivedChats: archivedShared };
- }, [threadsData, searchData, isSearchMode]);
-
- const threads = showArchived ? archivedChats : activeChats;
-
- const handleThreadClick = useCallback(
- (threadId: number) => {
- router.push(`/dashboard/${searchSpaceId}/new-chat/${threadId}`);
- onOpenChange(false);
- onCloseMobileSidebar?.();
- },
- [router, onOpenChange, searchSpaceId, onCloseMobileSidebar]
- );
-
- const handleDeleteThread = useCallback(
- async (threadId: number) => {
- setDeletingThreadId(threadId);
- try {
- await deleteThread(threadId);
- const fallbackTab = removeChatTab(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 (currentChatId === threadId) {
- onOpenChange(false);
- setTimeout(() => {
- if (fallbackTab?.type === "chat" && fallbackTab.chatUrl) {
- router.push(fallbackTab.chatUrl);
- return;
- }
- 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, removeChatTab]
- );
-
- 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]
- );
-
- const handleStartRename = useCallback((threadId: number, title: string) => {
- setRenamingThread({ id: threadId, title });
- setNewTitle(title);
- setShowRenameDialog(true);
- }, []);
-
- const handleConfirmRename = useCallback(async () => {
- if (!renamingThread || !newTitle.trim()) return;
- setIsRenaming(true);
- try {
- await updateThread(renamingThread.id, { title: newTitle.trim() });
- toast.success(t("chat_renamed") || "Chat renamed");
- queryClient.invalidateQueries({ queryKey: ["all-threads", searchSpaceId] });
- queryClient.invalidateQueries({ queryKey: ["search-threads", searchSpaceId] });
- queryClient.invalidateQueries({ queryKey: ["threads", searchSpaceId] });
- queryClient.invalidateQueries({
- queryKey: ["threads", searchSpaceId, "detail", String(renamingThread.id)],
- });
- } catch (error) {
- console.error("Error renaming thread:", error);
- toast.error(t("error_renaming_chat") || "Failed to rename chat");
- } finally {
- setIsRenaming(false);
- setShowRenameDialog(false);
- setRenamingThread(null);
- setNewTitle("");
- }
- }, [renamingThread, newTitle, queryClient, searchSpaceId, t]);
-
- const handleClearSearch = useCallback(() => {
- setSearchQuery("");
- }, []);
-
- const isLoading = isSearchMode ? isLoadingSearch : isLoadingThreads;
- const error = isSearchMode ? searchError : threadsError;
-
- const activeCount = activeChats.length;
- const archivedCount = archivedChats.length;
-
- return (
- <>
-
-
- {isMobile && (
-
- )}
-
{t("shared_chats") || "Shared Chats"}
-
-
-
-
- setSearchQuery(e.target.value)}
- className="h-8 border-0 bg-muted pl-8 pr-7 text-sm shadow-none"
- />
- {searchQuery && (
-
- )}
-
-
-
- {!isSearchMode && (
- setShowArchived(value === "archived")}
- className="shrink-0 mx-3 mt-1.5"
- >
-
-
-
-
- Active
-
- {activeCount}
-
-
-
-
-
-
- Archived
-
- {archivedCount}
-
-
-
-
-
- )}
-
-
- {isLoading ? (
-
- {[75, 90, 55, 80, 65, 85].map((titleWidth) => (
-
-
-
-
- ))}
-
- ) : 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;
-
- return (
-
- {isMobile ? (
-
- ) : (
-
-
-
-
-
-
- {t("updated") || "Updated"}: {formatThreadTimestamp(thread.updatedAt)}
-
-
-
- )}
-
-
-
setOpenDropdownId(isOpen ? thread.id : null)}
- >
-
-
-
-
- {!thread.archived && (
- handleStartRename(thread.id, thread.title || "New Chat")}
- >
-
- {t("rename") || "Rename"}
-
- )}
- handleToggleArchive(thread.id, thread.archived)}
- disabled={isArchiving}
- >
- {thread.archived ? (
- <>
-
- {t("unarchive") || "Restore"}
- >
- ) : (
- <>
-
- {t("archive") || "Archive"}
- >
- )}
-
- handleDeleteThread(thread.id)}>
-
- {t("delete") || "Delete"}
-
-
-
-
-
- );
- })}
-
- ) : isSearchMode ? (
-
-
-
- {t("no_chats_found") || "No chats found"}
-
-
- {t("try_different_search") || "Try a different search term"}
-
-
- ) : (
-
-
-
- {showArchived
- ? t("no_archived_chats") || "No archived chats"
- : t("no_shared_chats") || "No shared chats"}
-
- {!showArchived && (
-
- Share a chat to collaborate with your team
-
- )}
-
- )}
-
-
- >
- );
-}
-
-export function AllSharedChatsSidebar({
- open,
- onOpenChange,
- searchSpaceId,
- onCloseMobileSidebar,
-}: AllSharedChatsSidebarProps) {
- const t = useTranslations("sidebar");
-
- return (
-
-
-
- );
-}
diff --git a/surfsense_web/components/layout/ui/sidebar/ChatListItem.tsx b/surfsense_web/components/layout/ui/sidebar/ChatListItem.tsx
index ea4f946c2..ec0ba534a 100644
--- a/surfsense_web/components/layout/ui/sidebar/ChatListItem.tsx
+++ b/surfsense_web/components/layout/ui/sidebar/ChatListItem.tsx
@@ -1,6 +1,6 @@
"use client";
-import { ArchiveIcon, MoreHorizontal, Pencil, RotateCcwIcon, Trash2 } from "lucide-react";
+import { ArchiveIcon, MoreHorizontal, Pencil, RotateCcwIcon, Trash2, Users } from "lucide-react";
import { useTranslations } from "next-intl";
import { useCallback, useState } from "react";
import { Button } from "@/components/ui/button";
@@ -18,6 +18,7 @@ import { cn } from "@/lib/utils";
interface ChatListItemProps {
name: string;
isActive?: boolean;
+ isShared?: boolean;
archived?: boolean;
dropdownOpen?: boolean;
onDropdownOpenChange?: (open: boolean) => void;
@@ -30,6 +31,7 @@ interface ChatListItemProps {
export function ChatListItem({
name,
isActive,
+ isShared,
archived,
dropdownOpen: controlledOpen,
onDropdownOpenChange,
@@ -68,7 +70,13 @@ export function ChatListItem({
isActive && "bg-accent text-accent-foreground"
)}
>
- {animatedName}
+ {animatedName}
+ {isShared ? (
+
+ ) : null}
{/* Actions dropdown - trigger hidden on mobile, long-press opens it instead */}
diff --git a/surfsense_web/components/layout/ui/sidebar/MobileSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/MobileSidebar.tsx
index 83d423ace..bd9a95094 100644
--- a/surfsense_web/components/layout/ui/sidebar/MobileSidebar.tsx
+++ b/surfsense_web/components/layout/ui/sidebar/MobileSidebar.tsx
@@ -19,17 +19,14 @@ interface MobileSidebarProps {
navItems: NavItem[];
onNavItemClick?: (item: NavItem) => void;
chats: ChatItem[];
- sharedChats?: ChatItem[];
activeChatId?: number | null;
onNewChat: () => void;
onChatSelect: (chat: ChatItem) => void;
onChatRename?: (chat: ChatItem) => void;
onChatDelete?: (chat: ChatItem) => void;
onChatArchive?: (chat: ChatItem) => void;
- onViewAllSharedChats?: () => void;
- onViewAllPrivateChats?: () => void;
- isSharedChatsPanelOpen?: boolean;
- isPrivateChatsPanelOpen?: boolean;
+ onViewAllChats?: () => void;
+ isChatsPanelOpen?: boolean;
user: User;
onSettings?: () => void;
onManageMembers?: () => void;
@@ -69,17 +66,14 @@ export function MobileSidebar({
navItems,
onNavItemClick,
chats,
- sharedChats,
activeChatId,
onNewChat,
onChatSelect,
onChatRename,
onChatDelete,
onChatArchive,
- onViewAllSharedChats,
- onViewAllPrivateChats,
- isSharedChatsPanelOpen = false,
- isPrivateChatsPanelOpen = false,
+ onViewAllChats,
+ isChatsPanelOpen = false,
user,
onSettings,
onManageMembers,
@@ -152,7 +146,6 @@ export function MobileSidebar({
navItems={navItems}
onNavItemClick={handleNavItemClick}
chats={chats}
- sharedChats={sharedChats}
activeChatId={activeChatId}
onNewChat={() => {
onNewChat();
@@ -162,24 +155,15 @@ export function MobileSidebar({
onChatRename={onChatRename}
onChatDelete={onChatDelete}
onChatArchive={onChatArchive}
- onViewAllSharedChats={
- onViewAllSharedChats
+ onViewAllChats={
+ onViewAllChats
? () => {
onOpenChange(false);
- onViewAllSharedChats();
+ onViewAllChats();
}
: undefined
}
- onViewAllPrivateChats={
- onViewAllPrivateChats
- ? () => {
- onOpenChange(false);
- onViewAllPrivateChats();
- }
- : undefined
- }
- isSharedChatsPanelOpen={isSharedChatsPanelOpen}
- isPrivateChatsPanelOpen={isPrivateChatsPanelOpen}
+ isChatsPanelOpen={isChatsPanelOpen}
user={user}
onSettings={
onSettings
diff --git a/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx b/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx
index 805f8bfd3..b7c8d94c7 100644
--- a/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx
+++ b/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx
@@ -67,17 +67,14 @@ interface SidebarProps {
navItems: NavItem[];
onNavItemClick?: (item: NavItem) => void;
chats: ChatItem[];
- sharedChats?: ChatItem[];
activeChatId?: number | null;
onNewChat: () => void;
onChatSelect: (chat: ChatItem) => void;
onChatRename?: (chat: ChatItem) => void;
onChatDelete?: (chat: ChatItem) => void;
onChatArchive?: (chat: ChatItem) => void;
- onViewAllSharedChats?: () => void;
- onViewAllPrivateChats?: () => void;
- isSharedChatsPanelOpen?: boolean;
- isPrivateChatsPanelOpen?: boolean;
+ onViewAllChats?: () => void;
+ isChatsPanelOpen?: boolean;
user: User;
onSettings?: () => void;
onManageMembers?: () => void;
@@ -106,17 +103,14 @@ export function Sidebar({
navItems,
onNavItemClick,
chats,
- sharedChats = [],
activeChatId,
onNewChat,
onChatSelect,
onChatRename,
onChatDelete,
onChatArchive,
- onViewAllSharedChats,
- onViewAllPrivateChats,
- isSharedChatsPanelOpen = false,
- isPrivateChatsPanelOpen = false,
+ onViewAllChats,
+ isChatsPanelOpen = false,
user,
onSettings,
onManageMembers,
@@ -264,73 +258,20 @@ export function Sidebar({
) : (
- {/* Shared Chats Section - takes only space needed, max 50% */}
-
- {!disableTooltips && isSharedChatsPanelOpen ? t("hide") : t("show_all")}
-
- ) : undefined
- }
- >
- {isLoadingChats ? (
-
- ) : sharedChats.length > 0 ? (
-
-
4 ? "pb-2" : ""}`}
- >
- {sharedChats.slice(0, 20).map((chat) => (
- setOpenDropdownChatId(open ? chat.id : null)}
- onClick={() => onChatSelect(chat)}
- onRename={() => onChatRename?.(chat)}
- onArchive={() => onChatArchive?.(chat)}
- onDelete={() => onChatDelete?.(chat)}
- />
- ))}
-
- {/* Gradient fade indicator when more than 4 items */}
- {sharedChats.length > 4 && (
-
- )}
-
- ) : (
- {t("no_shared_chats")}
- )}
-
-
- {/* Private Chats Section - fills remaining space */}
- {!disableTooltips && isPrivateChatsPanelOpen ? t("hide") : t("show_all")}
+ {!disableTooltips && isChatsPanelOpen ? t("hide") : t("show_all")}
) : undefined
}
@@ -347,6 +288,7 @@ export function Sidebar({
key={chat.id}
name={chat.name}
isActive={chat.id === activeChatId}
+ isShared={chat.visibility === "SEARCH_SPACE"}
archived={chat.archived}
dropdownOpen={openDropdownChatId === chat.id}
onDropdownOpenChange={(open) => setOpenDropdownChatId(open ? chat.id : null)}
diff --git a/surfsense_web/components/layout/ui/sidebar/index.ts b/surfsense_web/components/layout/ui/sidebar/index.ts
index d72f86c8a..e25149b06 100644
--- a/surfsense_web/components/layout/ui/sidebar/index.ts
+++ b/surfsense_web/components/layout/ui/sidebar/index.ts
@@ -1,5 +1,4 @@
-export { AllPrivateChatsSidebar, AllPrivateChatsSidebarContent } from "./AllPrivateChatsSidebar";
-export { AllSharedChatsSidebar, AllSharedChatsSidebarContent } from "./AllSharedChatsSidebar";
+export { AllChatsSidebar, AllChatsSidebarContent } from "./AllChatsSidebar";
export { ChatListItem } from "./ChatListItem";
export { DocumentsSidebar } from "./DocumentsSidebar";
export { InboxSidebar, InboxSidebarContent } from "./InboxSidebar";
diff --git a/surfsense_web/messages/en.json b/surfsense_web/messages/en.json
index 97ae05101..de31e00b9 100644
--- a/surfsense_web/messages/en.json
+++ b/surfsense_web/messages/en.json
@@ -650,13 +650,14 @@
"created": "Created"
},
"sidebar": {
- "chats": "Private Chats",
+ "chats": "Chats",
"shared_chats": "Shared Chats",
"search_chats": "Search chats",
"no_chats_found": "No chats found",
"no_shared_chats": "No shared chats",
+ "shared_chat": "Shared chat",
"view_all_shared_chats": "View all shared chats",
- "view_all_private_chats": "View all private chats",
+ "view_all_chats": "View all chats",
"show_all": "Show all",
"hide": "Hide",
"no_chats": "No chats",
diff --git a/surfsense_web/messages/es.json b/surfsense_web/messages/es.json
index 2ac168d0a..658c9f7cf 100644
--- a/surfsense_web/messages/es.json
+++ b/surfsense_web/messages/es.json
@@ -650,13 +650,14 @@
"created": "Creado"
},
"sidebar": {
- "chats": "Chats privados",
+ "chats": "Chats",
"shared_chats": "Chats compartidos",
"search_chats": "Buscar chats",
"no_chats_found": "No se encontraron chats",
"no_shared_chats": "No hay chats compartidos",
+ "shared_chat": "Chat compartido",
"view_all_shared_chats": "Ver todos los chats compartidos",
- "view_all_private_chats": "Ver todos los chats privados",
+ "view_all_chats": "Ver todos los chats",
"show_all": "Ver todo",
"hide": "Ocultar",
"no_chats": "Sin chats",
diff --git a/surfsense_web/messages/hi.json b/surfsense_web/messages/hi.json
index 2bfa9a59f..33a0c8a36 100644
--- a/surfsense_web/messages/hi.json
+++ b/surfsense_web/messages/hi.json
@@ -650,13 +650,14 @@
"created": "बनाया गया"
},
"sidebar": {
- "chats": "निजी चैट",
+ "chats": "चैट",
"shared_chats": "साझा चैट",
"search_chats": "चैट खोजें",
"no_chats_found": "कोई चैट नहीं मिला",
"no_shared_chats": "कोई साझा चैट नहीं",
+ "shared_chat": "साझा चैट",
"view_all_shared_chats": "सभी साझा चैट देखें",
- "view_all_private_chats": "सभी निजी चैट देखें",
+ "view_all_chats": "सभी चैट देखें",
"show_all": "सभी देखें",
"hide": "छिपाएँ",
"no_chats": "कोई चैट नहीं",
diff --git a/surfsense_web/messages/pt.json b/surfsense_web/messages/pt.json
index 029959689..6ea0ae5cf 100644
--- a/surfsense_web/messages/pt.json
+++ b/surfsense_web/messages/pt.json
@@ -650,13 +650,14 @@
"created": "Criado"
},
"sidebar": {
- "chats": "Chats privados",
+ "chats": "Chats",
"shared_chats": "Chats compartilhados",
"search_chats": "Pesquisar chats",
"no_chats_found": "Nenhum chat encontrado",
"no_shared_chats": "Nenhum chat compartilhado",
+ "shared_chat": "Chat compartilhado",
"view_all_shared_chats": "Ver todos os chats compartilhados",
- "view_all_private_chats": "Ver todos os chats privados",
+ "view_all_chats": "Ver todos os chats",
"show_all": "Ver tudo",
"hide": "Ocultar",
"no_chats": "Nenhum chat",
diff --git a/surfsense_web/messages/zh.json b/surfsense_web/messages/zh.json
index 6f5b2cafb..1404c6ef0 100644
--- a/surfsense_web/messages/zh.json
+++ b/surfsense_web/messages/zh.json
@@ -634,13 +634,14 @@
"created": "创建于"
},
"sidebar": {
- "chats": "私人对话",
+ "chats": "对话",
"shared_chats": "共享对话",
"search_chats": "搜索对话...",
"no_chats_found": "未找到对话",
"no_shared_chats": "暂无共享对话",
+ "shared_chat": "共享对话",
"view_all_shared_chats": "查看所有共享对话",
- "view_all_private_chats": "查看所有私人对话",
+ "view_all_chats": "查看所有对话",
"show_all": "查看全部",
"hide": "隐藏",
"no_chats": "无对话",