diff --git a/surfsense_web/app/dashboard/[search_space_id]/client-layout.tsx b/surfsense_web/app/dashboard/[search_space_id]/client-layout.tsx index 90dced5f9..bf9bad321 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/client-layout.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/client-layout.tsx @@ -14,7 +14,6 @@ import { } from "@/atoms/new-llm-config/new-llm-config-query.atoms"; import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms"; import { DocumentUploadDialogProvider } from "@/components/assistant-ui/document-upload-popup"; -import { DashboardBreadcrumb } from "@/components/dashboard-breadcrumb"; import { LayoutDataProvider } from "@/components/layout"; import { OnboardingTour } from "@/components/onboarding-tour"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; @@ -187,7 +186,7 @@ export function DashboardClientLayout({ return ( - }> + {children} diff --git a/surfsense_web/app/dashboard/[search_space_id]/new-chat/[[...chat_id]]/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/new-chat/[[...chat_id]]/page.tsx index 6e14cb8e6..799acdf39 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/new-chat/[[...chat_id]]/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/new-chat/[[...chat_id]]/page.tsx @@ -750,15 +750,6 @@ export default function NewChatPage() { queryClient.invalidateQueries({ queryKey: ["threads", String(searchSpaceId)], }); - // Invalidate thread detail for breadcrumb update - queryClient.invalidateQueries({ - queryKey: [ - "threads", - String(searchSpaceId), - "detail", - String(titleData.threadId), - ], - }); } break; } diff --git a/surfsense_web/components/dashboard-breadcrumb.tsx b/surfsense_web/components/dashboard-breadcrumb.tsx deleted file mode 100644 index 4030c34ee..000000000 --- a/surfsense_web/components/dashboard-breadcrumb.tsx +++ /dev/null @@ -1,212 +0,0 @@ -"use client"; - -import { useQuery } from "@tanstack/react-query"; -import { usePathname } from "next/navigation"; -import { useTranslations } from "next-intl"; -import React, { useEffect, useState } from "react"; -import { - Breadcrumb, - BreadcrumbItem, - BreadcrumbLink, - BreadcrumbList, - BreadcrumbPage, - BreadcrumbSeparator, -} from "@/components/ui/breadcrumb"; -import { searchSpacesApiService } from "@/lib/apis/search-spaces-api.service"; -import { authenticatedFetch, getBearerToken } from "@/lib/auth-utils"; -import { getThreadFull } from "@/lib/chat/thread-persistence"; -import { cacheKeys } from "@/lib/query-client/cache-keys"; - -interface BreadcrumbItemInterface { - label: string; - href?: string; -} - -export function DashboardBreadcrumb() { - const t = useTranslations("breadcrumb"); - const pathname = usePathname(); - // Extract search space ID and chat ID from pathname - const segments = pathname.split("/").filter(Boolean); - const searchSpaceId = segments[0] === "dashboard" && segments[1] ? segments[1] : null; - - const { data: searchSpace } = useQuery({ - queryKey: cacheKeys.searchSpaces.detail(searchSpaceId || ""), - queryFn: () => searchSpacesApiService.getSearchSpace({ id: Number(searchSpaceId) }), - enabled: !!searchSpaceId, - }); - - // Extract chat thread ID from pathname for chat pages - const chatThreadId = segments[2] === "new-chat" && segments[3] ? segments[3] : null; - - // Fetch thread details when on a chat page with a thread ID - const { data: threadData } = useQuery({ - queryKey: ["threads", searchSpaceId, "detail", chatThreadId], - queryFn: () => getThreadFull(Number(chatThreadId)), - enabled: !!chatThreadId && !!searchSpaceId, - }); - - // State to store document title for editor breadcrumb - const [documentTitle, setDocumentTitle] = useState(null); - - // Fetch document title when on editor page - useEffect(() => { - if (segments[2] === "editor" && segments[3] && searchSpaceId) { - const documentId = segments[3]; - - // Skip fetch for "new" notes - if (documentId === "new") { - setDocumentTitle(null); - return; - } - - const token = getBearerToken(); - - if (token) { - authenticatedFetch( - `${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/search-spaces/${searchSpaceId}/documents/${documentId}/editor-content`, - { method: "GET" } - ) - .then((res) => res.json()) - .then((data) => { - if (data.title) { - setDocumentTitle(data.title); - } - }) - .catch(() => { - // If fetch fails, just use the document ID - setDocumentTitle(null); - }); - } - } else { - setDocumentTitle(null); - } - }, [segments, searchSpaceId]); - - // Parse the pathname to create breadcrumb items - const generateBreadcrumbs = (path: string): BreadcrumbItemInterface[] => { - const segments = path.split("/").filter(Boolean); - const breadcrumbs: BreadcrumbItemInterface[] = []; - - // Handle search space (start directly with search space, skip "Dashboard") - if (segments[0] === "dashboard" && segments[1]) { - // Use the actual search space name if available, otherwise fall back to the ID - const searchSpaceLabel = searchSpace?.name || `${t("search_space")} ${segments[1]}`; - breadcrumbs.push({ - label: searchSpaceLabel, - href: `/dashboard/${segments[1]}`, - }); - - // Handle specific sections - if (segments[2]) { - const section = segments[2]; - let sectionLabel = section.charAt(0).toUpperCase() + section.slice(1); - - // Map section names to more readable labels - const sectionLabels: Record = { - "new-chat": t("chat") || "Chat", - documents: t("documents"), - logs: t("logs"), - settings: t("settings"), - editor: t("editor"), - }; - - sectionLabel = sectionLabels[section] || sectionLabel; - - // Handle sub-sections - if (segments[3]) { - const subSection = segments[3]; - - // Handle editor sub-sections (document ID) - if (section === "editor") { - let documentLabel: string; - if (subSection === "new") { - documentLabel = "New Note"; - } else { - documentLabel = documentTitle || subSection; - } - - breadcrumbs.push({ - label: t("documents"), - }); - breadcrumbs.push({ - label: sectionLabel, - }); - breadcrumbs.push({ label: documentLabel }); - return breadcrumbs; - } - - // Handle documents sub-sections - if (section === "documents") { - const documentLabels: Record = { - upload: t("upload_documents"), - webpage: t("add_webpages"), - }; - - const documentLabel = documentLabels[subSection] || subSection; - breadcrumbs.push({ - label: t("documents"), - }); - breadcrumbs.push({ label: documentLabel }); - return breadcrumbs; - } - - // Handle new-chat sub-sections (thread IDs) - // Show the chat title if available, otherwise fall back to "Chat" - if (section === "new-chat") { - const chatLabel = threadData?.title || t("chat") || "Chat"; - breadcrumbs.push({ - label: chatLabel, - }); - return breadcrumbs; - } - - // Handle other sub-sections - let subSectionLabel = subSection.charAt(0).toUpperCase() + subSection.slice(1); - const subSectionLabels: Record = { - upload: t("upload_documents"), - youtube: t("add_youtube"), - webpage: t("add_webpages"), - manage: t("manage"), - }; - - subSectionLabel = subSectionLabels[subSection] || subSectionLabel; - - breadcrumbs.push({ - label: sectionLabel, - href: `/dashboard/${segments[1]}/${section}`, - }); - breadcrumbs.push({ label: subSectionLabel }); - } else { - breadcrumbs.push({ label: sectionLabel }); - } - } - } - - return breadcrumbs; - }; - - const breadcrumbs = generateBreadcrumbs(pathname); - - if (breadcrumbs.length === 0) { - return null; // Don't show breadcrumbs for root dashboard - } - - return ( - - - {breadcrumbs.map((item, index) => ( - - - {index === breadcrumbs.length - 1 ? ( - {item.label} - ) : ( - {item.label} - )} - - {index < breadcrumbs.length - 1 && } - - ))} - - - ); -} diff --git a/surfsense_web/components/layout/providers/LayoutDataProvider.tsx b/surfsense_web/components/layout/providers/LayoutDataProvider.tsx index f1caff27e..37f101f79 100644 --- a/surfsense_web/components/layout/providers/LayoutDataProvider.tsx +++ b/surfsense_web/components/layout/providers/LayoutDataProvider.tsx @@ -47,7 +47,6 @@ import { LayoutShell } from "../ui/shell"; interface LayoutDataProviderProps { searchSpaceId: string; children: React.ReactNode; - breadcrumb?: React.ReactNode; } /** @@ -64,7 +63,6 @@ function formatInboxCount(count: number): string { export function LayoutDataProvider({ searchSpaceId, children, - breadcrumb, }: LayoutDataProviderProps) { const t = useTranslations("dashboard"); const tCommon = useTranslations("common"); @@ -537,10 +535,6 @@ export function LayoutDataProvider({ queryClient.invalidateQueries({ queryKey: ["threads", searchSpaceId] }); queryClient.invalidateQueries({ queryKey: ["all-threads", searchSpaceId] }); queryClient.invalidateQueries({ queryKey: ["search-threads", searchSpaceId] }); - // Invalidate thread detail for breadcrumb update - queryClient.invalidateQueries({ - queryKey: ["threads", searchSpaceId, "detail", String(chatToRename.id)], - }); } catch (error) { console.error("Error renaming thread:", error); toast.error(tSidebar("error_renaming_chat") || "Failed to rename chat"); @@ -595,7 +589,6 @@ export function LayoutDataProvider({ onUserSettings={handleUserSettings} onLogout={handleLogout} pageUsage={pageUsage} - breadcrumb={breadcrumb} theme={theme} setTheme={setTheme} isChatPage={isChatPage} diff --git a/surfsense_web/components/layout/ui/header/Header.tsx b/surfsense_web/components/layout/ui/header/Header.tsx index 8f15bb6b3..1f04a347b 100644 --- a/surfsense_web/components/layout/ui/header/Header.tsx +++ b/surfsense_web/components/layout/ui/header/Header.tsx @@ -7,11 +7,10 @@ import { ChatShareButton } from "@/components/new-chat/chat-share-button"; import type { ChatVisibility, ThreadRecord } from "@/lib/chat/thread-persistence"; interface HeaderProps { - breadcrumb?: React.ReactNode; mobileMenuTrigger?: React.ReactNode; } -export function Header({ breadcrumb, mobileMenuTrigger }: HeaderProps) { +export function Header({ mobileMenuTrigger }: HeaderProps) { const pathname = usePathname(); // Check if we're on a chat page @@ -46,10 +45,9 @@ export function Header({ breadcrumb, mobileMenuTrigger }: HeaderProps) { return (
- {/* Left side - Mobile menu trigger + Breadcrumb */} + {/* Left side - Mobile menu trigger */}
{mobileMenuTrigger} -
{breadcrumb}
{/* Right side - Actions */} diff --git a/surfsense_web/components/layout/ui/shell/LayoutShell.tsx b/surfsense_web/components/layout/ui/shell/LayoutShell.tsx index 55c45d30d..f1205bd7c 100644 --- a/surfsense_web/components/layout/ui/shell/LayoutShell.tsx +++ b/surfsense_web/components/layout/ui/shell/LayoutShell.tsx @@ -69,7 +69,6 @@ interface LayoutShellProps { onUserSettings?: () => void; onLogout?: () => void; pageUsage?: PageUsage; - breadcrumb?: React.ReactNode; theme?: string; setTheme?: (theme: "light" | "dark" | "system") => void; defaultCollapsed?: boolean; @@ -122,7 +121,6 @@ export function LayoutShell({ onUserSettings, onLogout, pageUsage, - breadcrumb, theme, setTheme, defaultCollapsed = false, @@ -156,10 +154,9 @@ export function LayoutShell({
-
setMobileMenuOpen(true)} />} - /> +
setMobileMenuOpen(true)} />} + /> -
+
{children} diff --git a/surfsense_web/components/ui/breadcrumb.tsx b/surfsense_web/components/ui/breadcrumb.tsx deleted file mode 100644 index e2451573f..000000000 --- a/surfsense_web/components/ui/breadcrumb.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { Slot } from "@radix-ui/react-slot"; -import { ChevronRight, MoreHorizontal } from "lucide-react"; - -import { cn } from "@/lib/utils"; - -function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { - return