fix(objects): open database schema overview rows under clicked schema

This commit is contained in:
ordinary being
2026-10-12 14:39:38 +08:00
committed by GitHub
parent 6f6cf2f57c
commit a6b26ff1a6
4 changed files with 55 additions and 3 deletions
@@ -9,6 +9,7 @@ import ToolbarOverflowMenu from "@/components/ui/ToolbarOverflowMenu.vue";
import CustomContextMenu, { type ContextMenuItem } from "@/components/ui/CustomContextMenu.vue";
import { openSidebarDangerDialog } from "@/lib/sidebar/sidebarDangerDialog";
import { useDatabaseBrowserMutation } from "@/lib/database/databaseBrowserActions";
import { objectBrowserTargetForNamespaceRow } from "@/lib/database/objectBrowserTarget";
import SidebarTreeRuntimeHost from "@/components/sidebar/SidebarTreeRuntimeHost.vue";
import SidebarTreeItemDialogs from "@/components/sidebar/SidebarTreeItemDialogs.vue";
import { useToolbarOverflow } from "@/composables/useToolbarOverflow";
@@ -127,12 +128,14 @@ const visibleRows = computed(() => {
});
function openDatabase(database: string) {
const tabId = queryStore.openObjectBrowser(props.connection.id, database);
const target = objectBrowserTargetForNamespaceRow(props.connection, database);
const tabId = queryStore.openObjectBrowser(props.connection.id, target.database, target.schema);
void nextTick(() => requestObjectBrowserSearchFocus(tabId));
}
function databaseContextMenuItems(row: DatabaseRow): ContextMenuItem[] {
const node: TreeNode = { id: `${props.connection.id}:${row.name}`, label: row.name, type: "database", connectionId: props.connection.id, database: row.name };
const target = objectBrowserTargetForNamespaceRow(props.connection, row.name);
const node: TreeNode = { id: `${props.connection.id}:${row.name}`, label: row.name, type: "database", connectionId: props.connection.id, database: target.database, schema: target.schema };
const runtimeItems = sidebarRuntimeHost.value?.buildContextMenu(node);
if (runtimeItems?.length) return presentMenu(removeUnsupportedDatabaseItems(runtimeItems), "database");
const isDefault = props.connection.database === row.name;
@@ -0,0 +1,30 @@
import { describe, expect, it } from "vitest";
import { objectBrowserTargetForNamespaceRow } from "@/lib/database/objectBrowserTarget";
describe("objectBrowserTargetForNamespaceRow", () => {
it("binds connection-root schema engines as both database and schema", () => {
for (const dbType of ["oracle", "dameng", "oceanbase-oracle"] as const) {
expect(objectBrowserTargetForNamespaceRow({ db_type: dbType }, "schema_b")).toEqual({
database: "schema_b",
schema: "schema_b",
});
}
});
it("resolves inferred JDBC dialects before deciding", () => {
expect(objectBrowserTargetForNamespaceRow({ db_type: "jdbc", jdbc_driver_class: "oracle.jdbc.OracleDriver" }, "APP")).toEqual({
database: "APP",
schema: "APP",
});
});
it("keeps database rows as databases for engines with a database level", () => {
for (const dbType of ["mysql", "postgres", "sqlserver"] as const) {
expect(objectBrowserTargetForNamespaceRow({ db_type: dbType }, "shop")).toEqual({ database: "shop" });
}
});
it("treats a missing connection as a plain database row", () => {
expect(objectBrowserTargetForNamespaceRow(undefined, "shop")).toEqual({ database: "shop" });
});
});
+1 -1
View File
@@ -2,7 +2,7 @@ import type { ConnectionConfig, DatabaseType } from "@/types/database";
import { isSchemaAware, spannerObjectTreeSchema, usesDatabaseObjectTreeMode, usesTreeSchemaMode } from "@/lib/database/databaseFeatureSupport";
import type { CodeMirrorSqlDialectName } from "@/lib/editor/codemirrorSqlDialect";
type JdbcDialectConnection = Partial<Pick<ConnectionConfig, "db_type" | "driver_profile" | "driver_label" | "connection_string" | "url_params" | "jdbc_driver_class" | "jdbc_driver_paths" | "database_info" | "external_config" | "username">>;
export type JdbcDialectConnection = Partial<Pick<ConnectionConfig, "db_type" | "driver_profile" | "driver_label" | "connection_string" | "url_params" | "jdbc_driver_class" | "jdbc_driver_paths" | "database_info" | "external_config" | "username">>;
export type GaussdbIdentifierQuoteStyle = "auto" | "double" | "backtick";
export type GaussdbConnectionMode = "native" | "m-jdbc";
@@ -0,0 +1,19 @@
import { connectionUsesConnectionRootSchemaMode, type JdbcDialectConnection } from "@/lib/database/jdbcDialect";
/**
* Object-browser target for a row of the database/schema overview list.
*
* Engines that expose schemas directly below the connection (Oracle, Dameng,
* OceanBase Oracle, and JDBC profiles inferred to them) list schemas in that
* overview, so the clicked row must bind as both the database and the schema —
* the same convention the sidebar uses when it locates a query context (see
* ConnectionTree). Binding the row as a plain database instead opens the tab
* under the connection default or the first schema, while the tab title keeps
* showing the clicked name (#11795).
*
* Engines with a real database level (MySQL, PostgreSQL, ...) keep the row name
* as the database and leave the schema to the browser's default selection.
*/
export function objectBrowserTargetForNamespaceRow(connection: JdbcDialectConnection | undefined, rowName: string): { database: string; schema?: string } {
return connectionUsesConnectionRootSchemaMode(connection) ? { database: rowName, schema: rowName } : { database: rowName };
}