"use client" import { useState, useEffect, useRef } from "react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Card, CardContent } from "@/components/ui/card" import { Label } from "@/components/ui/label" import { Textarea } from "@/components/ui/textarea" import { ChevronDown, Filter, Search, X, Loader2, Plus, Save } from "lucide-react" import { cn } from "@/lib/utils" interface KnowledgeFilter { id: string name: string description: string query_data: string owner: string created_at: string updated_at: string } interface ParsedQueryData { query: string filters: { data_sources: string[] document_types: string[] owners: string[] } limit: number scoreThreshold: number } interface KnowledgeFilterDropdownProps { selectedFilter: KnowledgeFilter | null onFilterSelect: (filter: KnowledgeFilter | null) => void } export function KnowledgeFilterDropdown({ selectedFilter, onFilterSelect }: KnowledgeFilterDropdownProps) { const [isOpen, setIsOpen] = useState(false) const [filters, setFilters] = useState([]) const [loading, setLoading] = useState(false) const [searchQuery, setSearchQuery] = useState("") const [showCreateModal, setShowCreateModal] = useState(false) const [createName, setCreateName] = useState("") const [createDescription, setCreateDescription] = useState("") const [creating, setCreating] = useState(false) const dropdownRef = useRef(null) const loadFilters = async (query = "") => { setLoading(true) try { const response = await fetch("/api/knowledge-filter/search", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ query, limit: 20 // Limit for dropdown }), }) const result = await response.json() if (response.ok && result.success) { setFilters(result.filters) } else { console.error("Failed to load knowledge filters:", result.error) setFilters([]) } } catch (error) { console.error("Error loading knowledge filters:", error) setFilters([]) } finally { setLoading(false) } } const deleteFilter = async (filterId: string, e: React.MouseEvent) => { e.stopPropagation() try { const response = await fetch(`/api/knowledge-filter/${filterId}`, { method: "DELETE", }) if (response.ok) { // Remove from local state setFilters(prev => prev.filter(f => f.id !== filterId)) // If this was the selected filter, clear selection if (selectedFilter?.id === filterId) { onFilterSelect(null) } } else { console.error("Failed to delete knowledge filter") } } catch (error) { console.error("Error deleting knowledge filter:", error) } } const handleFilterSelect = (filter: KnowledgeFilter) => { onFilterSelect(filter) setIsOpen(false) } const handleClearFilter = () => { onFilterSelect(null) setIsOpen(false) } const handleCreateNew = () => { setIsOpen(false) setShowCreateModal(true) } const handleCreateFilter = async () => { if (!createName.trim()) return setCreating(true) try { // Create a basic filter with wildcards (match everything by default) const defaultFilterData = { query: "", filters: { data_sources: ["*"], document_types: ["*"], owners: ["*"] }, limit: 10, scoreThreshold: 0 } const response = await fetch("/api/knowledge-filter", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ name: createName.trim(), description: createDescription.trim(), queryData: JSON.stringify(defaultFilterData) }), }) const result = await response.json() if (response.ok && result.success) { // Create the new filter object const newFilter: KnowledgeFilter = { id: result.filter.id, name: createName.trim(), description: createDescription.trim(), query_data: JSON.stringify(defaultFilterData), owner: result.filter.owner, created_at: result.filter.created_at, updated_at: result.filter.updated_at } // Add to local filters list setFilters(prev => [newFilter, ...prev]) // Select the new filter onFilterSelect(newFilter) // Close modal and reset form setShowCreateModal(false) setCreateName("") setCreateDescription("") } else { console.error("Failed to create knowledge filter:", result.error) } } catch (error) { console.error("Error creating knowledge filter:", error) } finally { setCreating(false) } } const handleCancelCreate = () => { setShowCreateModal(false) setCreateName("") setCreateDescription("") } const getFilterSummary = (filter: KnowledgeFilter): string => { try { const parsed = JSON.parse(filter.query_data) as ParsedQueryData const parts = [] if (parsed.query) parts.push(`"${parsed.query}"`) if (parsed.filters.data_sources.length > 0) parts.push(`${parsed.filters.data_sources.length} sources`) if (parsed.filters.document_types.length > 0) parts.push(`${parsed.filters.document_types.length} types`) if (parsed.filters.owners.length > 0) parts.push(`${parsed.filters.owners.length} owners`) return parts.join(" • ") || "No filters" } catch { return "Invalid filter" } } useEffect(() => { if (isOpen) { loadFilters() } }, [isOpen]) useEffect(() => { const timeoutId = setTimeout(() => { if (isOpen) { loadFilters(searchQuery) } }, 300) return () => clearTimeout(timeoutId) }, [searchQuery, isOpen]) // Close dropdown when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setIsOpen(false) } } document.addEventListener("mousedown", handleClickOutside) return () => document.removeEventListener("mousedown", handleClickOutside) }, []) return (
{isOpen && ( {/* Search Header */}
setSearchQuery(e.target.value)} className="pl-9 h-8 text-sm" />
{/* Filter List */}
{/* Clear filter option */}
All Knowledge
No filters applied
{loading ? (
Loading...
) : filters.length === 0 ? (
{searchQuery ? "No filters found" : "No saved filters"}
) : ( filters.map((filter) => (
handleFilterSelect(filter)} className={cn( "flex items-center gap-3 p-3 hover:bg-accent hover:text-accent-foreground cursor-pointer group transition-colors", selectedFilter?.id === filter.id && "bg-accent text-accent-foreground" )} >
{filter.name}
{getFilterSummary(filter)}
)) )}
{/* Create New Filter Option */}
Create New Filter
Save current search as filter
{/* Selected Filter Details */} {selectedFilter && (
Selected: {selectedFilter.name}
{selectedFilter.description && (
{selectedFilter.description}
)}
)}
)} {/* Create Filter Modal */} {showCreateModal && (

Create New Knowledge Filter

setCreateName(e.target.value)} className="mt-1" />