"use client"; import { AlertCircle, ArrowLeft } from "lucide-react"; import { useParams, useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { type CloudFile, UnifiedCloudPicker } from "@/components/cloud-picker"; import type { IngestSettings } from "@/components/cloud-picker/types"; import { Button } from "@/components/ui/button"; import { useTask } from "@/contexts/task-context"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; // CloudFile interface is now imported from the unified cloud picker interface CloudConnector { id: string; name: string; description: string; status: "not_connected" | "connecting" | "connected" | "error"; type: string; connectionId?: string; clientId: string; hasAccessToken: boolean; accessTokenError?: string; } export default function UploadProviderPage() { const params = useParams(); const router = useRouter(); const provider = params.provider as string; const { addTask, tasks } = useTask(); const [connector, setConnector] = useState(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [accessToken, setAccessToken] = useState(null); const [selectedFiles, setSelectedFiles] = useState([]); const [isIngesting, setIsIngesting] = useState(false); const [currentSyncTaskId, setCurrentSyncTaskId] = useState( null, ); const [ingestSettings, setIngestSettings] = useState({ chunkSize: 1000, chunkOverlap: 200, ocr: false, pictureDescriptions: false, embeddingModel: "text-embedding-3-small", }); useEffect(() => { const fetchConnectorInfo = async () => { setIsLoading(true); setError(null); try { // Fetch available connectors to validate the provider const connectorsResponse = await fetch("/api/connectors"); if (!connectorsResponse.ok) { throw new Error("Failed to load connectors"); } const connectorsResult = await connectorsResponse.json(); const providerInfo = connectorsResult.connectors[provider]; if (!providerInfo || !providerInfo.available) { setError( `Cloud provider "${provider}" is not available or configured.`, ); return; } // Check connector status const statusResponse = await fetch( `/api/connectors/${provider}/status`, ); if (!statusResponse.ok) { throw new Error(`Failed to check ${provider} status`); } const statusData = await statusResponse.json(); const connections = statusData.connections || []; const activeConnection = connections.find( (conn: { is_active: boolean; connection_id: string }) => conn.is_active, ); const isConnected = activeConnection !== undefined; let hasAccessToken = false; let accessTokenError: string | undefined; // Try to get access token for connected connectors if (isConnected && activeConnection) { try { const tokenResponse = await fetch( `/api/connectors/${provider}/token?connection_id=${activeConnection.connection_id}`, ); if (tokenResponse.ok) { const tokenData = await tokenResponse.json(); if (tokenData.access_token) { hasAccessToken = true; setAccessToken(tokenData.access_token); } } else { const errorData = await tokenResponse .json() .catch(() => ({ error: "Token unavailable" })); accessTokenError = errorData.error || "Access token unavailable"; } } catch { accessTokenError = "Failed to fetch access token"; } } setConnector({ id: provider, name: providerInfo.name, description: providerInfo.description, status: isConnected ? "connected" : "not_connected", type: provider, connectionId: activeConnection?.connection_id, clientId: activeConnection?.client_id, hasAccessToken, accessTokenError, }); } catch (error) { console.error("Failed to load connector info:", error); setError( error instanceof Error ? error.message : "Failed to load connector information", ); } finally { setIsLoading(false); } }; if (provider) { fetchConnectorInfo(); } }, [provider]); // Watch for sync task completion and redirect useEffect(() => { if (!currentSyncTaskId) return; const currentTask = tasks.find( (task) => task.task_id === currentSyncTaskId, ); if (currentTask && currentTask.status === "completed") { // Task completed successfully, show toast and redirect setIsIngesting(false); setTimeout(() => { router.push("/knowledge"); }, 2000); // 2 second delay to let user see toast } else if (currentTask && currentTask.status === "failed") { // Task failed, clear the tracking but don't redirect setIsIngesting(false); setCurrentSyncTaskId(null); } }, [tasks, currentSyncTaskId, router]); const handleFileSelected = (files: CloudFile[]) => { setSelectedFiles(files); console.log(`Selected ${files.length} item(s) from ${provider}:`, files); // You can add additional handling here like triggering sync, etc. }; const handleSync = async (connector: CloudConnector) => { if (!connector.connectionId || selectedFiles.length === 0) return; setIsIngesting(true); try { const syncBody: { connection_id: string; max_files?: number; selected_files?: string[]; settings?: IngestSettings; } = { connection_id: connector.connectionId, selected_files: selectedFiles.map((file) => file.id), settings: ingestSettings, }; const response = await fetch(`/api/connectors/${connector.type}/sync`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(syncBody), }); const result = await response.json(); if (response.status === 201) { const taskIds = result.task_ids; if (taskIds && taskIds.length > 0) { const taskId = taskIds[0]; // Use the first task ID addTask(taskId); setCurrentSyncTaskId(taskId); } } else { console.error("Sync failed:", result.error); } } catch (error) { console.error("Sync error:", error); setIsIngesting(false); } }; const getProviderDisplayName = () => { const nameMap: { [key: string]: string } = { google_drive: "Google Drive", onedrive: "OneDrive", sharepoint: "SharePoint", }; return nameMap[provider] || provider; }; if (isLoading) { return (

Loading {getProviderDisplayName()} connector...

); } if (error || !connector) { return ( <>

Provider Not Available

{error}

); } if (connector.status !== "connected") { return ( <>

{connector.name} Not Connected

You need to connect your {connector.name} account before you can select files.

); } if (!connector.hasAccessToken) { return ( <>

Access Token Required

{connector.accessTokenError || `Unable to get access token for ${connector.name}. Try reconnecting your account.`}

); } const hasSelectedFiles = selectedFiles.length > 0; return ( <>

Add from {getProviderDisplayName()}

{!hasSelectedFiles ? ( Select at least one item before ingesting ) : null}
); }