diff --git a/src/App.vue b/src/App.vue index 0f869a181..67998e89a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -29,6 +29,7 @@ import { useDataGridActions } from "@/composables/useDataGridActions"; import { useTauriEvents } from "@/composables/useTauriEvents"; import { setLocale, currentLocale } from "@/i18n"; import * as api from "@/lib/api"; +import { resolveDefaultDatabase } from "@/lib/defaultDatabase"; import { resolveExecutableSql } from "@/lib/sqlExecutionTarget"; import { isTauriRuntime } from "@/lib/tauriRuntime"; import { isCloseTabShortcut, isExecuteSqlShortcut } from "@/lib/keyboardShortcuts"; @@ -204,24 +205,31 @@ async function openSqlFile() { } } -function newQuery() { +async function newQuery() { const connId = connectionStore.activeConnectionId || connectionStore.connections[0]?.id; if (!connId) return; const conn = connectionStore.getConfig(connId); if (!conn) return; connectionStore.activeConnectionId = connId; - queryStore.createTab(conn.id, conn.database || ""); + const tabId = queryStore.createTab(conn.id, resolveDefaultDatabase(conn, [])); + try { + await connectionStore.ensureConnected(connId); + const options = await getDatabaseOptions(connId); + queryStore.updateDatabase(tabId, resolveDefaultDatabase(conn, options)); + } catch (e: any) { + toast(t("connection.connectFailed", { message: e?.message || String(e) }), 5000); + } } async function openConnectionQuery(connectionId: string) { const connection = connectionStore.getConfig(connectionId); if (!connection) return; connectionStore.activeConnectionId = connectionId; - const tabId = queryStore.createTab(connectionId, connection.database || ""); + const tabId = queryStore.createTab(connectionId, resolveDefaultDatabase(connection, [])); try { await connectionStore.ensureConnected(connectionId); const options = await getDatabaseOptions(connectionId); - if (!connection.database && options[0]) queryStore.updateDatabase(tabId, options[0]); + queryStore.updateDatabase(tabId, resolveDefaultDatabase(connection, options)); } catch (e: any) { toast(t("connection.connectFailed", { message: e?.message || String(e) }), 5000); } @@ -253,12 +261,12 @@ async function changeActiveConnection(connectionId: string) { if (!tab) return; const connection = connectionStore.getConfig(connectionId); if (!connection) return; - queryStore.updateConnection(tab.id, connectionId, connection.database || ""); + queryStore.updateConnection(tab.id, connectionId, resolveDefaultDatabase(connection, [])); connectionStore.activeConnectionId = connectionId; try { await connectionStore.ensureConnected(connectionId); const options = await getDatabaseOptions(connectionId); - if (!connection.database && options[0]) queryStore.updateDatabase(tab.id, options[0]); + queryStore.updateDatabase(tab.id, resolveDefaultDatabase(connection, options)); } catch (e: any) { toast(t("connection.connectFailed", { message: e?.message || String(e) }), 5000); } @@ -269,6 +277,18 @@ function changeActiveDatabase(database: string) { if (tab) queryStore.updateDatabase(tab.id, database); } +async function setActiveDatabaseAsDefault() { + const tab = activeTab.value; + if (!tab || !tab.connectionId || !tab.database) return; + await connectionStore.setDefaultDatabase(tab.connectionId, tab.database); +} + +async function clearActiveDefaultDatabase() { + const tab = activeTab.value; + if (!tab || !tab.connectionId) return; + await connectionStore.clearDefaultDatabase(tab.connectionId); +} + function changeActiveSchema(schema: string | undefined) { const tab = activeTab.value; if (tab) queryStore.updateSchema(tab.id, schema); @@ -453,6 +473,8 @@ onUnmounted(() => { @change-connection="changeActiveConnection" @change-database="changeActiveDatabase" @change-schema="changeActiveSchema" + @set-default-database="setActiveDatabaseAsDefault" + @clear-default-database="clearActiveDefaultDatabase" /> (); const { t } = useI18n(); @@ -67,6 +71,8 @@ const activeSchemaOptions = computed(() => { return getSchemaOptionsForDb(connection.id, props.activeTab.database); }); +const isActiveDatabaseDefault = computed(() => isDefaultDatabase(props.activeConnection, activeDatabaseValue.value)); + function databaseDisplayName(database: string): string { const connection = props.activeConnection; if (connection?.db_type === "redis" && database !== "") return `db${database}`; @@ -210,6 +216,16 @@ function databaseDisplayName(database: string): string { +
diff --git a/src/components/sidebar/TreeItem.vue b/src/components/sidebar/TreeItem.vue index 850d1b029..b092b8d04 100644 --- a/src/components/sidebar/TreeItem.vue +++ b/src/components/sidebar/TreeItem.vue @@ -51,8 +51,10 @@ import { import { useConnectionStore } from "@/stores/connectionStore"; import { useQueryStore } from "@/stores/queryStore"; import { useToast } from "@/composables/useToast"; +import { useDatabaseOptions } from "@/composables/useDatabaseOptions"; import type { DatabaseType, QueryResult, TreeNode, TreeNodeType } from "@/types/database"; import * as api from "@/lib/api"; +import { resolveDefaultDatabase } from "@/lib/defaultDatabase"; import { DATABASE_EXPORT_PAGE_SIZE, DATABASE_EXPORT_ROW_LIMIT, @@ -80,12 +82,14 @@ import DatabaseIcon from "@/components/icons/DatabaseIcon.vue"; import ConnectionErrorIndicator from "@/components/connection/ConnectionErrorIndicator.vue"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; const { t } = useI18n(); const connectionStore = useConnectionStore(); const queryStore = useQueryStore(); const { toast } = useToast(); +const { getDatabaseOptions } = useDatabaseOptions(); const props = defineProps<{ node: TreeNode; @@ -295,12 +299,39 @@ async function newQuery() { try { await connectionStore.ensureConnected(node.connectionId); connectionStore.activeConnectionId = node.connectionId; - queryStore.createTab(node.connectionId, node.database || "", undefined, "query"); + if (node.database) { + queryStore.createTab(node.connectionId, node.database, undefined, "query"); + return; + } + const connection = connectionStore.getConfig(node.connectionId); + if (!connection) return; + const options = await getDatabaseOptions(node.connectionId); + queryStore.createTab(node.connectionId, resolveDefaultDatabase(connection, options), undefined, "query"); } catch (e: any) { toast(t("connection.connectFailed", { message: e?.message || String(e) }), 5000); } } +async function setNodeAsDefaultDatabase() { + const node = props.node; + if (!node.connectionId || !node.database) return; + try { + await connectionStore.setDefaultDatabase(node.connectionId, node.database); + } catch (e: any) { + toast(t("connection.saveFailed", { message: e?.message || String(e) }), 5000); + } +} + +async function clearNodeDefaultDatabase() { + const node = props.node; + if (!node.connectionId) return; + try { + await connectionStore.clearDefaultDatabase(node.connectionId); + } catch (e: any) { + toast(t("connection.saveFailed", { message: e?.message || String(e) }), 5000); + } +} + async function refresh() { const node = props.node; node.isExpanded = false; @@ -818,6 +849,13 @@ const canOpenFieldLineage = computed(() => { ); }); const isPinned = computed(() => props.node.pinned || connectionStore.isTreeNodePinned(props.node.id)); +const isNodeDefaultDatabase = computed( + () => + (props.node.type === "database" || props.node.type === "redis-db" || props.node.type === "mongo-db") && + !!props.node.connectionId && + !!props.node.database && + connectionStore.isDefaultDatabase(props.node.connectionId, props.node.database), +); const hasTypeMenu = computed(() => { const t = props.node.type; return ( @@ -1047,6 +1085,9 @@ const isDragging = computed(() => dragState.active && dragState.draggedId === pr @vue:mounted="($event: any) => $event.el.focus()" /> {{ isGroupLabel(node) ? t(node.label) : node.label }} + + {{ t("editor.defaultDatabase") }} + {{ columnComment }} @@ -1165,6 +1206,12 @@ const isDragging = computed(() => dragState.active && dragState.draggedId === pr {{ t("contextMenu.newQuery") }} + + {{ t("contextMenu.setDefaultDatabase") }} + + + {{ t("contextMenu.clearDefaultDatabase") }} + {{ t("contextMenu.createTable") }} @@ -1194,6 +1241,18 @@ const isDragging = computed(() => dragState.active && dragState.draggedId === pr + +