diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue index 51138634a..0c4f26ea7 100644 --- a/apps/desktop/src/components/connection/ConnectionDialog.vue +++ b/apps/desktop/src/components/connection/ConnectionDialog.vue @@ -19,7 +19,18 @@ import { applyParsedConnectionUrl, parseConnectionUrl } from "@/lib/connectionUr import { connectionUrlPlaceholder as getUrlPlaceholder } from "@/lib/connectionPresentation"; import { mongodbAuthFailureHint, mongoUrlParam, setMongoUrlParam } from "@/lib/mongoConnectionOptions"; import { showAgentDriverInstallHint, type AgentDriverInstallState } from "@/lib/agentDriverInstallHint"; -import { ArrowLeft, ChevronRight, Copy, ExternalLink, FolderOpen, Grid3X3, Link2, List, Search } from "lucide-vue-next"; +import { + ArrowLeft, + ChevronRight, + Copy, + ExternalLink, + FilePlus2, + FolderOpen, + Grid3X3, + Link2, + List, + Search, +} from "lucide-vue-next"; type DbOption = { value: string; label: string }; type DbCategory = { key: string; title: string; options: DbOption[] }; @@ -770,6 +781,24 @@ async function browseDbFilePath() { } } +function ensureDuckDbFileExtension(path: string): string { + return /\.(duckdb|db)$/i.test(path) ? path : `${path}.duckdb`; +} + +async function createDuckDbFilePath() { + if (!isTauriRuntime()) return; + const { save } = await import("@tauri-apps/plugin-dialog"); + const selected = await save({ + title: t("connection.createDuckDbFile"), + defaultPath: "database.duckdb", + filters: [{ name: "DuckDB", extensions: ["duckdb", "db"] }], + }); + if (!selected) return; + + const path = ensureDuckDbFileExtension(selected); + form.value.host = path; +} + async function browseJdbcDriverPaths() { if (!isTauriRuntime()) return; const { open } = await import("@tauri-apps/plugin-dialog"); @@ -1138,6 +1167,19 @@ function openExternalUrl(url: string) { {{ t("connection.sshKeyPathBrowse") }} + + + + + {{ t("connection.createDuckDbFile") }} +

{{ t("connection.memoryDatabasePathHint") }} diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts index 0684185d6..beb14adb5 100644 --- a/apps/desktop/src/i18n/locales/en.ts +++ b/apps/desktop/src/i18n/locales/en.ts @@ -97,6 +97,7 @@ export default { type: "Type", host: "Host", filePath: "File Path", + createDuckDbFile: "Create DuckDB file", memoryDatabasePathHint: "Use :memory: to create an in-memory SQLite or DuckDB database.", user: "User", password: "Password", diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts index 3f2f9f3ce..bc21f90fc 100644 --- a/apps/desktop/src/i18n/locales/es.ts +++ b/apps/desktop/src/i18n/locales/es.ts @@ -97,6 +97,7 @@ export default { type: "Tipo", host: "Host", filePath: "Ruta del archivo", + createDuckDbFile: "Crear archivo DuckDB", user: "Usuario", password: "Contraseña", database: "Base de datos", diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts index 0b09a0586..2cb5f979d 100644 --- a/apps/desktop/src/i18n/locales/zh-CN.ts +++ b/apps/desktop/src/i18n/locales/zh-CN.ts @@ -96,6 +96,7 @@ export default { type: "类型", host: "主机", filePath: "文件路径", + createDuckDbFile: "新建 DuckDB 文件", memoryDatabasePathHint: "输入 :memory: 可创建 SQLite 或 DuckDB 内存数据库。", user: "用户名", password: "密码", diff --git a/packages/app-tests/connectionDialogEditOpen.test.ts b/packages/app-tests/connectionDialogEditOpen.test.ts index 3da2909bf..b5611543b 100644 --- a/packages/app-tests/connectionDialogEditOpen.test.ts +++ b/packages/app-tests/connectionDialogEditOpen.test.ts @@ -28,3 +28,11 @@ test("connection dialog initializes edit form on first mount", () => { test("connection dialog maps legacy Dameng configs to the DM profile", () => { assert.match(connectionDialogSource, /if \(config\.db_type === "dameng"\) return "dm";/); }); + +test("connection dialog offers DuckDB file creation from the new connection form", () => { + assert.match(connectionDialogSource, /async function createDuckDbFilePath\(\)/); + assert.match(connectionDialogSource, /const \{ save \} = await import\("@tauri-apps\/plugin-dialog"\);/); + assert.match(connectionDialogSource, /form\.value\.host = path;/); + assert.match(connectionDialogSource, /form\.db_type === 'duckdb'/); + assert.match(connectionDialogSource, /@click="createDuckDbFilePath"/); +});