diff --git a/frontend/components/navigation.tsx b/frontend/components/navigation.tsx
index 1311a550..1d540e97 100644
--- a/frontend/components/navigation.tsx
+++ b/frontend/components/navigation.tsx
@@ -2,7 +2,7 @@
import Link from "next/link"
import { usePathname } from "next/navigation"
-import { Library, Database, MessageSquare, Settings2 } from "lucide-react"
+import { Library, MessageSquare, Settings2 } from "lucide-react"
import { cn } from "@/lib/utils"
export function Navigation() {
@@ -18,14 +18,14 @@ export function Navigation() {
{
label: "Knowledge",
icon: Library,
- href: "/search",
- active: pathname === "/search",
+ href: "/knowledge",
+ active: pathname === "/knowledge",
},
{
label: "Settings",
icon: Settings2,
- href: "/knowledge-sources",
- active: pathname === "/knowledge-sources",
+ href: "/settings",
+ active: pathname === "/settings",
},
]
@@ -33,7 +33,7 @@ export function Navigation() {
- {routes.map((route, index) => (
+ {routes.map((route) => (
(null)
- const inputRef = useRef
(null)
+ const inputRef = useRef(null)
const { addTask } = useTask()
const { selectedFilter, parsedFilterData } = useKnowledgeFilter()
@@ -1125,44 +1123,29 @@ function ChatPage() {
) : (
<>
{messages.map((message, index) => (
-
+
{message.role === "user" && (
-
-
-
-
-
- {user?.name ? user.name.charAt(0).toUpperCase() : }
-
-
-
{user?.name || "User"}
-
-
+
+
+
+
+ {user?.name ? user.name.charAt(0).toUpperCase() : }
+
+
+
)}
{message.role === "assistant" && (
-
-
-
-
-
-
AI
+
+
+
-
-
-
-
-
Finished
-
- {message.timestamp.toLocaleTimeString()}
-
-
- {renderFunctionCalls(message.functionCalls || [], index)}
-
{message.content}
-
+
+ {renderFunctionCalls(message.functionCalls || [], index)}
+
{message.content}
)}
@@ -1171,46 +1154,30 @@ function ChatPage() {
{/* Streaming Message Display */}
{streamingMessage && (
-
-
-
-
-
-
AI
+
+
+
-
-
-
-
- Streaming...
-
- {streamingMessage.timestamp.toLocaleTimeString()}
-
-
- {renderFunctionCalls(streamingMessage.functionCalls, messages.length)}
-
- {streamingMessage.content}
-
-
-
+
+ {renderFunctionCalls(streamingMessage.functionCalls, messages.length)}
+
+ {streamingMessage.content}
+
+
)}
- {loading && !asyncMode && (
-
-
-
-
-
-
AI
+ {/* Loading animation - shows immediately after user submits */}
+ {loading && (
+
+
+
-
-
@@ -1266,7 +1233,7 @@ function ChatPage() {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault()
if (input.trim() && !loading) {
- handleSubmit(e as any)
+ handleSubmit(e as React.FormEvent
)
}
}
}}
diff --git a/frontend/src/app/search/page.tsx b/frontend/src/app/knowledge/page.tsx
similarity index 96%
rename from frontend/src/app/search/page.tsx
rename to frontend/src/app/knowledge/page.tsx
index 0c93a734..25db537b 100644
--- a/frontend/src/app/search/page.tsx
+++ b/frontend/src/app/knowledge/page.tsx
@@ -3,11 +3,9 @@
import { useState, useEffect, useCallback, useRef } from "react"
import { Button } from "@/components/ui/button"
-import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
-import { Label } from "@/components/ui/label"
import { Badge } from "@/components/ui/badge"
-import { Search, Loader2, FileText, Zap, RefreshCw } from "lucide-react"
+import { Search, Loader2, FileText } from "lucide-react"
import { ProtectedRoute } from "@/components/protected-route"
import { useKnowledgeFilter } from "@/contexts/knowledge-filter-context"
@@ -30,7 +28,7 @@ interface SearchResponse {
function SearchPage() {
- const { selectedFilter, parsedFilterData } = useKnowledgeFilter()
+ const { parsedFilterData } = useKnowledgeFilter()
const [query, setQuery] = useState("")
const [loading, setLoading] = useState(false)
const [results, setResults] = useState([])
@@ -161,12 +159,23 @@ function SearchPage() {
}, [parsedFilterData, searchPerformed, query, handleSearch])
// Fetch stats with current knowledge filter applied
- const fetchStats = async () => {
+ const fetchStats = useCallback(async () => {
try {
setStatsLoading(true)
// Build search payload with current filter data
- const searchPayload: any = {
+ interface SearchPayload {
+ query: string;
+ limit: number;
+ scoreThreshold: number;
+ filters?: {
+ data_sources?: string[];
+ document_types?: string[];
+ owners?: string[];
+ };
+ }
+
+ const searchPayload: SearchPayload = {
query: '*',
limit: 0,
scoreThreshold: parsedFilterData?.scoreThreshold || 0
@@ -183,7 +192,7 @@ function SearchPage() {
!filters.owners.includes("*")
if (hasSpecificFilters) {
- const processedFilters: any = {}
+ const processedFilters: SearchPayload['filters'] = {}
// Only add filter arrays that don't contain wildcards
if (!filters.data_sources.includes("*")) {
@@ -227,12 +236,12 @@ function SearchPage() {
} finally {
setStatsLoading(false)
}
- }
+ }, [parsedFilterData])
// Initial stats fetch and refresh when filter changes
useEffect(() => {
fetchStats()
- }, [parsedFilterData])
+ }, [fetchStats])
diff --git a/frontend/src/app/knowledge-sources/page.tsx b/frontend/src/app/settings/page.tsx
similarity index 81%
rename from frontend/src/app/knowledge-sources/page.tsx
rename to frontend/src/app/settings/page.tsx
index 460fa244..3dfd583b 100644
--- a/frontend/src/app/knowledge-sources/page.tsx
+++ b/frontend/src/app/settings/page.tsx
@@ -62,11 +62,6 @@ function KnowledgeSourcesPage() {
const [syncResults, setSyncResults] = useState<{[key: string]: SyncResult | null}>({})
const [maxFiles, setMaxFiles] = useState(10)
- // Stats state (from wildcard search aggregations)
- const [statsLoading, setStatsLoading] = useState(false)
- const [totalDocs, setTotalDocs] = useState(0)
- const [totalChunks, setTotalChunks] = useState(0)
- const [facetStats, setFacetStats] = useState<{ data_sources: FacetBucket[]; document_types: FacetBucket[]; owners: FacetBucket[] } | null>(null)
// File upload handlers
const handleDirectFileUpload = async (file: File) => {
@@ -87,8 +82,6 @@ function KnowledgeSourcesPage() {
if (response.ok) {
setUploadStatus(`File processed successfully! ID: ${result.id}`)
- // Refresh stats after successful file upload
- fetchStats()
} else {
setUploadStatus(`Error: ${result.error || "Processing failed"}`)
}
@@ -176,9 +169,6 @@ function KnowledgeSourcesPage() {
addTask(taskId)
setUploadStatus(`🔄 Processing started for ${totalFiles} files. Check the task notification panel for real-time progress. (Task ID: ${taskId})`)
setBucketUrl("s3://")
-
- // Refresh stats after successful bucket upload
- fetchStats()
} else {
setUploadStatus(`Error: ${result.error || "Bucket processing failed"}`)
}
@@ -389,37 +379,6 @@ function KnowledgeSourcesPage() {
}
}, [searchParams, isAuthenticated, checkConnectorStatuses])
- // Fetch global stats using match-all wildcard
- const fetchStats = async () => {
- try {
- setStatsLoading(true)
- const response = await fetch('/api/search', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ query: '*', limit: 0 })
- })
- const result = await response.json()
- if (response.ok) {
- const aggs = result.aggregations || {}
- const toBuckets = (agg: { buckets?: Array<{ key: string | number; doc_count: number }> }): FacetBucket[] =>
- (agg?.buckets || []).map(b => ({ key: String(b.key), count: b.doc_count }))
- const dataSourceBuckets = toBuckets(aggs.data_sources)
- setFacetStats({
- data_sources: dataSourceBuckets.slice(0, 10),
- document_types: toBuckets(aggs.document_types).slice(0, 10),
- owners: toBuckets(aggs.owners).slice(0, 10)
- })
- // Frontend-only doc count: number of distinct filenames (data_sources buckets)
- setTotalDocs(dataSourceBuckets.length)
- // Chunk count from hits.total (match_all over chunks)
- setTotalChunks(Number(result.total || 0))
- }
- } catch {
- // non-fatal – keep page functional without stats
- } finally {
- setStatsLoading(false)
- }
- }
// Check AWS availability
useEffect(() => {
@@ -437,10 +396,6 @@ function KnowledgeSourcesPage() {
checkAws()
}, [])
- // Initial stats fetch
- useEffect(() => {
- fetchStats()
- }, [])
// Track previous tasks to detect new completions
const [prevTasks, setPrevTasks] = useState([])
@@ -454,9 +409,9 @@ function KnowledgeSourcesPage() {
})
if (newlyCompletedTasks.length > 0) {
- // Refresh stats when any task newly completes
+ // Task completed - could refresh data here if needed
const timeoutId = setTimeout(() => {
- fetchStats()
+ // Stats refresh removed
}, 1000)
// Update previous tasks state
@@ -471,95 +426,10 @@ function KnowledgeSourcesPage() {
return (
- {/* Hero Section */}
-
-
-
- Knowledge Sources
-
-
-
- Add documents to your knowledge base
-
-
- Import files and folders directly, or connect external services like Google Drive to automatically sync and index your documents.
-
-
-
- {/* Knowledge Overview Stats */}
-
-
-
- Knowledge Overview
-
-
- Snapshot of indexed content
-
-
- {/* Documents row */}
-
-
-
Total documents
-
{statsLoading ? '—' : totalDocs}
-
-
-
- {/* Separator */}
-
-
- {/* Chunks row */}
-
-
-
Total chunks
-
{statsLoading ? '—' : totalChunks}
-
-
-
Top types
-
- {(facetStats?.document_types || []).slice(0,5).map((b) => (
- {b.key} · {b.count}
- ))}
-
-
-
-
Top owners
-
- {(facetStats?.owners || []).slice(0,5).map((b) => (
- {b.key || 'unknown'} · {b.count}
- ))}
-
-
-
-
Top files
-
- {(facetStats?.data_sources || []).slice(0,5).map((b) => (
- {b.key} · {b.count}
- ))}
-
-
-
-
-
-
{/* Upload Section */}
-
Direct Import
-
- Add individual files or process entire folders from your local system
-
+
Import
@@ -686,10 +556,7 @@ function KnowledgeSourcesPage() {
{/* Connectors Section */}
-
Connectors
-
- Connect external services to automatically sync and index your documents
-
+
Cloud Connectors
{/* Sync Settings */}