diff --git a/frontend/src/components/DataSourceForm.tsx b/frontend/src/components/DataSourceForm.tsx index ea121a9..6f02bab 100644 --- a/frontend/src/components/DataSourceForm.tsx +++ b/frontend/src/components/DataSourceForm.tsx @@ -94,7 +94,12 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data const renderConfigFields = () => { switch (type) { case "postgres": + case "postgresql": case "supabase": + case "mysql": + case "sqlserver": + case "oracle": + case "redshift": return (
@@ -110,9 +115,9 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data handleConfigChange("port", parseInt(e.target.value))} - placeholder="5432" + placeholder={type === "postgres" ? "5432" : type === "mysql" ? "3306" : "5432"} />
@@ -121,7 +126,7 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data handleConfigChange("database", e.target.value)} - placeholder="postgres" + placeholder="database_name" />
@@ -129,7 +134,7 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data handleConfigChange("user", e.target.value)} - placeholder="postgres" + placeholder="username" />
@@ -149,7 +154,7 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data handleConfigChange("connection_string", e.target.value)} - placeholder="postgresql://user:pass@host:5432/db" + placeholder={type === "postgres" ? "postgresql://user:pass@host:5432/db" : "mysql://user:pass@host:3306/db"} />
@@ -204,59 +209,44 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data ); case "sqlite": + case "parquet": + case "csv": return (
- +
handleConfigChange("file_path", e.target.value)} - placeholder="/path/to/database.db" + placeholder="/path/to/file" /> -
-
-
- ); - case "parquet": - return ( -
-
- -
- handleConfigChange("file_path", e.target.value)} - placeholder="/path/to/data.parquet" - /> - -
+

上传文件或输入服务器路径

); default: - return null; + return ( +
+ +

暂不支持该数据源类型

+

+ 该数据源连接器正在开发中。请尝试使用 PostgreSQL, ClickHouse 或文件上传。 +

+
+ ); } }; @@ -272,20 +262,24 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data /> -
- - -
+ {!initialData?.type && ( +
+ + +
+ )}
{renderConfigFields()} diff --git a/frontend/src/pages/DataSources.tsx b/frontend/src/pages/DataSources.tsx index 6e9e13b..626b000 100644 --- a/frontend/src/pages/DataSources.tsx +++ b/frontend/src/pages/DataSources.tsx @@ -2,17 +2,39 @@ import { useState, useEffect } from "react"; import { api } from "@/lib/api"; import { DataSourceForm, type DataSourceConfig } from "@/components/DataSourceForm"; import { Button } from "@/components/ui/button"; -import { Plus, Database, Pencil, Trash2, Loader2, FolderOpen } from "lucide-react"; +import { Plus, Database, Pencil, Trash2, Loader2, FolderOpen, Info, ChevronLeft, FileText, Search } from "lucide-react"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { useAuthStore } from "@/store/authStore"; import { useProjectStore } from "@/store/projectStore"; import { useNavigate } from "react-router-dom"; +const SOURCE_TYPES = [ + { id: "csv", name: "CSV Upload", icon: }, + { id: "bigquery", name: "BigQuery", icon: }, + { id: "postgres", name: "PostgreSQL", icon: }, + { id: "mysql", name: "MySQL", icon: }, + { id: "oracle", name: "Oracle", icon: }, + { id: "sqlserver", name: "SQL Server", icon: }, + { id: "clickhouse", name: "ClickHouse", icon: }, + { id: "trino", name: "Trino", icon: }, + { id: "snowflake", name: "Snowflake", icon: }, + { id: "athena-trino", name: "Athena (Trino)", icon: }, + { id: "redshift", name: "Redshift", icon: }, + { id: "databricks", name: "Databricks", icon: }, + { id: "emr-spark", name: "EMR (Spark)", icon: }, + { id: "athena-spark", name: "Athena (Spark)", icon: }, + { id: "spark", name: "Spark", icon: }, + { id: "sqlite", name: "SQLite", icon: }, + { id: "parquet", name: "Parquet", icon: }, +]; + export function DataSources() { const [datasources, setDatasources] = useState([]); const [isLoading, setIsLoading] = useState(false); + const [view, setView] = useState<"list" | "select-type">("list"); const [isOpen, setIsOpen] = useState(false); const [editingDs, setEditingDs] = useState(null); + const [selectedType, setSelectedType] = useState(null); const { user } = useAuthStore(); const { currentProject } = useProjectStore(); const navigate = useNavigate(); @@ -34,15 +56,22 @@ export function DataSources() { } finally { setIsLoading(false); } - }; + } const handleCreate = () => { setEditingDs(null); + setSelectedType(null); + setView("select-type"); + }; + + const handleSelectType = (typeId: string) => { + setSelectedType(typeId); setIsOpen(true); }; const handleEdit = (ds: DataSourceConfig) => { setEditingDs(ds); + setSelectedType(ds.type); setIsOpen(true); }; @@ -82,6 +111,69 @@ export function DataSources() { } }; + if (view === "select-type") { + return ( +
+
+ + +

Connect an external data source

+ +
+ +

+ dbt integration is available for PostgreSQL, MySQL, BigQuery, Redshift, and Snowflake (For Essential Plan and above). Contact Us to suggest new data sources. +

+
+ +
+ {SOURCE_TYPES.map((type) => ( + + ))} +
+
+ + { + setIsOpen(open); + if (!open && !editingDs) setSelectedType(null); + }}> + + + + {editingDs ? "编辑数据源" : `新建 ${SOURCE_TYPES.find(t => t.id === selectedType)?.name || ""} 数据源`} + + +
+ setIsOpen(false)} + /> +
+
+
+
+ ); + } + return (
@@ -153,14 +245,19 @@ export function DataSources() { )}
- + { + setIsOpen(open); + if (!open && !editingDs) setSelectedType(null); + }}> - {editingDs ? "编辑数据源" : "新建数据源"} + + {editingDs ? `编辑 ${SOURCE_TYPES.find(t => t.id === editingDs.type)?.name || editingDs.type} 数据源` : `新建 ${SOURCE_TYPES.find(t => t.id === selectedType)?.name || ""} 数据源`} +
setIsOpen(false)}