From 1fef4ee1dfd3e4f8907438a73baa1d84290d1dd5 Mon Sep 17 00:00:00 2001 From: Cole Goldsmith Date: Wed, 22 Oct 2025 15:26:12 -0500 Subject: [PATCH] Refactor knowledge menu icons and use shadcn dropdown --- frontend/components/knowledge-dropdown.tsx | 158 ++++++++----------- frontend/src/app/settings/icons/aws-icon.tsx | 31 ++++ 2 files changed, 93 insertions(+), 96 deletions(-) create mode 100644 frontend/src/app/settings/icons/aws-icon.tsx diff --git a/frontend/components/knowledge-dropdown.tsx b/frontend/components/knowledge-dropdown.tsx index 19ddc387..56aa7def 100644 --- a/frontend/components/knowledge-dropdown.tsx +++ b/frontend/components/knowledge-dropdown.tsx @@ -4,10 +4,11 @@ import { useQueryClient } from "@tanstack/react-query"; import { ChevronDown, Cloud, + File, + Folder, FolderOpen, Loader2, PlugZap, - Upload, } from "lucide-react"; import { useRouter } from "next/navigation"; import { useEffect, useRef, useState } from "react"; @@ -22,18 +23,26 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useTask } from "@/contexts/task-context"; -import { cn } from "@/lib/utils"; import type { File as SearchFile } from "@/src/app/api/queries/useGetSearchQuery"; +import GoogleDriveIcon from "@/app/settings/icons/google-drive-icon"; +import OneDriveIcon from "@/app/settings/icons/one-drive-icon"; +import SharePointIcon from "@/app/settings/icons/share-point-icon"; +import AwsIcon from "@/app/settings/icons/aws-icon"; export function KnowledgeDropdown() { const { addTask } = useTask(); const { refetch: refetchTasks } = useGetTasksQuery(); const queryClient = useQueryClient(); const router = useRouter(); - const [isOpen, setIsOpen] = useState(false); const [showFolderDialog, setShowFolderDialog] = useState(false); const [showS3Dialog, setShowS3Dialog] = useState(false); const [showDuplicateDialog, setShowDuplicateDialog] = useState(false); @@ -55,7 +64,6 @@ export function KnowledgeDropdown() { }; }>({}); const fileInputRef = useRef(null); - const dropdownRef = useRef(null); // Check AWS availability and cloud connectors on mount useEffect(() => { @@ -141,24 +149,6 @@ export function KnowledgeDropdown() { checkAvailability(); }, []); - // Handle click outside to close dropdown - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if ( - dropdownRef.current && - !dropdownRef.current.contains(event.target as Node) - ) { - setIsOpen(false); - } - }; - - if (isOpen) { - document.addEventListener("mousedown", handleClickOutside); - return () => - document.removeEventListener("mousedown", handleClickOutside); - } - }, [isOpen]); - const handleFileUpload = () => { fileInputRef.current?.click(); }; @@ -168,8 +158,7 @@ export function KnowledgeDropdown() { if (files && files.length > 0) { const file = files[0]; - // Close dropdown immediately after file selection - setIsOpen(false); + // File selection will close dropdown automatically try { // Check if filename already exists (using ORIGINAL filename) @@ -427,13 +416,19 @@ export function KnowledgeDropdown() { } }; + // Icon mapping for cloud connectors + const connectorIconMap = { + google_drive: GoogleDriveIcon, + onedrive: OneDriveIcon, + sharepoint: SharePointIcon, + }; + const cloudConnectorItems = Object.entries(cloudConnectors) .filter(([, info]) => info.available) .map(([type, info]) => ({ label: info.name, - icon: PlugZap, + icon: connectorIconMap[type as keyof typeof connectorIconMap] || PlugZap, onClick: async () => { - setIsOpen(false); if (info.connected && info.hasToken) { setIsNavigatingToCloud(true); try { @@ -448,36 +443,30 @@ export function KnowledgeDropdown() { } }, disabled: !info.connected || !info.hasToken, - tooltip: !info.connected - ? `Connect ${info.name} in Settings first` - : !info.hasToken - ? `Reconnect ${info.name} - access token required` - : undefined, })); const menuItems = [ { - label: "Add File", - icon: Upload, + label: "File", + icon: File, onClick: handleFileUpload, }, { - label: "Process Folder", - icon: FolderOpen, - onClick: () => { - setIsOpen(false); - setShowFolderDialog(true); - }, + label: "Folder", + icon: Folder, + onClick: () => setShowFolderDialog(true), + }, + { + label: "Amazon S3", + icon: AwsIcon, + onClick: () => setShowS3Dialog(true), }, ...(awsEnabled ? [ { - label: "Process S3 Bucket", - icon: Cloud, - onClick: () => { - setIsOpen(false); - setShowS3Dialog(true); - }, + label: "Amazon S3", + icon: AwsIcon, + onClick: () => setShowS3Dialog(true), }, ] : []), @@ -490,13 +479,9 @@ export function KnowledgeDropdown() { return ( <> -
- + {!isLoading && } + + + + {menuItems.map((item, index) => ( + + + {item.label} + + ))} + + - {isOpen && !isLoading && ( -
-
- {menuItems.map((item, index) => ( - - ))} -
-
- )} - - -
+ {/* Process Folder Dialog */} @@ -575,7 +541,7 @@ export function KnowledgeDropdown() { type="text" placeholder="/path/to/documents" value={folderPath} - onChange={e => setFolderPath(e.target.value)} + onChange={(e) => setFolderPath(e.target.value)} />
@@ -617,7 +583,7 @@ export function KnowledgeDropdown() { type="text" placeholder="s3://bucket/path" value={bucketUrl} - onChange={e => setBucketUrl(e.target.value)} + onChange={(e) => setBucketUrl(e.target.value)} />
diff --git a/frontend/src/app/settings/icons/aws-icon.tsx b/frontend/src/app/settings/icons/aws-icon.tsx new file mode 100644 index 00000000..f78457f4 --- /dev/null +++ b/frontend/src/app/settings/icons/aws-icon.tsx @@ -0,0 +1,31 @@ +const AwsIcon = ({ className }: { className?: string }) => { + return ( + + + + + + ); +}; + +export default AwsIcon;