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 799acdf39..ced63a6f6 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
@@ -32,7 +32,6 @@ import { closeReportPanelAtom } from "@/atoms/chat/report-panel.atom";
import { membersAtom } from "@/atoms/members/members-query.atoms";
import { currentUserAtom } from "@/atoms/user/user-query.atoms";
import { Thread } from "@/components/assistant-ui/thread";
-import { ChatHeader } from "@/components/new-chat/chat-header";
import { ReportPanel } from "@/components/report-panel/report-panel";
import type { ThinkingStep } from "@/components/tool-ui/deepagent-thinking";
import { DisplayImageToolUI } from "@/components/tool-ui/display-image";
@@ -476,7 +475,7 @@ export default function NewChatPage() {
const newThread = await createThread(searchSpaceId, initialTitle);
currentThreadId = newThread.id;
setThreadId(currentThreadId);
- // Set currentThread so ChatHeader can show share button immediately
+ // Set currentThread so share button in header appears immediately
setCurrentThread(newThread);
// Track chat creation
@@ -1670,10 +1669,9 @@ export default function NewChatPage() {
{/* Disabled for now */}
diff --git a/surfsense_web/components/assistant-ui/thread.tsx b/surfsense_web/components/assistant-ui/thread.tsx
index 483ca2133..53e7f7eb6 100644
--- a/surfsense_web/components/assistant-ui/thread.tsx
+++ b/surfsense_web/components/assistant-ui/thread.tsx
@@ -79,18 +79,17 @@ const CYCLING_PLACEHOLDERS = [
interface ThreadProps {
messageThinkingSteps?: Map;
- header?: React.ReactNode;
}
-export const Thread: FC = ({ messageThinkingSteps = new Map(), header }) => {
+export const Thread: FC = ({ messageThinkingSteps = new Map() }) => {
return (
-
+
);
};
-const ThreadContent: FC<{ header?: React.ReactNode }> = ({ header }) => {
+const ThreadContent: FC = () => {
const showGutter = useAtomValue(showCommentsGutterAtom);
return (
@@ -108,8 +107,6 @@ const ThreadContent: FC<{ header?: React.ReactNode }> = ({ header }) => {
showGutter && "lg:pr-30"
)}
>
- {header && {header}
}
-
thread.isEmpty}>
diff --git a/surfsense_web/components/layout/ui/header/Header.tsx b/surfsense_web/components/layout/ui/header/Header.tsx
index 1f04a347b..166bf6ed0 100644
--- a/surfsense_web/components/layout/ui/header/Header.tsx
+++ b/surfsense_web/components/layout/ui/header/Header.tsx
@@ -3,6 +3,8 @@
import { useAtomValue } from "jotai";
import { usePathname } from "next/navigation";
import { currentThreadAtom } from "@/atoms/chat/current-thread.atom";
+import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms";
+import { ChatHeader } from "@/components/new-chat/chat-header";
import { ChatShareButton } from "@/components/new-chat/chat-share-button";
import type { ChatVisibility, ThreadRecord } from "@/lib/chat/thread-persistence";
@@ -12,23 +14,19 @@ interface HeaderProps {
export function Header({ mobileMenuTrigger }: HeaderProps) {
const pathname = usePathname();
+ const searchSpaceId = useAtomValue(activeSearchSpaceIdAtom);
- // Check if we're on a chat page
const isChatPage = pathname?.includes("/new-chat") ?? false;
- // Use Jotai atom for thread state (synced from chat page)
const currentThreadState = useAtomValue(currentThreadAtom);
- // Show button only when we have a thread id (thread exists and is synced to Jotai)
const hasThread = isChatPage && currentThreadState.id !== null;
- // Create minimal thread object for ChatShareButton (used for API calls)
const threadForButton: ThreadRecord | null =
hasThread && currentThreadState.id !== null
? {
id: currentThreadState.id,
visibility: currentThreadState.visibility ?? "PRIVATE",
- // These fields are not used by ChatShareButton for display, only for checks
created_by_id: null,
search_space_id: 0,
title: "",
@@ -38,21 +36,20 @@ export function Header({ mobileMenuTrigger }: HeaderProps) {
}
: null;
- const handleVisibilityChange = (_visibility: ChatVisibility) => {
- // Visibility change is handled by ChatShareButton internally via Jotai
- // This callback can be used for additional side effects if needed
- };
+ const handleVisibilityChange = (_visibility: ChatVisibility) => {};
return (
-
- {/* Left side - Mobile menu trigger */}
+
+ {/* Left side - Mobile menu trigger + Model selector */}
{mobileMenuTrigger}
+ {isChatPage && searchSpaceId && (
+
+ )}
{/* Right side - Actions */}
- {/* Share button - only show on chat pages when thread exists */}
{hasThread && (
)}
diff --git a/surfsense_web/components/new-chat/chat-header.tsx b/surfsense_web/components/new-chat/chat-header.tsx
index 2f1d9d845..4d40bc21a 100644
--- a/surfsense_web/components/new-chat/chat-header.tsx
+++ b/surfsense_web/components/new-chat/chat-header.tsx
@@ -13,9 +13,10 @@ import { ModelSelector } from "./model-selector";
interface ChatHeaderProps {
searchSpaceId: number;
+ className?: string;
}
-export function ChatHeader({ searchSpaceId }: ChatHeaderProps) {
+export function ChatHeader({ searchSpaceId, className }: ChatHeaderProps) {
// LLM config sidebar state
const [sidebarOpen, setSidebarOpen] = useState(false);
const [selectedConfig, setSelectedConfig] = useState<
@@ -85,6 +86,7 @@ export function ChatHeader({ searchSpaceId }: ChatHeaderProps) {
onAddNewLLM={handleAddNewLLM}
onEditImage={handleEditImageConfig}
onAddNewImage={handleAddImageModel}
+ className={className}
/>