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 (
@@ -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 (
{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 (
+
+
+
setView("list")}
+ className="flex items-center text-zinc-500 hover:text-zinc-800 transition-colors mb-6 group"
+ >
+
+ 返回列表
+
+
+
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) => (
+
handleSelectType(type.id)}
+ className="flex items-center gap-4 bg-white p-4 rounded-lg border border-zinc-200 hover:border-blue-500 hover:shadow-sm transition-all text-left group"
+ >
+
+ {type.icon}
+
+
+ {type.name}
+
+
+ ))}
+
+
+
+
{
+ 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)}