frontend bug fix and lint
This commit is contained in:
parent
91f0b608b5
commit
40cac9950c
5 changed files with 75 additions and 59 deletions
|
|
@ -4,7 +4,7 @@ import { useState, useEffect, useRef } from "react"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Card, CardContent } from "@/components/ui/card"
|
import { Card, CardContent } from "@/components/ui/card"
|
||||||
import { Badge } from "@/components/ui/badge"
|
|
||||||
import { Label } from "@/components/ui/label"
|
import { Label } from "@/components/ui/label"
|
||||||
import { Textarea } from "@/components/ui/textarea"
|
import { Textarea } from "@/components/ui/textarea"
|
||||||
import { ChevronDown, Filter, Search, X, Loader2, Plus, Save } from "lucide-react"
|
import { ChevronDown, Filter, Search, X, Loader2, Plus, Save } from "lucide-react"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import { Filter, X, Edit3, Save, Settings, ChevronDown, ChevronUp, RefreshCw } from 'lucide-react'
|
import { X, Edit3, Save, Settings, ChevronDown, ChevronUp, RefreshCw } from 'lucide-react'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
|
|
@ -11,16 +11,6 @@ import { Checkbox } from '@/components/ui/checkbox'
|
||||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
|
||||||
import { useKnowledgeFilter } from '@/contexts/knowledge-filter-context'
|
import { useKnowledgeFilter } from '@/contexts/knowledge-filter-context'
|
||||||
|
|
||||||
interface ParsedQueryData {
|
|
||||||
query: string
|
|
||||||
filters: {
|
|
||||||
data_sources: string[]
|
|
||||||
document_types: string[]
|
|
||||||
owners: string[]
|
|
||||||
}
|
|
||||||
limit: number
|
|
||||||
scoreThreshold: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FacetBucket {
|
interface FacetBucket {
|
||||||
key: string
|
key: string
|
||||||
|
|
@ -143,14 +133,7 @@ export function KnowledgeFilterPanel() {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleFilterChange = (facetType: keyof typeof selectedFilters, value: string, checked: boolean) => {
|
|
||||||
setSelectedFilters(prev => ({
|
|
||||||
...prev,
|
|
||||||
[facetType]: checked
|
|
||||||
? [...prev[facetType], value]
|
|
||||||
: prev[facetType].filter(item => item !== value)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectAllFilters = () => {
|
const selectAllFilters = () => {
|
||||||
// Use wildcards instead of listing all specific items
|
// Use wildcards instead of listing all specific items
|
||||||
|
|
@ -276,7 +259,6 @@ export function KnowledgeFilterPanel() {
|
||||||
if (!buckets || buckets.length === 0) return null
|
if (!buckets || buckets.length === 0) return null
|
||||||
|
|
||||||
const isAllSelected = selectedFilters[facetType].includes("*") // Wildcard
|
const isAllSelected = selectedFilters[facetType].includes("*") // Wildcard
|
||||||
const hasSpecificSelections = selectedFilters[facetType].some(item => item !== "*")
|
|
||||||
|
|
||||||
const handleAllToggle = (checked: boolean) => {
|
const handleAllToggle = (checked: boolean) => {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
|
|
|
||||||
|
|
@ -236,12 +236,6 @@ function ChatPage() {
|
||||||
inputRef.current?.focus()
|
inputRef.current?.focus()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// Update input when global filter query changes
|
|
||||||
useEffect(() => {
|
|
||||||
if (parsedFilterData?.query) {
|
|
||||||
setInput(parsedFilterData.query)
|
|
||||||
}
|
|
||||||
}, [parsedFilterData])
|
|
||||||
|
|
||||||
const handleSSEStream = async (userMessage: Message) => {
|
const handleSSEStream = async (userMessage: Message) => {
|
||||||
const apiEndpoint = endpoint === "chat" ? "/api/chat" : "/api/langflow"
|
const apiEndpoint = endpoint === "chat" ? "/api/chat" : "/api/langflow"
|
||||||
|
|
@ -252,17 +246,21 @@ function ChatPage() {
|
||||||
stream: true,
|
stream: true,
|
||||||
...(parsedFilterData?.filters && (() => {
|
...(parsedFilterData?.filters && (() => {
|
||||||
const filters = parsedFilterData.filters
|
const filters = parsedFilterData.filters
|
||||||
const processed: SelectedFilters = {}
|
const processed: SelectedFilters = {
|
||||||
if (!filters.data_sources.includes("*")) {
|
data_sources: [],
|
||||||
processed.data_sources = filters.data_sources
|
document_types: [],
|
||||||
|
owners: []
|
||||||
}
|
}
|
||||||
if (!filters.document_types.includes("*")) {
|
// Only copy non-wildcard arrays
|
||||||
processed.document_types = filters.document_types
|
processed.data_sources = filters.data_sources.includes("*") ? [] : filters.data_sources
|
||||||
}
|
processed.document_types = filters.document_types.includes("*") ? [] : filters.document_types
|
||||||
if (!filters.owners.includes("*")) {
|
processed.owners = filters.owners.includes("*") ? [] : filters.owners
|
||||||
processed.owners = filters.owners
|
|
||||||
}
|
// Only include filters if any array has values
|
||||||
return Object.keys(processed).length > 0 ? { filters: processed } : {}
|
const hasFilters = processed.data_sources.length > 0 ||
|
||||||
|
processed.document_types.length > 0 ||
|
||||||
|
processed.owners.length > 0
|
||||||
|
return hasFilters ? { filters: processed } : {}
|
||||||
})()),
|
})()),
|
||||||
limit: parsedFilterData?.limit ?? 10,
|
limit: parsedFilterData?.limit ?? 10,
|
||||||
scoreThreshold: parsedFilterData?.scoreThreshold ?? 0
|
scoreThreshold: parsedFilterData?.scoreThreshold ?? 0
|
||||||
|
|
@ -725,17 +723,21 @@ function ChatPage() {
|
||||||
prompt: userMessage.content,
|
prompt: userMessage.content,
|
||||||
...(parsedFilterData?.filters && (() => {
|
...(parsedFilterData?.filters && (() => {
|
||||||
const filters = parsedFilterData.filters
|
const filters = parsedFilterData.filters
|
||||||
const processed: SelectedFilters = {}
|
const processed: SelectedFilters = {
|
||||||
if (!filters.data_sources.includes("*")) {
|
data_sources: [],
|
||||||
processed.data_sources = filters.data_sources
|
document_types: [],
|
||||||
|
owners: []
|
||||||
}
|
}
|
||||||
if (!filters.document_types.includes("*")) {
|
// Only copy non-wildcard arrays
|
||||||
processed.document_types = filters.document_types
|
processed.data_sources = filters.data_sources.includes("*") ? [] : filters.data_sources
|
||||||
}
|
processed.document_types = filters.document_types.includes("*") ? [] : filters.document_types
|
||||||
if (!filters.owners.includes("*")) {
|
processed.owners = filters.owners.includes("*") ? [] : filters.owners
|
||||||
processed.owners = filters.owners
|
|
||||||
}
|
// Only include filters if any array has values
|
||||||
return Object.keys(processed).length > 0 ? { filters: processed } : {}
|
const hasFilters = processed.data_sources.length > 0 ||
|
||||||
|
processed.document_types.length > 0 ||
|
||||||
|
processed.owners.length > 0
|
||||||
|
return hasFilters ? { filters: processed } : {}
|
||||||
})()),
|
})()),
|
||||||
limit: parsedFilterData?.limit ?? 10,
|
limit: parsedFilterData?.limit ?? 10,
|
||||||
scoreThreshold: parsedFilterData?.scoreThreshold ?? 0
|
scoreThreshold: parsedFilterData?.scoreThreshold ?? 0
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Label } from "@/components/ui/label"
|
import { Label } from "@/components/ui/label"
|
||||||
import { Upload, FolderOpen, Loader2, PlugZap, CheckCircle, XCircle, RefreshCw, Download, AlertCircle, Database } from "lucide-react"
|
import { Upload, FolderOpen, Loader2, PlugZap, RefreshCw, Download } from "lucide-react"
|
||||||
import { ProtectedRoute } from "@/components/protected-route"
|
import { ProtectedRoute } from "@/components/protected-route"
|
||||||
import { useTask } from "@/contexts/task-context"
|
import { useTask } from "@/contexts/task-context"
|
||||||
import { useAuth } from "@/contexts/auth-context"
|
import { useAuth } from "@/contexts/auth-context"
|
||||||
|
|
@ -42,7 +42,7 @@ interface Connection {
|
||||||
|
|
||||||
function KnowledgeSourcesPage() {
|
function KnowledgeSourcesPage() {
|
||||||
const { isAuthenticated } = useAuth()
|
const { isAuthenticated } = useAuth()
|
||||||
const { addTask, refreshTasks, tasks } = useTask()
|
const { addTask, tasks } = useTask()
|
||||||
const searchParams = useSearchParams()
|
const searchParams = useSearchParams()
|
||||||
|
|
||||||
// File upload state
|
// File upload state
|
||||||
|
|
@ -319,8 +319,8 @@ function KnowledgeSourcesPage() {
|
||||||
const result = await response.json()
|
const result = await response.json()
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const aggs = result.aggregations || {}
|
const aggs = result.aggregations || {}
|
||||||
const toBuckets = (agg: any): FacetBucket[] =>
|
const toBuckets = (agg: { buckets?: Array<{ key: string | number; doc_count: number }> }): FacetBucket[] =>
|
||||||
(agg?.buckets || []).map((b: any) => ({ key: String(b.key), count: b.doc_count }))
|
(agg?.buckets || []).map(b => ({ key: String(b.key), count: b.doc_count }))
|
||||||
const dataSourceBuckets = toBuckets(aggs.data_sources)
|
const dataSourceBuckets = toBuckets(aggs.data_sources)
|
||||||
setFacetStats({
|
setFacetStats({
|
||||||
data_sources: dataSourceBuckets.slice(0, 10),
|
data_sources: dataSourceBuckets.slice(0, 10),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from "react"
|
import { useState, useEffect, useCallback, useRef } from "react"
|
||||||
import { useSearchParams } from "next/navigation"
|
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
|
|
@ -26,12 +26,13 @@ interface SearchResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
function SearchPage() {
|
function SearchPage() {
|
||||||
const searchParams = useSearchParams()
|
|
||||||
const { selectedFilter, parsedFilterData } = useKnowledgeFilter()
|
const { selectedFilter, parsedFilterData } = useKnowledgeFilter()
|
||||||
const [query, setQuery] = useState("")
|
const [query, setQuery] = useState("")
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [results, setResults] = useState<SearchResult[]>([])
|
const [results, setResults] = useState<SearchResult[]>([])
|
||||||
const [searchPerformed, setSearchPerformed] = useState(false)
|
const [searchPerformed, setSearchPerformed] = useState(false)
|
||||||
|
const prevFilterDataRef = useRef<string>("")
|
||||||
|
|
||||||
const handleSearch = useCallback(async (e?: React.FormEvent) => {
|
const handleSearch = useCallback(async (e?: React.FormEvent) => {
|
||||||
if (e) e.preventDefault()
|
if (e) e.preventDefault()
|
||||||
|
|
@ -42,7 +43,18 @@ function SearchPage() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Build search payload with global filter data
|
// Build search payload with global 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,
|
query,
|
||||||
limit: parsedFilterData?.limit || 10,
|
limit: parsedFilterData?.limit || 10,
|
||||||
scoreThreshold: parsedFilterData?.scoreThreshold || 0
|
scoreThreshold: parsedFilterData?.scoreThreshold || 0
|
||||||
|
|
@ -59,7 +71,7 @@ function SearchPage() {
|
||||||
!filters.owners.includes("*")
|
!filters.owners.includes("*")
|
||||||
|
|
||||||
if (hasSpecificFilters) {
|
if (hasSpecificFilters) {
|
||||||
const processedFilters: any = {}
|
const processedFilters: SearchPayload['filters'] = {}
|
||||||
|
|
||||||
// Only add filter arrays that don't contain wildcards
|
// Only add filter arrays that don't contain wildcards
|
||||||
if (!filters.data_sources.includes("*")) {
|
if (!filters.data_sources.includes("*")) {
|
||||||
|
|
@ -114,12 +126,32 @@ function SearchPage() {
|
||||||
}
|
}
|
||||||
}, [parsedFilterData])
|
}, [parsedFilterData])
|
||||||
|
|
||||||
// Auto-refresh search when filter changes (if search was already performed)
|
// Auto-refresh search when filter changes (but only if search was already performed)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (searchPerformed && query.trim()) {
|
if (!parsedFilterData) return
|
||||||
|
|
||||||
|
// Create a stable string representation of the filter data for comparison
|
||||||
|
const currentFilterString = JSON.stringify({
|
||||||
|
filters: parsedFilterData.filters,
|
||||||
|
limit: parsedFilterData.limit,
|
||||||
|
scoreThreshold: parsedFilterData.scoreThreshold
|
||||||
|
})
|
||||||
|
|
||||||
|
// Only trigger search if filter data actually changed and we've done a search before
|
||||||
|
if (prevFilterDataRef.current !== "" &&
|
||||||
|
prevFilterDataRef.current !== currentFilterString &&
|
||||||
|
searchPerformed &&
|
||||||
|
query.trim()) {
|
||||||
|
|
||||||
|
console.log("Filter changed, auto-refreshing search")
|
||||||
handleSearch()
|
handleSearch()
|
||||||
}
|
}
|
||||||
}, [parsedFilterData]) // Only depend on parsedFilterData to avoid infinite loop
|
|
||||||
|
// Update the ref with current filter data
|
||||||
|
prevFilterDataRef.current = currentFilterString
|
||||||
|
}, [parsedFilterData, searchPerformed, query, handleSearch])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue