diff --git a/surfsense_web/app/(home)/login/LocalLoginForm.tsx b/surfsense_web/app/(home)/login/LocalLoginForm.tsx index a0326e39b..9692d35e1 100644 --- a/surfsense_web/app/(home)/login/LocalLoginForm.tsx +++ b/surfsense_web/app/(home)/login/LocalLoginForm.tsx @@ -7,6 +7,7 @@ import { useRouter } from "next/navigation"; import { useTranslations } from "next-intl"; import { useState } from "react"; import { loginMutationAtom } from "@/atoms/auth/auth-mutation.atoms"; +import { Button } from "@/components/ui/button"; import { Spinner } from "@/components/ui/spinner"; import { getAuthErrorDetails, isNetworkError } from "@/lib/auth-errors"; import { AUTH_TYPE } from "@/lib/env-config"; @@ -120,11 +121,13 @@ export function LocalLoginForm() {

{error.title}

{error.message}

- + )} @@ -191,21 +194,23 @@ export function LocalLoginForm() { }`} disabled={isLoggingIn} /> - + - + {authType === "LOCAL" && ( diff --git a/surfsense_web/app/(home)/login/page.tsx b/surfsense_web/app/(home)/login/page.tsx index c336e757c..42a9182e9 100644 --- a/surfsense_web/app/(home)/login/page.tsx +++ b/surfsense_web/app/(home)/login/page.tsx @@ -6,6 +6,7 @@ import { useTranslations } from "next-intl"; import { Suspense, useEffect, useState } from "react"; import { toast } from "sonner"; import { Logo } from "@/components/Logo"; +import { Button } from "@/components/ui/button"; import { useGlobalLoadingEffect } from "@/hooks/use-global-loading"; import { getAuthErrorDetails, shouldRetry } from "@/lib/auth-errors"; import { setRedirectPath } from "@/lib/auth-utils"; @@ -154,10 +155,12 @@ function LoginContent() {

{urlError.title}

{urlError.message}

- + )} diff --git a/surfsense_web/app/(home)/register/page.tsx b/surfsense_web/app/(home)/register/page.tsx index 00f142567..1fd1a4ecb 100644 --- a/surfsense_web/app/(home)/register/page.tsx +++ b/surfsense_web/app/(home)/register/page.tsx @@ -9,6 +9,7 @@ import { useEffect, useState } from "react"; import { type ExternalToast, toast } from "sonner"; import { registerMutationAtom } from "@/atoms/auth/auth-mutation.atoms"; import { Logo } from "@/components/Logo"; +import { Button } from "@/components/ui/button"; import { Spinner } from "@/components/ui/spinner"; import { getAuthErrorDetails, isNetworkError, shouldRetry } from "@/lib/auth-errors"; import { getBearerToken } from "@/lib/auth-utils"; @@ -199,11 +200,13 @@ export default function RegisterPage() {

{error.title}

{error.message}

- + )} @@ -295,18 +298,18 @@ export default function RegisterPage() { /> - +
diff --git a/surfsense_web/app/dashboard/[search_space_id]/buy-more/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/buy-more/page.tsx index d5f1d0539..ba13a6239 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/buy-more/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/buy-more/page.tsx @@ -4,6 +4,7 @@ import { motion } from "motion/react"; import { useState } from "react"; import { BuyPagesContent } from "@/components/settings/buy-pages-content"; import { BuyTokensContent } from "@/components/settings/buy-tokens-content"; +import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; const TABS = [ @@ -26,19 +27,21 @@ export default function BuyMorePage() { >
{TABS.map((tab) => ( - + ))}
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 c431ab304..604e241f9 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 @@ -44,6 +44,7 @@ import { } from "@/components/assistant-ui/edit-message-dialog"; import { StepSeparatorDataUI } from "@/components/assistant-ui/step-separator"; import { Thread } from "@/components/assistant-ui/thread"; +import { Button } from "@/components/ui/button"; import { createTokenUsageStore, type TokenUsageData, @@ -76,8 +77,6 @@ import { import { createStreamFlushHelpers } from "@/lib/chat/stream-flush"; import { consumeSseEvents, - hasPersistableContent, - markInterruptsCompleted, processSharedStreamEvent, } from "@/lib/chat/stream-pipeline"; import { @@ -88,7 +87,6 @@ import { } from "@/lib/chat/stream-side-effects"; import { addToolCall, - buildContentForPersistence, buildContentForUI, type ContentPartsState, type FrameBatchedUpdater, @@ -1718,8 +1716,19 @@ export default function NewChatPage() { } const byTcId = new Map(); - for (let i = 0; i < tcIds.length; i++) byTcId.set(tcIds[i], incoming[i]); - const submittedDecisions = tcIds.map((id) => byTcId.get(id)!); + const submittedDecisions: typeof incoming = []; + for (let i = 0; i < tcIds.length; i++) { + const tcId = tcIds[i]; + const decision = incoming[i]; + if (tcId === undefined || decision === undefined) { + toast.error( + `Cannot resume: ${incoming.length} decision(s) submitted for ${N} pending actions.` + ); + return; + } + byTcId.set(tcId, decision); + submittedDecisions.push(decision); + } setMessages((prev) => prev.map((m) => { @@ -2341,16 +2350,15 @@ export default function NewChatPage() { return (
Failed to load chat
- +
); } diff --git a/surfsense_web/app/dashboard/[search_space_id]/team/team-content.tsx b/surfsense_web/app/dashboard/[search_space_id]/team/team-content.tsx index 2ab6ef34e..e93ad1799 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/team/team-content.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/team/team-content.tsx @@ -482,13 +482,15 @@ function MemberRow({ {showActions ? ( - + Failed to load agent status {error instanceof Error ? error.message : "Unknown error."} - + ); diff --git a/surfsense_web/app/dashboard/error.tsx b/surfsense_web/app/dashboard/error.tsx index fa71f72bb..85c31e1a0 100644 --- a/surfsense_web/app/dashboard/error.tsx +++ b/surfsense_web/app/dashboard/error.tsx @@ -3,6 +3,7 @@ import { ExternalLink } from "lucide-react"; import Link from "next/link"; import { useEffect, useMemo } from "react"; +import { Button } from "@/components/ui/button"; import { buildIssueUrl } from "@/lib/error-toast"; export default function DashboardError({ @@ -39,13 +40,12 @@ export default function DashboardError({ )}
- + - + (null); const messagesEndRef = useRef(null); const textareaRef = useRef(null); + const modelSlug = model.seo_slug ?? model.model_name; useEffect(() => { anonymousChatApiService.getQuota().then(setQuota).catch(console.error); }, []); useEffect(() => { + if (messages.length === 0) return; messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); - }, [messages]); + }, [messages.length]); const autoResizeTextarea = useCallback(() => { const textarea = textareaRef.current; @@ -63,7 +66,7 @@ export function AnonymousChat({ model }: AnonymousChatProps) { } trackAnonymousChatMessageSent({ - modelSlug: model.seo_slug, + modelSlug, messageLength: trimmed.length, surface: "free_model_page", }); @@ -84,7 +87,7 @@ export function AnonymousChat({ model }: AnonymousChatProps) { headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ - model_slug: model.seo_slug, + model_slug: modelSlug, messages: chatHistory, }), signal: controller.signal, @@ -100,6 +103,7 @@ export function AnonymousChat({ model }: AnonymousChatProps) { remaining: 0, status: "exceeded", warning_threshold: quota?.warning_threshold ?? 800000, + captcha_required: errorData.detail?.captcha_required ?? quota?.captcha_required ?? false, }); setMessages((prev) => prev.filter((m) => m.id !== assistantId)); return; @@ -148,7 +152,7 @@ export function AnonymousChat({ model }: AnonymousChatProps) { abortRef.current = null; anonymousChatApiService.getQuota().then(setQuota).catch(console.error); } - }, [input, isStreaming, messages, model.seo_slug, quota]); + }, [input, isStreaming, messages, modelSlug, quota]); const handleCancel = useCallback(() => { abortRef.current?.abort(); @@ -258,22 +262,26 @@ export function AnonymousChat({ model }: AnonymousChatProps) { )} /> {isStreaming ? ( - + ) : ( - + )}
diff --git a/surfsense_web/components/layout/ui/sidebar/DesktopLocalTabContent.tsx b/surfsense_web/components/layout/ui/sidebar/DesktopLocalTabContent.tsx index 3730f0e53..473a4894b 100644 --- a/surfsense_web/components/layout/ui/sidebar/DesktopLocalTabContent.tsx +++ b/surfsense_web/components/layout/ui/sidebar/DesktopLocalTabContent.tsx @@ -9,9 +9,9 @@ import { DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, - DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; +import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Separator } from "@/components/ui/separator"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; @@ -65,29 +65,30 @@ export function DesktopLocalTabContent({ return (
-
+
{localRootPaths.length > 0 ? ( - + Selected folders - {localRootPaths.map((rootPath) => ( {getFolderDisplayName(rootPath)} - + ))} - ) : (
- + No local folders selected
)} @@ -140,9 +142,11 @@ export function DesktopLocalTabContent({ - + @@ -177,9 +181,11 @@ export function DesktopLocalTabContent({ aria-label="Search local files" /> {Boolean(localSearch) && ( - + )}
diff --git a/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx index 017f14adf..98943a6e4 100644 --- a/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx +++ b/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx @@ -1043,82 +1043,84 @@ function AuthenticatedDocumentsSidebarBase({ const cloudContent = ( <> {/* Connected tools strip */} -
- -
+ } + )} + + {isElectron && ( - + + Watch local folder + )}
@@ -1139,15 +1141,17 @@ function AuthenticatedDocumentsSidebarBase({
{deletableSelectedIds.length > 0 && (
- +
)} @@ -1762,42 +1766,42 @@ function AnonymousDocumentsSidebar({
{/* Connectors strip (gated) */} -
- -
+ {/* Filters & upload */}
@@ -1849,18 +1853,19 @@ function AnonymousDocumentsSidebar({ {!hasDoc && (
- +

Text, code, CSV, and HTML files only. Create an account for PDFs, images, and 30+ connectors. diff --git a/surfsense_web/components/onboarding-tour.tsx b/surfsense_web/components/onboarding-tour.tsx index 86caaf543..a3c530ac0 100644 --- a/surfsense_web/components/onboarding-tour.tsx +++ b/surfsense_web/components/onboarding-tour.tsx @@ -9,6 +9,7 @@ import { createPortal } from "react-dom"; import { connectorsAtom } from "@/atoms/connectors/connector-query.atoms"; import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms"; import { currentUserAtom } from "@/atoms/user/user-query.atoms"; +import { Button } from "@/components/ui/button"; import { useIsMobile } from "@/hooks/use-mobile"; import { useZeroDocumentTypeCounts } from "@/hooks/use-zero-document-type-counts"; import { fetchThreads } from "@/lib/chat/thread-persistence"; @@ -322,39 +323,45 @@ function TourTooltip({ {/* Navigation buttons */}

{!isFirstStep && ( - + )} {isFirstStep && ( - + )} - +
@@ -714,9 +721,10 @@ export function OnboardingTour() { `}
{/* Clickable backdrop to close */} -