import { useState, useRef } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Loader2, Check, AlertTriangle, Upload } from "lucide-react"; import { useTranslation } from "react-i18next"; import { api } from "@/lib/api"; export interface DataSourceConfig { id?: number; name: string; type: string; config: Record; } interface DataSourceFormProps { initialData?: DataSourceConfig | null; onSubmit: (data: Omit) => Promise; onTest: (type: string, config: Record) => Promise; onCancel: () => void; } export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: DataSourceFormProps) { const { t } = useTranslation(); const [name, setName] = useState(initialData?.name || ""); const [type, setType] = useState(initialData?.type || "postgres"); const [config, setConfig] = useState>(initialData?.config || {}); const [isTesting, setIsTesting] = useState(false); const [testResult, setTestResult] = useState<{ success: boolean; message: string } | null>(null); const [isSaving, setIsSaving] = useState(false); const [isUploading, setIsUploading] = useState(false); const fileInputRef = useRef(null); const handleConfigChange = (key: string, value: any) => { setConfig(prev => ({ ...prev, [key]: value })); }; const handleFileSelect = () => { fileInputRef.current?.click(); }; const handleFileUpload = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; setIsUploading(true); const formData = new FormData(); formData.append("file", file); try { // @ts-ignore const res = await api.post("/api/v1/upload/file", formData); if (res && (res as any).url) { handleConfigChange("file_path", (res as any).url); } } catch (error) { console.error("Upload failed", error); alert(t('uploadFailed')); } finally { setIsUploading(false); // Clear input value so same file can be selected again if (fileInputRef.current) { fileInputRef.current.value = ""; } } }; const handleTest = async () => { setIsTesting(true); setTestResult(null); try { const success = await onTest(type, config); setTestResult({ success, message: success ? t('connectionSuccess') : t('connectionFailed'), }); } catch (e: any) { setTestResult({ success: false, message: e.message || t('connectionFailed'), }); } finally { setIsTesting(false); } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setIsSaving(true); try { await onSubmit({ name, type, config }); } finally { setIsSaving(false); } }; const renderConfigFields = () => { switch (type) { case "supabase": return (
handleConfigChange("host", e.target.value)} placeholder="aws-0-[region].pooler.supabase.com" />
handleConfigChange("port", parseInt(e.target.value))} placeholder="6543" />
handleConfigChange("database", e.target.value)} placeholder="postgres" />
handleConfigChange("user", e.target.value)} placeholder="postgres.[project-ref]" />
handleConfigChange("password", e.target.value)} placeholder="••••••" />
{t('orUseSupabaseConnectionString')}
handleConfigChange("connection_string", e.target.value)} placeholder="postgresql://postgres.[project-ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres?sslmode=require" />
); case "postgres": case "postgresql": case "mysql": case "sqlserver": case "oracle": case "redshift": return (
handleConfigChange("host", e.target.value)} placeholder="localhost" />
handleConfigChange("port", parseInt(e.target.value))} placeholder={type === "postgres" ? "5432" : type === "mysql" ? "3306" : "5432"} />
handleConfigChange("database", e.target.value)} placeholder="database_name" />
handleConfigChange("user", e.target.value)} placeholder="username" />
handleConfigChange("password", e.target.value)} placeholder="••••••" />
{t('orUseConnectionString')}
handleConfigChange("connection_string", e.target.value)} placeholder={type === "postgres" ? "postgresql://user:pass@host:5432/db" : "mysql://user:pass@host:3306/db"} />
); case "clickhouse": return (
handleConfigChange("host", e.target.value)} placeholder="localhost" />
handleConfigChange("port", parseInt(e.target.value))} placeholder="9000" />
handleConfigChange("database", e.target.value)} placeholder="default" />
handleConfigChange("user", e.target.value)} placeholder="default" />
handleConfigChange("password", e.target.value)} placeholder="••••••" />
); case "sqlite": case "parquet": case "csv": return (
handleConfigChange("file_path", e.target.value)} placeholder="/path/to/file" />

{t('uploadFileOrEnterPath')}

); default: return (

{t('unsupportedDataSourceType')}

{t('dataSourceConnectorInDevelopment')}

); } }; return (
setName(e.target.value)} placeholder={t('myDataSource')} required />
{!initialData?.type && (
)}
{renderConfigFields()}
{testResult && (
{testResult.success ? : } {testResult.message}
)}
); }