From 198c38b335a27cb2af72e0320cbfbc0e7d580fca Mon Sep 17 00:00:00 2001
From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com>
Date: Thu, 14 May 2026 13:30:20 +0530
Subject: [PATCH] refactor: replace button elements with Button component for
consistent styling across various UI components
---
.../app/(home)/login/LocalLoginForm.tsx | 23 +-
surfsense_web/app/(home)/login/page.tsx | 9 +-
surfsense_web/app/(home)/register/page.tsx | 17 +-
.../[search_space_id]/buy-more/page.tsx | 9 +-
.../new-chat/[[...chat_id]]/page.tsx | 24 ++-
.../[search_space_id]/team/team-content.tsx | 8 +-
.../components/AgentStatusContent.tsx | 9 +-
surfsense_web/app/dashboard/error.tsx | 6 +-
surfsense_web/app/error.tsx | 6 +-
.../components/free-chat/anonymous-chat.tsx | 28 ++-
.../ui/sidebar/DesktopLocalTabContent.tsx | 44 ++--
.../layout/ui/sidebar/DocumentsSidebar.tsx | 201 +++++++++---------
surfsense_web/components/onboarding-tour.tsx | 30 ++-
13 files changed, 234 insertions(+), 180 deletions(-)
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() {
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
-
+
+
Watch local folder
+
)}
@@ -1139,15 +1141,17 @@ function AuthenticatedDocumentsSidebarBase({
{deletableSelectedIds.length > 0 && (
- setBulkDeleteConfirmOpen(true)}
- className="pointer-events-auto flex items-center gap-1.5 px-3 py-1 rounded-md bg-destructive text-destructive-foreground shadow-lg text-xs font-medium hover:bg-destructive/90 transition-colors"
+ className="pointer-events-auto h-auto gap-1.5 px-3 py-1 text-xs shadow-lg"
>
Delete {deletableSelectedIds.length}{" "}
{deletableSelectedIds.length === 1 ? "item" : "items"}
-
+
)}
@@ -1762,42 +1766,42 @@ function AnonymousDocumentsSidebar({
{/* Connectors strip (gated) */}
-
-
gate("connect your data sources")}
- className="flex min-w-0 flex-1 items-center gap-2 px-3 py-1.5 text-left"
- >
-
- Connect your connectors
-
- {(isMobile ? SHOWCASE_CONNECTORS.slice(0, 5) : SHOWCASE_CONNECTORS).map(
- ({ type, label }, i) => {
- const avatar = (
-
-
- {getConnectorIcon(type, "size-3.5")}
-
-
- );
- if (isMobile) return avatar;
- return (
-
- {avatar}
-
- {label}
-
-
- );
- }
- )}
-
-
-
+
gate("connect your data sources")}
+ className="shrink-0 mx-4 mt-6 mb-2.5 h-auto select-none justify-start gap-2 border bg-muted/50 px-3 py-1.5 text-xs text-muted-foreground"
+ >
+
+ Connect your connectors
+
+ {(isMobile ? SHOWCASE_CONNECTORS.slice(0, 5) : SHOWCASE_CONNECTORS).map(
+ ({ type, label }, i) => {
+ const avatar = (
+
+
+ {getConnectorIcon(type, "size-3.5")}
+
+
+ );
+ if (isMobile) return avatar;
+ return (
+
+ {avatar}
+
+ {label}
+
+
+ );
+ }
+ )}
+
+
{/* Filters & upload */}
@@ -1849,18 +1853,19 @@ function AnonymousDocumentsSidebar({
{!hasDoc && (
-
Upload a document
{isUploading && }
-
+
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 && (
- {
e.stopPropagation();
onPrev();
}}
- className="text-sm font-medium text-muted-foreground transition-opacity hover:opacity-80"
+ className="h-auto px-0 py-0 text-sm text-muted-foreground hover:bg-transparent hover:text-muted-foreground hover:opacity-80"
>
Back
-
+
)}
{isFirstStep && (
- {
e.stopPropagation();
onSkip();
}}
- className="text-sm font-medium text-muted-foreground transition-opacity hover:opacity-80"
+ className="h-auto px-0 py-0 text-sm text-muted-foreground hover:bg-transparent hover:text-muted-foreground hover:opacity-80"
>
Skip
-
+
)}
- {
e.stopPropagation();
onNext();
}}
- className="text-sm font-medium text-foreground transition-opacity hover:opacity-80"
+ className="h-auto px-0 py-0 text-sm text-foreground hover:bg-transparent hover:text-foreground hover:opacity-80"
>
{isLastStep ? "Done" : "Next"}
-
+
@@ -714,9 +721,10 @@ export function OnboardingTour() {
`}
{/* Clickable backdrop to close */}
-